Expose Nouveau panel brightness through the connector LUMINANCE property when DRM_LUMINANCE is enabled. Reuse the existing NV40, NV50, and DPCD hardware paths while preserving the backlight class interface otherwise.
Signed-off-by: Mario Limonciello <[email protected]> --- drivers/gpu/drm/nouveau/Kconfig | 4 +- drivers/gpu/drm/nouveau/dispnv50/disp.c | 2 +- drivers/gpu/drm/nouveau/nouveau_backlight.c | 110 ++++++++++++++++---- drivers/gpu/drm/nouveau/nouveau_connector.c | 2 + drivers/gpu/drm/nouveau/nouveau_connector.h | 14 +++ 5 files changed, 108 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig index 3b5757aed9c84..2dcb7c5344f48 100644 --- a/drivers/gpu/drm/nouveau/Kconfig +++ b/drivers/gpu/drm/nouveau/Kconfig @@ -17,13 +17,13 @@ config DRM_NOUVEAU select DRM_SCHED select I2C select I2C_ALGOBIT - select BACKLIGHT_CLASS_DEVICE if DRM_NOUVEAU_BACKLIGHT + select BACKLIGHT_CLASS_DEVICE if DRM_NOUVEAU_BACKLIGHT && !DRM_LUMINANCE select X86_PLATFORM_DEVICES if ACPI && X86 select ACPI_WMI if ACPI && X86 select MXM_WMI if ACPI && X86 select POWER_SUPPLY # Similar to i915, we need to select ACPI_VIDEO and it's dependencies - select BACKLIGHT_CLASS_DEVICE if ACPI && X86 + select BACKLIGHT_CLASS_DEVICE if ACPI && X86 && !DRM_LUMINANCE select INPUT if ACPI && X86 select THERMAL if ACPI && X86 select ACPI_VIDEO if ACPI && X86 diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index add19d479ebe4..3810083daefdc 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -1839,7 +1839,7 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_commit *st backlight = nv_connector->backlight; if (backlight && backlight->uses_dpcd) drm_edp_backlight_enable(&nv_connector->aux, &backlight->edp_info, - backlight->dev->props.brightness); + backlight->brightness); #endif break; diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index da1ee24a2531d..fefcfa8c2a3a9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -73,12 +73,10 @@ nv40_get_intensity(struct backlight_device *bd) } static int -nv40_set_intensity(struct backlight_device *bd) +nv40_set_intensity_value(struct nouveau_encoder *nv_encoder, int val) { - struct nouveau_encoder *nv_encoder = bl_get_data(bd); struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); struct nvif_object *device = &drm->client.device.object; - int val = bd->props.brightness; int reg = nvif_rd32(device, NV40_PMC_BACKLIGHT); nvif_wr32(device, NV40_PMC_BACKLIGHT, @@ -87,6 +85,12 @@ nv40_set_intensity(struct backlight_device *bd) return 0; } +static int +nv40_set_intensity(struct backlight_device *bd) +{ + return nv40_set_intensity_value(bl_get_data(bd), bd->props.brightness); +} + static const struct backlight_ops nv40_bl_ops = { .options = BL_CORE_SUSPENDRESUME, .get_brightness = nv40_get_intensity, @@ -105,6 +109,8 @@ nv40_backlight_init(struct nouveau_encoder *encoder, return -ENODEV; props->max_brightness = 31; + props->brightness = (nvif_rd32(device, NV40_PMC_BACKLIGHT) & + NV40_PMC_BACKLIGHT_MASK) >> 16; *ops = &nv40_bl_ops; return 0; } @@ -234,12 +240,15 @@ nv50_backlight_init(struct nouveau_backlight *bl, const struct backlight_ops **ops) { struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); + int brightness; + + brightness = nvif_outp_bl_get(&nv_encoder->outp); /* * Note when this runs the connectors have not been probed yet, * so nv_conn->base.status is not set yet. */ - if (nvif_outp_bl_get(&nv_encoder->outp) < 0 || + if (brightness < 0 || drm_helper_probe_detect(&nv_conn->base, NULL, false) != connector_status_connected) return -ENODEV; @@ -284,6 +293,7 @@ nv50_backlight_init(struct nouveau_backlight *bl, *ops = &nv50_bl_ops; props->max_brightness = 100; + props->brightness = brightness; return 0; } @@ -317,10 +327,13 @@ nouveau_backlight_init(struct drm_connector *connector) bl = kzalloc_obj(*bl); if (!bl) return -ENOMEM; + bl->id = -1; + bl->encoder = nv_encoder; switch (device->info.family) { case NV_DEVICE_INFO_V0_CURIE: ret = nv40_backlight_init(nv_encoder, &props, &ops); + bl->uses_nv40 = true; break; case NV_DEVICE_INFO_V0_TESLA: case NV_DEVICE_INFO_V0_FERMI: @@ -349,26 +362,39 @@ nouveau_backlight_init(struct drm_connector *connector) goto fail_alloc; } - if (!nouveau_get_backlight_name(backlight_name, bl)) { - NV_ERROR(drm, "Failed to retrieve a unique name for the backlight interface\n"); - goto fail_alloc; - } - props.type = BACKLIGHT_RAW; - bl->dev = backlight_device_register(backlight_name, connector->kdev, - nv_encoder, ops, &props); - if (IS_ERR(bl->dev)) { - if (bl->id >= 0) - ida_free(&bl_ida, bl->id); - ret = PTR_ERR(bl->dev); - goto fail_alloc; + bl->brightness = props.brightness; + bl->max_brightness = props.max_brightness; + if (IS_ENABLED(CONFIG_DRM_LUMINANCE)) { + ret = drm_connector_attach_luminance_property(connector, 0, props.max_brightness, + props.brightness); + if (ret) + goto fail_alloc; + } else { + if (!nouveau_get_backlight_name(backlight_name, bl)) { + NV_ERROR(drm, + "Failed to retrieve a unique name for the backlight interface\n"); + goto fail_alloc; + } + + bl->dev = backlight_device_register(backlight_name, connector->kdev, + nv_encoder, ops, &props); + if (IS_ERR(bl->dev)) { + if (bl->id >= 0) + ida_free(&bl_ida, bl->id); + ret = PTR_ERR(bl->dev); + goto fail_alloc; + } } nouveau_connector(connector)->backlight = bl; - if (!bl->dev->props.brightness) - bl->dev->props.brightness = - bl->dev->ops->get_brightness(bl->dev); - backlight_update_status(bl->dev); + if (bl->dev) { + if (!bl->dev->props.brightness) + bl->dev->props.brightness = + bl->dev->ops->get_brightness(bl->dev); + bl->brightness = bl->dev->props.brightness; + backlight_update_status(bl->dev); + } return 0; @@ -396,7 +422,9 @@ nouveau_backlight_fini(struct drm_connector *connector) if (bl->id >= 0) ida_free(&bl_ida, bl->id); - backlight_device_unregister(bl->dev); + if (!IS_ENABLED(CONFIG_DRM_LUMINANCE)) + backlight_device_unregister(bl->dev); + nv_conn->backlight = NULL; kfree(bl); } @@ -412,3 +440,43 @@ nouveau_backlight_dtor(void) { ida_destroy(&bl_ida); } + +void +nouveau_backlight_set_luminance(const struct drm_connector_state *conn_state) +{ + struct nouveau_connector *nv_connector = nouveau_connector(conn_state->connector); + struct nouveau_backlight *bl = nv_connector->backlight; + unsigned int luminance = conn_state->luminance; + + if (!bl || !bl->max_brightness) + return; + + bl->brightness = luminance; + if (bl->uses_dpcd) { + drm_edp_backlight_set_level(&nv_connector->aux, &bl->edp_info, + luminance); + return; + } + + if (bl->uses_nv40) + nv40_set_intensity_value(bl->encoder, luminance); + else + nvif_outp_bl_set(&bl->encoder->outp, luminance); +} + +void +nouveau_backlight_disable_luminance(const struct drm_connector_state *conn_state) +{ + struct nouveau_connector *nv_connector = nouveau_connector(conn_state->connector); + struct nouveau_backlight *bl = nv_connector->backlight; + + if (!bl) + return; + + if (bl->uses_dpcd) + drm_edp_backlight_disable(&nv_connector->aux, &bl->edp_info); + else if (bl->uses_nv40) + nv40_set_intensity_value(bl->encoder, 0); + else + nvif_outp_bl_set(&bl->encoder->outp, 0); +} diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index cc3caf8de64b0..56ee579ea7909 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -1225,6 +1225,8 @@ nouveau_connector_helper_funcs = { .mode_valid = nouveau_connector_mode_valid, .best_encoder = nouveau_connector_best_encoder, .atomic_check = nouveau_connector_atomic_check, + .set_luminance = nouveau_backlight_set_luminance, + .disable_luminance = nouveau_backlight_disable_luminance, }; static const struct drm_connector_funcs diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index eb292d2ba4bcd..0cee3e4c1d11c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -50,9 +50,13 @@ struct nouveau_backlight { struct backlight_device *dev; struct drm_edp_backlight_info edp_info; + struct nouveau_encoder *encoder; bool uses_dpcd : 1; + bool uses_nv40 : 1; int id; + int brightness; + int max_brightness; }; #endif @@ -239,6 +243,8 @@ extern int nouveau_backlight_init(struct drm_connector *); extern void nouveau_backlight_fini(struct drm_connector *); extern void nouveau_backlight_ctor(void); extern void nouveau_backlight_dtor(void); +void nouveau_backlight_set_luminance(const struct drm_connector_state *conn_state); +void nouveau_backlight_disable_luminance(const struct drm_connector_state *conn_state); #else static inline int nouveau_backlight_init(struct drm_connector *connector) @@ -257,6 +263,14 @@ nouveau_backlight_ctor(void) { static inline void nouveau_backlight_dtor(void) { } + +static inline void +nouveau_backlight_set_luminance(const struct drm_connector_state *conn_state) { +} + +static inline void +nouveau_backlight_disable_luminance(const struct drm_connector_state *conn_state) { +} #endif #endif /* __NOUVEAU_CONNECTOR_H__ */ -- 2.43.0
