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];
};
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_non_discrete(void * genode_xml);
void lx_emul_i915_hotplug_connector(void);
void lx_emul_i915_report_connector(void * lx_data, void * genode_xml,
char const *name, char connected,
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 *)
{
while (true) {
struct drm_connector_list_iter conn_iter;
struct drm_connector *connector = NULL;
struct drm_device const *dev = dev_client->dev;
struct drm_connector *connector = NULL;
struct drm_device const *dev = dev_client->dev;
bool block_task = true;
drm_connector_list_iter_begin(dev, &conn_iter);
drm_client_for_each_connector_iter(connector, &conn_iter) {
struct drm_modeset_acquire_ctx ctx;
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)
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;
if (valid_id)
unchanged[connector->index] = 0;
if (!connector->state || !connector->state->crtc)
continue;
@ -872,8 +914,11 @@ static int update_content(void *)
}
drm_connector_list_iter_end(&conn_iter);
/* schedule_timeout(jiffes) or hrtimer or msleep */
msleep(20);
if (block_task)
lx_emul_task_schedule(true /* block task */);
else
/* schedule_timeout(jiffes) or hrtimer or msleep */
msleep(CAPTURE_RATE_MS);
}
return 0;

View File

@ -67,9 +67,8 @@ struct Framebuffer::Driver
using Space = Id_space<Connector>;
using Id = Space::Id;
Space::Element id_element;
Connector(Space &space, Id id) : id_element(*this, space, id) { }
Space::Element id_element;
Signal_handler<Connector> capture_wakeup;
addr_t base { };
Capture::Area size { };
@ -78,11 +77,23 @@ struct Framebuffer::Driver
Constructible<Capture::Connection> capture { };
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 { };
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;
@ -109,6 +120,10 @@ struct Framebuffer::Driver
dirty = true;
});
});
if (!dirty && may_stop)
connector.capture->capture_stopped();
}, [&](){ /* unknown connector id */ });
return dirty;
@ -136,6 +151,8 @@ struct Framebuffer::Driver
Capture::Connection::Screen::Attr attr = { .px = conn.size, .mm = conn.size_mm };
conn.capture.construct(env, label);
conn.screen .construct(*conn.capture, env.rm(), attr);
conn.capture->wakeup_sigh(conn.capture_wakeup);
} else {
conn.screen .destruct();
conn.capture.destruct();
@ -450,7 +467,9 @@ void lx_emul_i915_framebuffer_ready(unsigned const connector_id,
if (!base)
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) {
@ -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 const id = Framebuffer::Driver::Connector::Id { connector_id };
return drv.capture(drv.ids, id);
return drv.capture(drv.ids, id, may_stop);
}