diff --git a/exosphere/mariko_fatal/source/fatal_display.cpp b/exosphere/mariko_fatal/source/fatal_display.cpp index a94ebbb8d..46bd18ade 100644 --- a/exosphere/mariko_fatal/source/fatal_display.cpp +++ b/exosphere/mariko_fatal/source/fatal_display.cpp @@ -15,23 +15,439 @@ */ #include #include "fatal_device_page_table.hpp" +#include "fatal_registers_di.hpp" namespace ams::secmon::fatal { - void InitializeDisplay() { - /* TODO */ - AMS_SECMON_LOG("InitializeDisplay not yet implemented\n"); + namespace { + + #include "fatal_display_config.inc" + } - void ShowDisplay(const ams::impl::FatalErrorContext *f_ctx, const Result save_result) { - /* TODO */ - AMS_UNUSED(f_ctx, save_result); - AMS_SECMON_LOG("ShowDisplay not yet implemented\n"); + namespace { + + /* Helpful defines. */ + constexpr size_t FrameBufferHeight = 768; + constexpr size_t FrameBufferWidth = 1280; + constexpr size_t FrameBufferSize = FrameBufferHeight * FrameBufferWidth * sizeof(u32); + + 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 EnableBacklightForVendor2050ForHardwareTypeFive(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(); + std::memset(g_frame_buffer, 0, FrameBufferSize); + hw::FlushDataCache(g_frame_buffer, FrameBufferSize); + + /* Attach the frame buffer to DC. */ + InitializeDevicePageTableForDc(); + } + } + + void FinalizeFrameBuffer() { + /* We don't actually support finalizing the framebuffer, so do nothing here. */ + } + } void FinalizeDisplay() { + FinalizeFrameBuffer(); /* TODO */ AMS_SECMON_LOG("FinalizeDisplay not yet implemented\n"); } + void InitializeDisplay() { + /* Ensure that the display is finalized. */ + /* TODO */ + + /* 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_Five) { + /* 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_Five) { + 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) { + /* Draw the image to the screen. */ + std::memset(g_frame_buffer, 0, FrameBufferSize); + { + /* TODO: Actually print the contents of the report. */ + AMS_UNUSED(f_ctx, save_result); + for (size_t n = 0; n < 8; n++) { + const size_t x = n * (FrameBufferWidth / 8); + for (size_t cur_y = 0; cur_y < FrameBufferHeight; cur_y++) { + for (size_t cur_x = 0; cur_x < (FrameBufferWidth / 8); cur_x++) { + g_frame_buffer[(FrameBufferWidth - (x + cur_x)) * FrameBufferHeight + 0 + cur_y] = ((0x20 * n) | 0x1F); + } + } + } + } + hw::FlushDataCache(g_frame_buffer, FrameBufferSize); + + /* Enable backlight. */ + constexpr auto DisplayBrightness = 100; + if (GetLcdVendor() == 0x2050) { + EnableBacklightForVendor2050ForHardwareTypeFive(DisplayBrightness); + } else { + EnableBacklightForGeneric(DisplayBrightness); + } + } + } diff --git a/exosphere/mariko_fatal/source/fatal_display_config.inc b/exosphere/mariko_fatal/source/fatal_display_config.inc new file mode 100644 index 000000000..21377b97c --- /dev/null +++ b/exosphere/mariko_fatal/source/fatal_display_config.inc @@ -0,0 +1,682 @@ +/* + * Copyright (c) 2018-2020 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 . + */ + +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}, +}; diff --git a/exosphere/mariko_fatal/source/fatal_main.cpp b/exosphere/mariko_fatal/source/fatal_main.cpp index 169a43f38..205f3a845 100644 --- a/exosphere/mariko_fatal/source/fatal_main.cpp +++ b/exosphere/mariko_fatal/source/fatal_main.cpp @@ -22,6 +22,8 @@ namespace ams::secmon::fatal { namespace { + constexpr inline int I2cAddressMax77620Pmic = 0x3C; + ALWAYS_INLINE const ams::impl::FatalErrorContext *GetFatalErrorContext() { return MemoryRegionVirtualTzramMarikoProgramFatalErrorContext.GetPointer(); } @@ -58,6 +60,10 @@ namespace ams::secmon::fatal { AMS_SECMON_LOG("Failed to save fatal error context: %08x\n", result.GetValue()); } + /* Ensure that i2c-5 is usable for communicating with the pmic. */ + clkrst::EnableI2c5Clock(); + i2c::Initialize(i2c::Port_5); + /* Display the fatal error. */ { AMS_SECMON_LOG("Showing Display, LCD Vendor = %04x\n", GetLcdVendor()); @@ -69,7 +75,15 @@ namespace ams::secmon::fatal { /* Ensure we have nothing waiting to be logged. */ AMS_LOG_FLUSH(); - /* TODO: Wait for a button press, then reboot. */ + /* 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(); } diff --git a/exosphere/mariko_fatal/source/fatal_registers_di.hpp b/exosphere/mariko_fatal/source/fatal_registers_di.hpp new file mode 100644 index 000000000..db32152fe --- /dev/null +++ b/exosphere/mariko_fatal/source/fatal_registers_di.hpp @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (C) 2018 CTCaer + * Copyright (c) 2018-2020 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 . + */ +#pragma once +#include + +#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 diff --git a/exosphere/program/source/secmon_mariko_fatal_error.cpp b/exosphere/program/source/secmon_mariko_fatal_error.cpp index e4cd4b3ae..33999a5a4 100644 --- a/exosphere/program/source/secmon_mariko_fatal_error.cpp +++ b/exosphere/program/source/secmon_mariko_fatal_error.cpp @@ -42,7 +42,6 @@ namespace ams::secmon { /* If not all cores have received the fatal, we need to trigger the interrupt on other cores. */ if (g_fatal_error_mask != (1u << NumCores) - 1) { - /* Configure and send the interrupt to the next core. */ const auto next_core = __builtin_ctz(~g_fatal_error_mask); gic::SetSpiTargetCpu(MarikoFatalErrorInterruptId, (1u << next_core)); diff --git a/libraries/libexosphere/include/exosphere/pmic.hpp b/libraries/libexosphere/include/exosphere/pmic.hpp index fc43715b8..ea85f60a0 100644 --- a/libraries/libexosphere/include/exosphere/pmic.hpp +++ b/libraries/libexosphere/include/exosphere/pmic.hpp @@ -32,6 +32,8 @@ namespace ams::pmic { void DisableVddCpu(Regulator regulator); void EnableSleep(); void PowerOff(); + void ShutdownSystem(bool reboot); bool IsAcOk(); + bool IsPowerButtonPressed(); } \ No newline at end of file diff --git a/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp b/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp index 2de446314..3c46b2965 100644 --- a/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp +++ b/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp @@ -149,7 +149,10 @@ namespace ams::secmon { HANDLER(ExceptionVectors, I2c1, UINT64_C(0x6000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ HANDLER(MemoryController0, ExceptionVectors, UINT64_C(0x7001C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ HANDLER(MemoryController1, MemoryController0, UINT64_C(0x7001D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ - HANDLER(Sdmmc, MemoryController1, UINT64_C(0x700B0000), UINT64_C(0x1000), true, ## __VA_ARGS__) + HANDLER(Sdmmc, MemoryController1, UINT64_C(0x700B0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ + HANDLER(Disp1, Sdmmc, UINT64_C(0x54200000), UINT64_C(0x3000), true, ## __VA_ARGS__) \ + HANDLER(Dsi, Disp1, UINT64_C(0x54300000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ + HANDLER(MipiCal, Dsi, UINT64_C(0x700E3000), UINT64_C(0x1000), true, ## __VA_ARGS__) #define DEFINE_DEVICE_REGION(_NAME_, _PREV_, _ADDRESS_, _SIZE_, _SECURE_) \ constexpr inline const MemoryRegion MemoryRegionVirtualDevice##_NAME_ = MemoryRegion(MemoryRegionVirtualDevice##_PREV_.GetEndAddress() + 0x1000, _SIZE_); \ diff --git a/libraries/libexosphere/source/pmic/pmic_api.cpp b/libraries/libexosphere/source/pmic/pmic_api.cpp index 808d465d0..f42d4264e 100644 --- a/libraries/libexosphere/source/pmic/pmic_api.cpp +++ b/libraries/libexosphere/source/pmic/pmic_api.cpp @@ -176,8 +176,40 @@ namespace ams::pmic { i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterOnOffCnfg1, MAX77620_ONOFFCNFG1_PWR_OFF); } + void ShutdownSystem(bool reboot) { + /* Get value, set or clear software reset mask. */ + u8 on_off_2_val = i2c::QueryByte(i2c::Port_5, I2cAddressMax77620Pmic, MAX77620_REG_ONOFFCNFG2); + if (reboot) { + on_off_2_val |= MAX77620_ONOFFCNFG2_SFT_RST_WK; + } else { + on_off_2_val &= ~(MAX77620_ONOFFCNFG2_SFT_RST_WK); + } + i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, MAX77620_REG_ONOFFCNFG2, on_off_2_val); + + /* Get value, set software reset mask. */ + u8 on_off_1_val = i2c::QueryByte(i2c::Port_5, I2cAddressMax77620Pmic, MAX77620_REG_ONOFFCNFG1); + on_off_1_val |= MAX77620_ONOFFCNFG1_SFT_RST; + + /* NOTE: Here, userland finalizes the battery on non-Calcio. */ + if (fuse::GetHardwareType() != fuse::HardwareType_Calcio) { + /* ... */ + } + + /* Actually write the value to trigger shutdown/reset. */ + i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, MAX77620_REG_ONOFFCNFG1, on_off_1_val); + + /* Allow up to 5 seconds for shutdown/reboot to take place. */ + util::WaitMicroSeconds(5'000'000ul); + + AMS_ABORT("Shutdown failed"); + } + bool IsAcOk() { return (GetPmicOnOffStat() & (1 << 1)) != 0; } + bool IsPowerButtonPressed() { + return (GetPmicOnOffStat() & (1 << 2)) != 0; + } + } diff --git a/stratosphere/boot/source/boot_display.cpp b/stratosphere/boot/source/boot_display.cpp index 126b20d17..950916226 100644 --- a/stratosphere/boot/source/boot_display.cpp +++ b/stratosphere/boot/source/boot_display.cpp @@ -344,9 +344,6 @@ namespace ams::boot { 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); - /* NOTE: Nintendo bug here. */ - /* As of 8.0.0, Nintendo writes this list to CAR instead of DSI */ - /* This results in them zeroing CLK_SOURCE_UARTA... */ 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);