intel/display: support stop/wakeup protocol

Issue #5344
This commit is contained in:
Alexander Boettcher 2024-09-23 16:53:21 +02:00 committed by Christian Helmuth
parent 50cc52a091
commit 458458b65f
3 changed files with 80 additions and 14 deletions

View File

@ -33,10 +33,12 @@ struct genode_mode {
char name[32]; char name[32];
}; };
int lx_emul_i915_blit(unsigned); int lx_emul_i915_blit(unsigned const connector_id, char const may_sleep);
void lx_emul_i915_wakeup(unsigned connector_id);
void lx_emul_i915_report_discrete(void * genode_xml); void lx_emul_i915_report_discrete(void * genode_xml);
void lx_emul_i915_report_non_discrete(void * genode_xml); void lx_emul_i915_report_non_discrete(void * genode_xml);
void lx_emul_i915_hotplug_connector(void); void lx_emul_i915_hotplug_connector(void);
void lx_emul_i915_report_connector(void * lx_data, void * genode_xml, void lx_emul_i915_report_connector(void * lx_data, void * genode_xml,
char const *name, char connected, char const *name, char connected,
unsigned brightness, unsigned brightness,

View File

@ -837,25 +837,67 @@ static void mark_framebuffer_dirty(struct drm_framebuffer * const fb)
} }
/* track per connector (16 max) the empty capture attempts before stopping */
enum { CAPTURE_RATE_MS = 10, ATTEMPTS_BEFORE_STOP = 7 };
static unsigned unchanged[16] = { };
void lx_emul_i915_wakeup(unsigned const connector_id)
{
bool const valid_id = connector_id < sizeof(unchanged) / sizeof(*unchanged);
if (!valid_id) {
printk("%s: connector id invalid %d\n", __func__, connector_id);
return;
}
unchanged[connector_id] = 0;
/* wake potential sleeping update task */
lx_emul_task_unblock(lx_update_task);
}
static int update_content(void *) static int update_content(void *)
{ {
while (true) { while (true) {
struct drm_connector_list_iter conn_iter; struct drm_connector_list_iter conn_iter;
struct drm_connector *connector = NULL; struct drm_connector *connector = NULL;
struct drm_device const *dev = dev_client->dev; struct drm_device const *dev = dev_client->dev;
bool block_task = true;
drm_connector_list_iter_begin(dev, &conn_iter); drm_connector_list_iter_begin(dev, &conn_iter);
drm_client_for_each_connector_iter(connector, &conn_iter) { drm_client_for_each_connector_iter(connector, &conn_iter) {
struct drm_modeset_acquire_ctx ctx; struct drm_modeset_acquire_ctx ctx;
struct drm_framebuffer *fb = NULL; struct drm_framebuffer *fb = NULL;
int err = -1;
int err = -1;
bool may_sleep = false;
bool const valid_id = connector->index < sizeof(unchanged) / sizeof(*unchanged);
if (connector->status != connector_status_connected) if (connector->status != connector_status_connected)
continue; continue;
if (!lx_emul_i915_blit(connector->index)) if (valid_id) {
unchanged[connector->index] ++;
if (unchanged[connector->index] > ATTEMPTS_BEFORE_STOP)
continue;
}
else
printk("%s: connector id invalid %d\n", __func__, connector->index);
block_task = false;
if (valid_id)
may_sleep = unchanged[connector->index] >= ATTEMPTS_BEFORE_STOP;
if (!lx_emul_i915_blit(connector->index, may_sleep))
continue; continue;
if (valid_id)
unchanged[connector->index] = 0;
if (!connector->state || !connector->state->crtc) if (!connector->state || !connector->state->crtc)
continue; continue;
@ -872,8 +914,11 @@ static int update_content(void *)
} }
drm_connector_list_iter_end(&conn_iter); drm_connector_list_iter_end(&conn_iter);
/* schedule_timeout(jiffes) or hrtimer or msleep */ if (block_task)
msleep(20); lx_emul_task_schedule(true /* block task */);
else
/* schedule_timeout(jiffes) or hrtimer or msleep */
msleep(CAPTURE_RATE_MS);
} }
return 0; return 0;

View File

@ -67,9 +67,8 @@ struct Framebuffer::Driver
using Space = Id_space<Connector>; using Space = Id_space<Connector>;
using Id = Space::Id; using Id = Space::Id;
Space::Element id_element; Space::Element id_element;
Signal_handler<Connector> capture_wakeup;
Connector(Space &space, Id id) : id_element(*this, space, id) { }
addr_t base { }; addr_t base { };
Capture::Area size { }; Capture::Area size { };
@ -78,11 +77,23 @@ struct Framebuffer::Driver
Constructible<Capture::Connection> capture { }; Constructible<Capture::Connection> capture { };
Constructible<Capture::Connection::Screen> screen { }; Constructible<Capture::Connection::Screen> screen { };
Connector(Env &env, Space &space, Id id)
:
id_element(*this, space, id),
capture_wakeup(env.ep(), *this, &Connector::wakeup_handler)
{ }
void wakeup_handler()
{
lx_emul_i915_wakeup(unsigned(id_element.id().value));
Lx_kit::env().scheduler.execute();
}
}; };
Connector::Space ids { }; Connector::Space ids { };
bool capture(Connector::Space &ids, Connector::Id const &id) bool capture(Connector::Space &ids, Connector::Id const &id, bool const may_stop)
{ {
using Pixel = Capture::Pixel; using Pixel = Capture::Pixel;
@ -109,6 +120,10 @@ struct Framebuffer::Driver
dirty = true; dirty = true;
}); });
}); });
if (!dirty && may_stop)
connector.capture->capture_stopped();
}, [&](){ /* unknown connector id */ }); }, [&](){ /* unknown connector id */ });
return dirty; return dirty;
@ -136,6 +151,8 @@ struct Framebuffer::Driver
Capture::Connection::Screen::Attr attr = { .px = conn.size, .mm = conn.size_mm }; Capture::Connection::Screen::Attr attr = { .px = conn.size, .mm = conn.size_mm };
conn.capture.construct(env, label); conn.capture.construct(env, label);
conn.screen .construct(*conn.capture, env.rm(), attr); conn.screen .construct(*conn.capture, env.rm(), attr);
conn.capture->wakeup_sigh(conn.capture_wakeup);
} else { } else {
conn.screen .destruct(); conn.screen .destruct();
conn.capture.destruct(); conn.capture.destruct();
@ -450,7 +467,9 @@ void lx_emul_i915_framebuffer_ready(unsigned const connector_id,
if (!base) if (!base)
return; return;
new (drv.heap) Connector (drv.ids, id); new (drv.heap) Connector (env, drv.ids, id);
lx_emul_i915_wakeup(unsigned(id.value));
}); });
drv.ids.apply<Connector>(id, [&](Connector &conn) { drv.ids.apply<Connector>(id, [&](Connector &conn) {
@ -549,13 +568,13 @@ void lx_emul_i915_report_modes(void * genode_xml, struct genode_mode *mode)
} }
int lx_emul_i915_blit(unsigned connector_id) int lx_emul_i915_blit(unsigned const connector_id, char const may_stop)
{ {
auto &drv = driver(Lx_kit::env().env); auto &drv = driver(Lx_kit::env().env);
auto const id = Framebuffer::Driver::Connector::Id { connector_id }; auto const id = Framebuffer::Driver::Connector::Id { connector_id };
return drv.capture(drv.ids, id); return drv.capture(drv.ids, id, may_stop);
} }