Skip to content

Commit

Permalink
display: Put DCP to sleep if display is external
Browse files Browse the repository at this point in the history
This stops DCP from killing our modeset if the connection cycles.

Also force a (potential) configure cycle if the display is external;
this makes sure updated stage2s will have a chance at fixing issues of
old stage1s. Modesetting is fast when it's the same mode as before.

Signed-off-by: Hector Martin <marcan@marcan.st>
  • Loading branch information
marcan committed May 31, 2022
1 parent 9748b55 commit 714420a
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 22 deletions.
9 changes: 7 additions & 2 deletions proxyclient/m1n1/proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ class EXC_RET(IntEnum):
EXIT_GUEST = 3
STEP = 4

class DCP_SHUTDOWN_MODE(IntEnum):
QUIESCED = 0
SLEEP_IF_EXTERNAL = 1
SLEEP = 2

ExcInfo = Struct(
"regs" / Array(32, Int64ul),
"spsr" / RegAdapter(SPSR),
Expand Down Expand Up @@ -1043,8 +1048,8 @@ def display_init(self):
return self.request(self.P_DISPLAY_INIT)
def display_configure(self, cfg):
return self.request(self.P_DISPLAY_CONFIGURE, cfg)
def display_shutdown(self):
return self.request(self.P_DISPLAY_SHUTDOWN)
def display_shutdown(self, mode):
return self.request(self.P_DISPLAY_SHUTDOWN, mode)

__all__.extend(k for k, v in globals().items()
if (callable(v) or isinstance(v, type)) and v.__module__ == __name__)
Expand Down
10 changes: 8 additions & 2 deletions src/dcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "dcp.h"
#include "adt.h"
#include "malloc.h"
#include "pmgr.h"
#include "rtkit.h"
#include "utils.h"

Expand Down Expand Up @@ -59,9 +60,14 @@ dcp_dev_t *dcp_init(const char *dcp_path, const char *dcp_dart_path, const char
return NULL;
}

int dcp_shutdown(dcp_dev_t *dcp)
int dcp_shutdown(dcp_dev_t *dcp, bool sleep)
{
rtkit_quiesce(dcp->rtkit);
if (sleep) {
rtkit_sleep(dcp->rtkit);
pmgr_reset(0, "DISP0_CPU0");
} else {
rtkit_quiesce(dcp->rtkit);
}
rtkit_free(dcp->rtkit);
dart_shutdown(dcp->dart_disp);
iovad_shutdown(dcp->iovad_dcp, dcp->dart_dcp);
Expand Down
2 changes: 1 addition & 1 deletion src/dcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ typedef struct {

dcp_dev_t *dcp_init(const char *dcp_path, const char *dcp_dart_path, const char *disp_dart_path);

int dcp_shutdown(dcp_dev_t *dcp);
int dcp_shutdown(dcp_dev_t *dcp, bool sleep);

#endif
52 changes: 42 additions & 10 deletions src/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@
continue; \
}

dcp_dev_t *dcp;
dcp_iboot_if_t *iboot;
u64 fb_dva;
u64 fb_size;
static dcp_dev_t *dcp;
static dcp_iboot_if_t *iboot;
static u64 fb_dva;
static u64 fb_size;
static bool display_is_external;

#define abs(x) ((x) >= 0 ? (x) : -(x))

Expand Down Expand Up @@ -157,7 +158,7 @@ static uintptr_t display_map_fb(uintptr_t iova, u64 paddr, u64 size)
return iova;
}

static int display_start_dcp(void)
int display_start_dcp(void)
{
if (iboot)
return 0;
Expand Down Expand Up @@ -185,14 +186,14 @@ static int display_start_dcp(void)
fb_dva = display_map_fb(0, pa, size);
if (!fb_dva) {
printf("display: failed to find display DVA\n");
dcp_shutdown(dcp);
dcp_shutdown(dcp, false);
return -1;
}

iboot = dcp_ib_init(dcp);
if (!iboot) {
printf("display: failed to initialize DCP iBoot interface\n");
dcp_shutdown(dcp);
dcp_shutdown(dcp, false);
return -1;
}

Expand Down Expand Up @@ -453,9 +454,24 @@ int display_configure(const char *config)

int display_init(void)
{
int node = adt_path_offset(adt, "/arm-io/disp0");

if (node < 0) {
printf("DISP0 node not found!\n");
return -1;
}

display_is_external = adt_getprop(adt, node, "external", NULL);
if (display_is_external)
printf("display: Display is external\n");
else
printf("display: Display is internal\n");

if (cur_boot_args.video.width == 640 && cur_boot_args.video.height == 1136) {
printf("display: Dummy framebuffer found, initializing display\n");

return display_configure(NULL);
} else if (display_is_external) {
printf("display: External display found, reconfiguring\n");
return display_configure(NULL);
} else {
printf("display: Display is already initialized (%ldx%ld)\n", cur_boot_args.video.width,
Expand All @@ -464,11 +480,27 @@ int display_init(void)
}
}

void display_shutdown(void)
void display_shutdown(dcp_shutdown_mode mode)
{
if (iboot) {
dcp_ib_shutdown(iboot);
dcp_shutdown(dcp);
switch (mode) {
case DCP_QUIESCED:
printf("display: Quiescing DCP (unconditional)\n");
dcp_shutdown(dcp, false);
break;
case DCP_SLEEP_IF_EXTERNAL:
if (!display_is_external)
printf("display: Quiescing DCP (internal)\n");
else
printf("display: Sleeping DCP (external)\n");
dcp_shutdown(dcp, display_is_external);
break;
case DCP_SLEEP:
printf("display: Sleeping DCP (unconditional)\n");
dcp_shutdown(dcp, true);
break;
}
iboot = NULL;
}
}
9 changes: 8 additions & 1 deletion src/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,15 @@
#ifndef DISPLAY_H
#define DISPLAY_H

typedef enum _dcp_shutdown_mode {
DCP_QUIESCED = 0,
DCP_SLEEP_IF_EXTERNAL = 1,
DCP_SLEEP = 2,
} dcp_shutdown_mode;

int display_init(void);
int display_start_dcp(void);
int display_configure(const char *config);
void display_shutdown(void);
void display_shutdown(dcp_shutdown_mode mode);

#endif
4 changes: 3 additions & 1 deletion src/hv.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ static struct hv_secondary_info_t hv_secondary_info;
void hv_init(void)
{
pcie_shutdown();
display_shutdown();
// Make sure we wake up DCP if we put it to sleep, just quiesce it to match ADT
if (display_start_dcp() >= 0)
display_shutdown(DCP_QUIESCED);
// reenable hpm interrupts for the guest for unused iodevs
usb_hpm_restore_irqs(0);
smp_start_secondaries();
Expand Down
11 changes: 7 additions & 4 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,15 @@ void m1n1_main(void)
gxf_init();
mcc_init();
mmu_init();
aic_init();
wdt_disable();
pmgr_init();

#ifdef USE_FB
display_init();
// Kick DCP to sleep, so dodgy monitors which cause reconnect cycles don't cause us to lose the
// framebuffer.
display_shutdown(DCP_SLEEP_IF_EXTERNAL);
fb_init(false);
fb_display_logo();
#ifdef FB_SILENT_MODE
Expand All @@ -144,9 +150,6 @@ void m1n1_main(void)
#endif
#endif

aic_init();
wdt_disable();
pmgr_init();
clk_init();
cpufreq_init();
sep_init();
Expand All @@ -164,7 +167,7 @@ void m1n1_main(void)
nvme_shutdown();
exception_shutdown();
usb_iodev_shutdown();
display_shutdown();
display_shutdown(DCP_SLEEP_IF_EXTERNAL);
#ifdef USE_FB
fb_shutdown(next_stage.restore_logo);
#endif
Expand Down
2 changes: 1 addition & 1 deletion src/proxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ int proxy_process(ProxyRequest *request, ProxyReply *reply)
reply->retval = display_configure((char *)request->args[0]);
break;
case P_DISPLAY_SHUTDOWN:
display_shutdown();
display_shutdown(request->args[0]);
break;

default:
Expand Down

0 comments on commit 714420a

Please sign in to comment.