Add a DRM plane property "color_mode" for panels that support 3-color (black/white/red) display modes.
The property allows runtime selection between: - bw (black/white): R1 format represents black (0) and white (1) - 3color: R1 format represents red ink (1) on white background The property is created on all panels with "black-white" selectable; panels with red_supported = true also expose the "3-color" option. The default is set from the panel configuration's default_color_mode field (typically BW for monochrome panels). Signed-off-by: Devarsh Thakkar <[email protected]> --- Changes in v3: - Reject 3-color mode together with partial refresh in the plane atomic_check, as partial refresh does not update the red channel - Only create the color_mode property on panels with a red plane instead of exposing a property with a single possible value --- drivers/gpu/drm/solomon/ssd16xx.c | 51 +++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/drivers/gpu/drm/solomon/ssd16xx.c b/drivers/gpu/drm/solomon/ssd16xx.c index f53c67ae7d31..6037717635a4 100644 --- a/drivers/gpu/drm/solomon/ssd16xx.c +++ b/drivers/gpu/drm/solomon/ssd16xx.c @@ -399,6 +399,7 @@ struct ssd16xx_device { u8 spi_buf[64] ____cacheline_aligned; /* DMA-safe buffer for SPI transfers */ struct drm_property *refresh_mode_property; + struct drm_property *color_mode_property; }; /* Plane state subclass: refresh_mode lives on the plane, not the connector, @@ -407,6 +408,7 @@ struct ssd16xx_device { struct ssd16xx_plane_state { struct drm_shadow_plane_state base; enum ssd16xx_refresh_mode refresh_mode; /* Pending refresh mode */ + enum ssd16xx_color_mode color_mode; /* Pending color mode */ }; #define to_ssd16xx_plane_state(s) \ @@ -1457,6 +1459,7 @@ static struct drm_plane_state *ssd16xx_plane_atomic_create_state(struct drm_plan __drm_gem_shadow_plane_state_init(plane, &ssd_state->base); ssd_state->refresh_mode = device->refresh_mode; + ssd_state->color_mode = device->color_mode; return &ssd_state->base.base; } @@ -1499,6 +1502,10 @@ static int ssd16xx_plane_atomic_get_property(struct drm_plane *plane, *val = ssd_state->refresh_mode; return 0; } + if (property == device->color_mode_property) { + *val = ssd_state->color_mode; + return 0; + } return -EINVAL; } @@ -1516,6 +1523,18 @@ static int ssd16xx_plane_atomic_set_property(struct drm_plane *plane, ssd_state->refresh_mode = val; return 0; } + if (property == device->color_mode_property) { + if (val > SSD16XX_COLOR_MODE_3COLOR) + return -EINVAL; + if (val == SSD16XX_COLOR_MODE_3COLOR && + !device->device_cfg->red_supported) { + drm_dbg(&device->drm, + "3-color not supported by this panel\n"); + return -EINVAL; + } + ssd_state->color_mode = val; + return 0; + } return -EINVAL; } @@ -1535,11 +1554,20 @@ static int ssd16xx_plane_atomic_check(struct drm_plane *plane, { struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); + struct ssd16xx_plane_state *ssd_state = + to_ssd16xx_plane_state(new_plane_state); struct drm_crtc_state *crtc_state; if (!new_plane_state->crtc) return 0; + if (ssd_state->color_mode == SSD16XX_COLOR_MODE_3COLOR && + ssd_state->refresh_mode == SSD16XX_REFRESH_PARTIAL) { + drm_dbg_atomic(plane->dev, + "3-color mode does not support partial refresh\n"); + return -EINVAL; + } + crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_state->crtc); return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, @@ -1608,6 +1636,7 @@ static void ssd16xx_plane_atomic_update(struct drm_plane *plane, } device->refresh_mode = new_ssd->refresh_mode; + device->color_mode = new_ssd->color_mode; /* * When refresh_mode_init was set, use the specified mode for this first @@ -1855,6 +1884,11 @@ static const struct drm_prop_enum_list ssd16xx_refresh_mode_enum[] = { { SSD16XX_REFRESH_FAST, "fast" }, }; +static const struct drm_prop_enum_list ssd16xx_color_mode_enum[] = { + { SSD16XX_COLOR_MODE_BW, "black-white" }, + { SSD16XX_COLOR_MODE_3COLOR, "3-color" }, +}; + static int ssd16xx_plane_create_properties(struct ssd16xx_device *device) { struct drm_device *drm = &device->drm; @@ -1869,6 +1903,23 @@ static int ssd16xx_plane_create_properties(struct ssd16xx_device *device) drm_object_attach_property(plane_obj, device->refresh_mode_property, device->refresh_mode); + + /* + * Color mode: only meaningful on panels with a physical red plane. + * BW-only panels get no property at all rather than a one-value knob. + */ + if (!device->device_cfg->red_supported) + return 0; + + device->color_mode_property = + drm_property_create_enum(drm, 0, "color_mode", + ssd16xx_color_mode_enum, + ARRAY_SIZE(ssd16xx_color_mode_enum)); + if (!device->color_mode_property) + return -ENOMEM; + drm_object_attach_property(plane_obj, + device->color_mode_property, + device->color_mode); return 0; } -- 2.39.1
