Switch OC Suite | Overclocking suite for Horizon OS (HOS) running on Atmosphere CFW. Licensed under GPL v2.
Switch OC Suite
Overclocking suite for Horizon OS (HOS) running on Atmosphere CFW. Licensed under GPL v2.
README
🚨DISCLAIMER: THIS IS PROVIDED AS IS. USE AT YOUR OWN RISK!🚨
Overclocking in general will shorten the lifespan of some
-hardware components. YOU ARE RESPONSIBLE for any problem or
-potential damage if unsafe frequencies are ENABLED in
-sys-clk-OC. Issues like asking for bypassing limit will BE IGNORED OR
-CLOSED WITHOUT REPLY.
Due to HorizonOS design, instabilities from unsafe RAM clocks may
-cause filesystem corruption. Always make backup before enabling
-DRAM OC.
Add kip1=atmosphere/kips/loader.kip to boot entry
-section in bootloader/hekate_ipl.ini.
How to build this project
Grab necessary patches from the repo, then compile sys-clk, ReverseNX-RT and Atmosphere loader with
-devkitpro.
Before compiling Atmosphere loader, run patch.py in
-Atmosphere/stratosphere/loader/source/ to insert oc module into loader sysmodule.
When compilation is done, uncompress the kip to make it work with configurator:
-hactool -t kip1 Atmosphere/stratosphere/loader/out/nintendo_nx_arm64_armv8a/release/loader.kip --uncompress=./loader.kip
See the end of README in sys-clk-OC. Place this line allow_unsafe_freq=1 under
-[value] section in
-/config/sys-clk/config.ini
I would like to bypass limit enforced in sys-clk to improve handheld performance without charger
-connected.
Never will it be implemented here, or work out of the box.
You have to modify the code yourself for your own use. If you are to share modified binaries you have
-made based on this project publicly, make sure to comply with GPL v2 licenses.
Download
Get latest version of Switch OC Suite and its corresponding Atmosphere package here.
Configure frequencies and voltages to suit your hardware and preferences.
\ No newline at end of file
+Switch OC Suite | Overclocking suite for Horizon OS (HOS) running on Atmosphere CFW. Licensed under GPL v2.
Switch OC Suite
Overclocking suite for Horizon OS (HOS) running on Atmosphere CFW. Licensed under GPL v2.
README
🚨DISCLAIMER: THIS IS PROVIDED AS IS. USE AT YOUR OWN RISK!🚨
Overclocking in general will shorten the lifespan of some hardware components. YOU ARE RESPONSIBLE for any problem or potential damage if unsafe frequencies are ENABLED in sys-clk-OC. Issues like asking for bypassing limit will BE IGNORED OR CLOSED WITHOUT REPLY.
Due to HorizonOS design, instabilities from unsafe RAM clocks may cause filesystem corruption. Always make backup before enabling DRAM OC.
Add kip1=atmosphere/kips/loader.kip to boot entry section in bootloader/hekate_ipl.ini.
How to build this project
Grab necessary patches from the repo, then compile sys-clk, ReverseNX-RT and Atmosphere loader with devkitpro.
Before compiling Atmosphere loader, run patch.py in Atmosphere/stratosphere/loader/source/ to insert oc module into loader sysmodule.
When compilation is done, uncompress the kip to make it work with configurator: hactool -t kip1 Atmosphere/stratosphere/loader/out/nintendo_nx_arm64_armv8a/release/loader.kip --uncompress=./loader.kip
See the end of README in sys-clk-OC. Place this line allow_unsafe_freq=1 under [value] section in /config/sys-clk/config.ini
I would like to bypass limit enforced in sys-clk to improve handheld performance without charger connected.
Never will it be implemented here, or work out of the box.
You have to modify the code yourself for your own use. If you are to share modified binaries you have made based on this project publicly, make sure to comply with GPL v2 licenses.
Download
Get latest version of Switch OC Suite and its corresponding Atmosphere package here.
",d.setAttribute("for",this.id),b.appendChild(d),document.getElementById("config-list-basic").appendChild(b),new ErrorToolTip(this.id).addChangeListener()}a.value=String(this.value)}setElementValue(){this.getInputElement().value=String(this.value)}setElementDefaultValue(){this.getInputElement().value=String(this.defval)}removeElement(){let a=this.getInputElement();a&&a.parentElement.parentElement.remove()}showElement(){let a=this.getInputElement();a&&a.parentElement.parentElement.style.removeProperty("display")}hideElement(){let a=this.getInputElement();a&&a.parentElement.parentElement.style.setProperty("display","none")}}CustTable=[new CustEntry("mtcConf","DRAM Timing",CustPlatform.Mariko,2,["0: AUTO_ADJ_MARIKO_SAFE: Auto adjust timings for LPDDR4 ≤3733 Mbps specs, 8Gb density. (Default)","1: AUTO_ADJ_MARIKO_4266: Auto adjust timings for LPDDR4X 4266 Mbps specs, 8Gb density.","2: NO_ADJ_ALL: No timing adjustment for both Erista and Mariko. Might achieve better performance on Mariko but lower maximum frequency is expected."],0,[0,2],1),new CustEntry("commonCpuBoostClock","Boost Clock in kHz",CustPlatform.All,4,["System default: 1785000","Boost clock will be applied when applications request higher CPU frequency for quicker loading.","This will be set regardless of whether sys-clk is enabled."],1785e3,[102e4,3e6],1,!1),new CustEntry("commonEmcMemVolt","EMC Vddq (Erista Only) & RAM Vdd2 Voltage in uV",CustPlatform.All,4,["Acceptable range: 1100000 ≤ x ≤ 1250000, and it should be divided evenly by 12500.","Erista Default (HOS): 1125000 (bootloader: 1100000)","Mariko Default: 1100000 (It will not work without sys-clk-OC)","Not enabled by default"],0,[11e5,125e4],12500),new CustEntry("eristaCpuMaxVolt","Erista CPU Max Voltage in mV",CustPlatform.Erista,4,["Acceptable range: 1100 ≤ x ≤ 1300","L4T Default: 1235"],1235,[1100,1300],1),new CustEntry("eristaEmcMaxClock","Erista RAM Max Clock in kHz",CustPlatform.Erista,4,["Values should be ≥ 1600000, and divided evenly by 3200.","WARNING: RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM"],1862400,[16e5,24e5],3200),new CustEntry("marikoCpuMaxVolt","Mariko CPU Max Voltage in mV",CustPlatform.Mariko,4,["System default: 1120","Acceptable range: 1100 ≤ x ≤ 1300"],1235,[1100,1300],5),new CustEntry("marikoEmcMaxClock","Mariko RAM Max Clock in kHz",CustPlatform.Mariko,4,["Values should be ≥ 1600000, and divided evenly by 3200.","WARNING: RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM."],1996800,[16e5,24e5],3200),new CustEntry("marikoEmcVddqVolt","EMC Vddq (Mariko Only) Voltage in uV",CustPlatform.Mariko,4,["Acceptable range: 550000 ≤ x ≤ 650000","Value should be divided evenly by 5000","Default: 600000","Not enabled by default.","This will not work without sys-clk-OC."],0,[55e4,65e4],5e3)];class ErrorToolTip{constructor(a,b){this.id=a,this.msg=b,this.id=a,this.element=document.getElementById(a),b&&this.setMsg(b)}setMsg(a){return this.msg=a,this}show(){var a,b,c,d,e,f;return(a=this.element)===null||a===void 0?void 0:a.setAttribute("aria-invalid","true"),this.msg&&((b=this.element)===null||b===void 0?void 0:b.setAttribute("title",this.msg),(d=(c=this.element)===null||c===void 0?void 0:c.parentElement)===null||d===void 0?void 0:d.setAttribute("data-tooltip",this.msg),(f=(e=this.element)===null||e===void 0?void 0:e.parentElement)===null||f===void 0?void 0:f.setAttribute("data-placement","top")),this}clear(){var a,b,c,d,e,f;return(a=this.element)===null||a===void 0?void 0:a.removeAttribute("aria-invalid"),(b=this.element)===null||b===void 0?void 0:b.removeAttribute("title"),(d=(c=this.element)===null||c===void 0?void 0:c.parentElement)===null||d===void 0?void 0:d.removeAttribute("data-tooltip"),(f=(e=this.element)===null||e===void 0?void 0:e.parentElement)===null||f===void 0?void 0:f.removeAttribute("data-placement"),this}addChangeListener(){var a;(a=this.element)===null||a===void 0?void 0:a.addEventListener('change',b=>{let a=CustTable.filter(a=>a.id===this.id)[0];a.value=Number(this.element.value),a.validate()})}}class CustStorage{constructor(){this.storage={},this.key="last_saved"}updateFromTable(){CustTable.forEach(a=>{var b;if(a.updateValueFromElement(),!a.validate())throw(b=a.getInputElement())===null||b===void 0?void 0:b.focus(),new Error(`Invalid ${a.name}`)}),this.storage={};let a=Object.fromEntries(CustTable.map(a=>[a.id,a.value]));Object.keys(a).forEach(b=>this.storage[b]=a[b])}setTable(){let a=Object.keys(this.storage);a.forEach(a=>CustTable.filter(b=>b.id==a)[0].value=this.storage[a]),CustTable.filter(b=>!a.includes(b.id)).forEach(a=>a.value=a.defval),CustTable.forEach(a=>{var b;if(!a.validate())throw(b=a.getInputElement())===null||b===void 0?void 0:b.focus(),new Error(`Invalid ${a.name}`);a.setElementValue()})}save(){localStorage.setItem(this.key,JSON.stringify(this.storage))}load(){let b=localStorage.getItem(this.key);if(!b)return null;let a=JSON.parse(b),c=CustTable.map(a=>a.id),d=Object.keys(a).filter(a=>!c.includes(a));return d.length&&console.log(`Ignored: ${d}`),Object.keys(a).filter(a=>c.includes(a)).forEach(b=>this.storage[b]=a[b]),this.storage}}class Cust{constructor(){this.storage=new CustStorage,this.magic=1414747459,this.magicLen=4,this.mapper={2:{get:a=>this.view.getUint16(a,!0),set:(a,b)=>this.view.setUint16(a,b,!0)},4:{get:a=>this.view.getUint32(a,!0),set:(a,b)=>this.view.setUint32(a,b,!0)}}}findMagicOffset(){this.view=new DataView(this.buffer);for(let a=0;a{var b,c;if(!a.offset)throw(b=a.getInputElement())===null||b===void 0?void 0:b.focus(),new Error(`Failed to get offset for ${a.name}`);let d=this.mapper[a.size];if(!d)throw(c=a.getInputElement())===null||c===void 0?void 0:c.focus(),new Error(`Unknown size at ${a.name}`);d.set(a.offset,a.value)}),this.storage.save();let a=document.createElement("a");a.href=window.URL.createObjectURL(new Blob([this.buffer],{type:"application/octet-stream"})),a.download="loader.kip",a.click(),this.toggleLoadLastSavedBtn(!0)}removeHTMLForm(){CustTable.forEach(a=>a.removeElement())}toggleLoadLastSavedBtn(b){let a=document.getElementById("load_saved");b?(a.addEventListener('click',()=>{this.storage.load()&&this.storage.setTable()}),a.style.removeProperty("display"),a.removeAttribute("disabled")):a.style.setProperty("display","none")}createHTMLForm(){var a;CustTable.forEach(a=>a.createElement());let b=document.createElement("p");b.innerHTML="Advanced configuration: Coming soon...",(a=document.getElementById("config-list-advanced"))===null||a===void 0?void 0:a.appendChild(b);let c=document.getElementById("load_default");c.removeAttribute("disabled"),c.addEventListener('click',()=>{CustTable.forEach(a=>a.setElementDefaultValue())}),this.toggleLoadLastSavedBtn(this.storage.load()!==null);let d=document.getElementById("save");d.removeAttribute("disabled"),d.addEventListener('click',()=>{try{this.save()}catch(a){console.error(a),alert(a)}})}initCustTabs(){const a=Array.from(document.querySelectorAll(`nav[role="tablist"] > button`));a.forEach(b=>{b.removeAttribute("disabled");let c=Number(b.getAttribute("data-platform"));b.addEventListener('click',f=>{const d=["outline"];b.classList.remove(...d);let e=a.filter(a=>a!=b);e.forEach(a=>a.classList.add(...d)),CustTable.forEach(a=>{a.isAvailableFor(c)?a.showElement():a.hideElement()})})})}parse(){let a=this.beginOffset+this.magicLen,b=2,c=this.mapper[b].get(a);if(c!=CUST_REV)throw new Error(`Unsupported custRev, expected: ${CUST_REV}, got ${c}`);a+=b,document.getElementById("cust_rev").innerHTML=`Cust v${CUST_REV} is loaded.`,CustTable.forEach(b=>{var c;b.offset=a;let d=this.mapper[b.size];if(!d)throw(c=b.getInputElement())===null||c===void 0?void 0:c.focus(),new Error(`Unknown size at ${b}`);b.value=d.get(a),a+=b.size,b.validate()})}load(a){try{this.buffer=a,this.findMagicOffset(),this.removeHTMLForm(),this.parse(),this.initCustTabs(),this.createHTMLForm()}catch(a){console.error(a),alert(a)}}}class ReleaseAsset{constructor(a){this.downloadUrl=a.browser_download_url,this.updatedAt=a.updated_at}}class ReleaseInfo{constructor(){this.ocLatestApi="https://api.github.com/repos/hanai3Bi/Switch-OC-Suite/releases/latest"}load(){return __awaiter(this,void 0,void 0,function*(){try{this.parseOcResponse(yield this.responseFromApi(this.ocLatestApi).catch())}catch(a){console.error(a),alert(a)}})}responseFromApi(a){return __awaiter(this,void 0,void 0,function*(){const b=yield fetch(a,{method:'GET',headers:{Accept:'application/json'}});if(b.ok)return yield b.json();throw new Error(`Failed to connect to "${a}": ${b.status}`)})}parseOcResponse(a){this.ocVer=a.tag_name,this.amsVer=this.ocVer.split(".").slice(0,3).join("."),this.loaderKipAsset=new ReleaseAsset(a.assets.filter(a=>a.name.endsWith("loader.kip"))[0]),this.sdOutZipAsset=new ReleaseAsset(a.assets.filter(a=>a.name.endsWith(".zip"))[0]),this.amsUrl=`https://github.com/Atmosphere-NX/Atmosphere/releases/tags/${this.amsVer}`}}class DownloadSection{constructor(){this.element=document.getElementById("download_btn_grid")}load(){return __awaiter(this,void 0,void 0,function*(){while(!this.isVisible())yield new Promise(a=>setTimeout(a,1e3));const a=new ReleaseInfo;yield a.load(),this.update("loader_kip_btn",`loader.kip ${a.ocVer} ${a.loaderKipAsset.updatedAt}`,a.loaderKipAsset.downloadUrl),this.update("sdout_zip_btn",`SdOut.zip ${a.ocVer} ${a.sdOutZipAsset.updatedAt}`,a.sdOutZipAsset.downloadUrl),this.update("ams_btn",`Atmosphere-NX ${a.amsVer}`,a.amsUrl)})}isVisible(){let a=this.element.getBoundingClientRect();return a.top>0&&a.left>0&&a.bottom-a.height<(window.innerHeight||document.documentElement.clientHeight)&&a.right-a.width<(window.innerWidth||document.documentElement.clientWidth)}update(b,c,d){let a=document.getElementById(b);a.innerHTML=c,a.removeAttribute("aria-busy"),a.setAttribute("href",d)}}const fileInput=document.getElementById("file");fileInput.addEventListener('change',a=>{var c=new Cust;if(!a.target||!a.target.files)return;let b=new FileReader;b.readAsArrayBuffer(a.target.files[0]),b.onloadend=a=>{a.target.readyState==FileReader.DONE&&c.load(a.target.result)}}),addEventListener('DOMContentLoaded',a=>__awaiter(this,void 0,void 0,function*(){yield(new DownloadSection).load()}))
\ No newline at end of file
+var __awaiter=this&&this.__awaiter||function(e,t,i,s){return new(i||(i=Promise))((function(a,l){function n(e){try{o(s.next(e))}catch(e){l(e)}}function r(e){try{o(s.throw(e))}catch(e){l(e)}}function o(e){var t;e.done?a(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(n,r)}o((s=s.apply(e,t||[])).next())}))};const CUST_REV=4;var CustPlatform;!function(e){e[e.Undefined=0]="Undefined",e[e.Erista=1]="Erista",e[e.Mariko=2]="Mariko",e[e.All=3]="All"}(CustPlatform||(CustPlatform={}));class CustEntry{constructor(e,t,i,s,a,l,n=[0,1e6],r=1,o=!0){this.id=e,this.name=t,this.platform=i,this.size=s,this.desc=a,this.defval=l,this.step=r,this.zeroable=o,this.min=n[0],this.max=n[1]}validate(){let e=new ErrorToolTip(this.id).clear();return Number.isNaN(this.value)||void 0===this.value?(e.setMsg("Invalid value: Not a number").show(),!1):!(!this.zeroable||0!=this.value)||(this.valuethis.max?(e.setMsg(`Expected range: [${this.min}, ${this.max}], got ${this.value}.`).show(),!1):this.value%this.step==0||(e.setMsg(`${this.value} % ${this.step} ≠0`).show(),!1))}getInputElement(){return document.getElementById(this.id)}updateValueFromElement(){var e;this.value=Number(null===(e=this.getInputElement())||void 0===e?void 0:e.value)}isAvailableFor(e){return e===CustPlatform.Undefined||this.platform===e||this.platform===CustPlatform.All}createElement(){let e=this.getInputElement();if(!e){let t=document.createElement("div");t.classList.add("grid","cust-element"),e=document.createElement("input"),e.min=String(this.zeroable?0:this.min),e.max=String(this.max),e.id=this.id,e.type="number",e.step=String(this.step);let i=document.createElement("label");i.setAttribute("for",this.id),i.innerHTML=this.name,i.appendChild(e),t.appendChild(i);let s=document.createElement("blockquote");s.innerHTML="
"+this.desc.map((e=>`
${e}
`)).join("")+"
",s.setAttribute("for",this.id),t.appendChild(s),document.getElementById("config-list-basic").appendChild(t),new ErrorToolTip(this.id).addChangeListener()}e.value=String(this.value)}setElementValue(){this.getInputElement().value=String(this.value)}setElementDefaultValue(){this.getInputElement().value=String(this.defval)}removeElement(){let e=this.getInputElement();e&&e.parentElement.parentElement.remove()}showElement(){let e=this.getInputElement();e&&e.parentElement.parentElement.style.removeProperty("display")}hideElement(){let e=this.getInputElement();e&&e.parentElement.parentElement.style.setProperty("display","none")}}var CustTable=[new CustEntry("mtcConf","DRAM Timing",CustPlatform.Mariko,4,["0: AUTO_ADJ_MARIKO_SAFE: Auto adjust timings for LPDDR4 ≤3733 Mbps specs, 8Gb density. (Default)","1: AUTO_ADJ_MARIKO_4266: Auto adjust timings for LPDDR4X 4266 Mbps specs, 8Gb density.","2: NO_ADJ_ALL: No timing adjustment for both Erista and Mariko. Might achieve better performance on Mariko but lower maximum frequency is expected."],0,[0,2],1),new CustEntry("commonCpuBoostClock","Boost Clock in kHz",CustPlatform.All,4,["System default: 1785000","Boost clock will be applied when applications request higher CPU frequency for quicker loading.","This will be set regardless of whether sys-clk is enabled."],1785e3,[102e4,3e6],1,!1),new CustEntry("commonEmcMemVolt","EMC Vddq (Erista Only) & RAM Vdd2 Voltage in uV",CustPlatform.All,4,["Acceptable range: 1100000 ≤ x ≤ 1250000, and it should be divided evenly by 12500.","Erista Default (HOS): 1125000 (bootloader: 1100000)","Mariko Default: 1100000 (It will not work without sys-clk-OC)","Not enabled by default"],0,[11e5,125e4],12500),new CustEntry("eristaCpuMaxVolt","Erista CPU Max Voltage in mV",CustPlatform.Erista,4,["Acceptable range: 1100 ≤ x ≤ 1300","L4T Default: 1235"],1235,[1100,1300],1),new CustEntry("eristaEmcMaxClock","Erista RAM Max Clock in kHz",CustPlatform.Erista,4,["Values should be ≥ 1600000, and divided evenly by 3200.","WARNING: RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM"],1862400,[16e5,24e5],3200),new CustEntry("marikoCpuMaxVolt","Mariko CPU Max Voltage in mV",CustPlatform.Mariko,4,["System default: 1120","Acceptable range: 1100 ≤ x ≤ 1300"],1235,[1100,1300],5),new CustEntry("marikoEmcMaxClock","Mariko RAM Max Clock in kHz",CustPlatform.Mariko,4,["Values should be ≥ 1600000, and divided evenly by 3200.","WARNING: RAM overclock could be UNSTABLE if timing parameters are not suitable for your DRAM."],1996800,[16e5,24e5],3200),new CustEntry("marikoEmcVddqVolt","EMC Vddq (Mariko Only) Voltage in uV",CustPlatform.Mariko,4,["Acceptable range: 550000 ≤ x ≤ 650000","Value should be divided evenly by 5000","Default: 600000","Not enabled by default.","This will not work without sys-clk-OC."],0,[55e4,65e4],5e3)];class ErrorToolTip{constructor(e,t){this.id=e,this.msg=t,this.id=e,this.element=document.getElementById(e),t&&this.setMsg(t)}setMsg(e){return this.msg=e,this}show(){var e,t,i,s,a,l;return null===(e=this.element)||void 0===e||e.setAttribute("aria-invalid","true"),this.msg&&(null===(t=this.element)||void 0===t||t.setAttribute("title",this.msg),null===(s=null===(i=this.element)||void 0===i?void 0:i.parentElement)||void 0===s||s.setAttribute("data-tooltip",this.msg),null===(l=null===(a=this.element)||void 0===a?void 0:a.parentElement)||void 0===l||l.setAttribute("data-placement","top")),this}clear(){var e,t,i,s,a,l;return null===(e=this.element)||void 0===e||e.removeAttribute("aria-invalid"),null===(t=this.element)||void 0===t||t.removeAttribute("title"),null===(s=null===(i=this.element)||void 0===i?void 0:i.parentElement)||void 0===s||s.removeAttribute("data-tooltip"),null===(l=null===(a=this.element)||void 0===a?void 0:a.parentElement)||void 0===l||l.removeAttribute("data-placement"),this}addChangeListener(){var e;null===(e=this.element)||void 0===e||e.addEventListener("change",(e=>{let t=CustTable.filter((e=>e.id===this.id))[0];t.value=Number(this.element.value),t.validate()}))}}class CustStorage{constructor(){this.storage={},this.key="last_saved"}updateFromTable(){CustTable.forEach((e=>{var t;if(e.updateValueFromElement(),!e.validate())throw null===(t=e.getInputElement())||void 0===t||t.focus(),new Error(`Invalid ${e.name}`)})),this.storage={};let e=Object.fromEntries(CustTable.map((e=>[e.id,e.value])));Object.keys(e).forEach((t=>this.storage[t]=e[t]))}setTable(){let e=Object.keys(this.storage);e.forEach((e=>CustTable.filter((t=>t.id==e))[0].value=this.storage[e])),CustTable.filter((t=>!e.includes(t.id))).forEach((e=>e.value=e.defval)),CustTable.forEach((e=>{var t;if(!e.validate())throw null===(t=e.getInputElement())||void 0===t||t.focus(),new Error(`Invalid ${e.name}`);e.setElementValue()}))}save(){localStorage.setItem(this.key,JSON.stringify(this.storage))}load(){let e=localStorage.getItem(this.key);if(!e)return null;let t=JSON.parse(e),i=CustTable.map((e=>e.id)),s=Object.keys(t).filter((e=>!i.includes(e)));return s.length&&console.log(`Ignored: ${s}`),Object.keys(t).filter((e=>i.includes(e))).forEach((e=>this.storage[e]=t[e])),this.storage}}class Cust{constructor(){this.storage=new CustStorage,this.magic=1414747459,this.magicLen=4,this.mapper={2:{get:e=>this.view.getUint16(e,!0),set:(e,t)=>this.view.setUint16(e,t,!0)},4:{get:e=>this.view.getUint32(e,!0),set:(e,t)=>this.view.setUint32(e,t,!0)}}}findMagicOffset(){this.view=new DataView(this.buffer);for(let e=0;e{var t,i;if(!e.offset)throw null===(t=e.getInputElement())||void 0===t||t.focus(),new Error(`Failed to get offset for ${e.name}`);let s=this.mapper[e.size];if(!s)throw null===(i=e.getInputElement())||void 0===i||i.focus(),new Error(`Unknown size at ${e.name}`);s.set(e.offset,e.value)})),this.storage.save();let e=document.createElement("a");e.href=window.URL.createObjectURL(new Blob([this.buffer],{type:"application/octet-stream"})),e.download="loader.kip",e.click(),this.toggleLoadLastSavedBtn(!0)}removeHTMLForm(){CustTable.forEach((e=>e.removeElement()))}toggleLoadLastSavedBtn(e){let t=document.getElementById("load_saved");e?(t.addEventListener("click",(()=>{this.storage.load()&&this.storage.setTable()})),t.style.removeProperty("display"),t.removeAttribute("disabled")):t.style.setProperty("display","none")}createHTMLForm(){var e;CustTable.forEach((e=>e.createElement()));let t=document.createElement("p");t.innerHTML="Advanced configuration: Coming soon...",null===(e=document.getElementById("config-list-advanced"))||void 0===e||e.appendChild(t);let i=document.getElementById("load_default");i.removeAttribute("disabled"),i.addEventListener("click",(()=>{CustTable.forEach((e=>e.setElementDefaultValue()))})),this.toggleLoadLastSavedBtn(null!==this.storage.load());let s=document.getElementById("save");s.removeAttribute("disabled"),s.addEventListener("click",(()=>{try{this.save()}catch(e){console.error(e),alert(e)}}))}initCustTabs(){const e=Array.from(document.querySelectorAll('nav[role="tablist"] > button'));e.forEach((t=>{t.removeAttribute("disabled");let i=Number(t.getAttribute("data-platform"));t.addEventListener("click",(s=>{const a=["outline"];t.classList.remove(...a),e.filter((e=>e!=t)).forEach((e=>e.classList.add(...a))),CustTable.forEach((e=>{e.isAvailableFor(i)?e.showElement():e.hideElement()}))}))}))}parse(){let e=this.beginOffset+this.magicLen,t=this.mapper[4].get(e);if(4!=t)throw new Error(`Unsupported custRev, expected: 4, got ${t}`);e+=4,document.getElementById("cust_rev").innerHTML="Cust v4 is loaded.",CustTable.forEach((t=>{var i;t.offset=e;let s=this.mapper[t.size];if(!s)throw null===(i=t.getInputElement())||void 0===i||i.focus(),new Error(`Unknown size at ${t}`);t.value=s.get(e),e+=t.size,t.validate()}))}load(e){try{this.buffer=e,this.findMagicOffset(),this.removeHTMLForm(),this.parse(),this.initCustTabs(),this.createHTMLForm()}catch(e){console.error(e),alert(e)}}}class ReleaseAsset{constructor(e){this.downloadUrl=e.browser_download_url,this.updatedAt=e.updated_at}}class ReleaseInfo{constructor(){this.ocLatestApi="https://api.github.com/repos/hanai3Bi/Switch-OC-Suite/releases/latest"}load(){return __awaiter(this,void 0,void 0,(function*(){try{this.parseOcResponse(yield this.responseFromApi(this.ocLatestApi).catch())}catch(e){console.error(e),alert(e)}}))}responseFromApi(e){return __awaiter(this,void 0,void 0,(function*(){const t=yield fetch(e,{method:"GET",headers:{Accept:"application/json"}});if(t.ok)return yield t.json();throw new Error(`Failed to connect to "${e}": ${t.status}`)}))}parseOcResponse(e){this.ocVer=e.tag_name,this.amsVer=this.ocVer.split(".").slice(0,3).join("."),this.loaderKipAsset=new ReleaseAsset(e.assets.filter((e=>e.name.endsWith("loader.kip")))[0]),this.sdOutZipAsset=new ReleaseAsset(e.assets.filter((e=>e.name.endsWith(".zip")))[0]),this.amsUrl=`https://github.com/Atmosphere-NX/Atmosphere/releases/tags/${this.amsVer}`}}class DownloadSection{constructor(){this.element=document.getElementById("download_btn_grid")}load(){return __awaiter(this,void 0,void 0,(function*(){for(;!this.isVisible();)yield new Promise((e=>setTimeout(e,1e3)));const e=new ReleaseInfo;yield e.load(),this.update("loader_kip_btn",`loader.kip ${e.ocVer} ${e.loaderKipAsset.updatedAt}`,e.loaderKipAsset.downloadUrl),this.update("sdout_zip_btn",`SdOut.zip ${e.ocVer} ${e.sdOutZipAsset.updatedAt}`,e.sdOutZipAsset.downloadUrl),this.update("ams_btn",`Atmosphere-NX ${e.amsVer}`,e.amsUrl)}))}isVisible(){let e=this.element.getBoundingClientRect();return e.top>0&&e.left>0&&e.bottom-e.height<(window.innerHeight||document.documentElement.clientHeight)&&e.right-e.width<(window.innerWidth||document.documentElement.clientWidth)}update(e,t,i){let s=document.getElementById(e);s.innerHTML=t,s.removeAttribute("aria-busy"),s.setAttribute("href",i)}}const fileInput=document.getElementById("file");fileInput.addEventListener("change",(e=>{var t=new Cust;if(!e.target||!e.target.files)return;let i=new FileReader;i.readAsArrayBuffer(e.target.files[0]),i.onloadend=e=>{e.target.readyState==FileReader.DONE&&t.load(e.target.result)}})),addEventListener("DOMContentLoaded",(e=>__awaiter(this,void 0,void 0,(function*(){yield(new DownloadSection).load()}))));
diff --git a/pages/src/main.ts b/pages/src/main.ts
index a5933f6a..5de0e77a 100644
--- a/pages/src/main.ts
+++ b/pages/src/main.ts
@@ -126,7 +126,7 @@ var CustTable: Array = [
"mtcConf",
"DRAM Timing",
CustPlatform.Mariko,
- 2,
+ 4,
["0: AUTO_ADJ_MARIKO_SAFE: Auto adjust timings for LPDDR4 ≤3733 Mbps specs, 8Gb density. (Default)",
"1: AUTO_ADJ_MARIKO_4266: Auto adjust timings for LPDDR4X 4266 Mbps specs, 8Gb density.",
"2: NO_ADJ_ALL: No timing adjustment for both Erista and Mariko. Might achieve better performance on Mariko but lower maximum frequency is expected."],
@@ -439,7 +439,7 @@ class Cust {
parse() {
let offset = this.beginOffset + this.magicLen;
- let revLen = 2;
+ let revLen = 4;
let rev = this.mapper[revLen].get(offset);
if (rev != CUST_REV) {
throw new Error(`Unsupported custRev, expected: ${CUST_REV}, got ${rev}`);
@@ -493,7 +493,7 @@ class ReleaseInfo {
sdOutZipAsset: ReleaseAsset;
amsUrl: string;
- readonly ocLatestApi = "https://api.github.com/repos/KazushiMe/Switch-OC-Suite/releases/latest";
+ readonly ocLatestApi = "https://api.github.com/repos/hanai3Bi/Switch-OC-Suite/releases/latest";
async load() {
try {