diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_backlight.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_backlight.c | 220 |
1 files changed, 107 insertions, 113 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index 408b955e5c39..5f5be6368aed 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -37,18 +37,19 @@ #include "nouveau_drv.h" #include "nouveau_reg.h" #include "nouveau_encoder.h" +#include "nouveau_connector.h" static struct ida bl_ida; #define BL_NAME_SIZE 15 // 12 for name + 2 for digits + 1 for '\0' -struct backlight_connector { - struct list_head head; +struct nouveau_backlight { + struct backlight_device *dev; int id; }; static bool -nouveau_get_backlight_name(char backlight_name[BL_NAME_SIZE], struct backlight_connector - *connector) +nouveau_get_backlight_name(char backlight_name[BL_NAME_SIZE], + struct nouveau_backlight *bl) { const int nb = ida_simple_get(&bl_ida, 0, 0, GFP_KERNEL); if (nb < 0 || nb >= 100) @@ -57,17 +58,18 @@ nouveau_get_backlight_name(char backlight_name[BL_NAME_SIZE], struct backlight_c snprintf(backlight_name, BL_NAME_SIZE, "nv_backlight%d", nb); else snprintf(backlight_name, BL_NAME_SIZE, "nv_backlight"); - connector->id = nb; + bl->id = nb; return true; } static int nv40_get_intensity(struct backlight_device *bd) { - struct nouveau_drm *drm = bl_get_data(bd); + 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 = (nvif_rd32(device, NV40_PMC_BACKLIGHT) & - NV40_PMC_BACKLIGHT_MASK) >> 16; + NV40_PMC_BACKLIGHT_MASK) >> 16; return val; } @@ -75,13 +77,14 @@ nv40_get_intensity(struct backlight_device *bd) static int nv40_set_intensity(struct backlight_device *bd) { - struct nouveau_drm *drm = bl_get_data(bd); + 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, - (val << 16) | (reg & ~NV40_PMC_BACKLIGHT_MASK)); + (val << 16) | (reg & ~NV40_PMC_BACKLIGHT_MASK)); return 0; } @@ -93,38 +96,19 @@ static const struct backlight_ops nv40_bl_ops = { }; static int -nv40_backlight_init(struct drm_connector *connector) +nv40_backlight_init(struct nouveau_encoder *encoder, + struct backlight_properties *props, + const struct backlight_ops **ops) { - struct nouveau_drm *drm = nouveau_drm(connector->dev); + struct nouveau_drm *drm = nouveau_drm(encoder->base.base.dev); struct nvif_object *device = &drm->client.device.object; - struct backlight_properties props; - struct backlight_device *bd; - struct backlight_connector bl_connector; - char backlight_name[BL_NAME_SIZE]; if (!(nvif_rd32(device, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK)) - return 0; - - memset(&props, 0, sizeof(struct backlight_properties)); - props.type = BACKLIGHT_RAW; - props.max_brightness = 31; - if (!nouveau_get_backlight_name(backlight_name, &bl_connector)) { - NV_ERROR(drm, "Failed to retrieve a unique name for the backlight interface\n"); - return 0; - } - bd = backlight_device_register(backlight_name , connector->kdev, drm, - &nv40_bl_ops, &props); - - if (IS_ERR(bd)) { - if (bl_connector.id > 0) - ida_simple_remove(&bl_ida, bl_connector.id); - return PTR_ERR(bd); - } - list_add(&bl_connector.head, &drm->bl_connectors); - drm->backlight = bd; - bd->props.brightness = nv40_get_intensity(bd); - backlight_update_status(bd); + return -ENODEV; + props->type = BACKLIGHT_RAW; + props->max_brightness = 31; + *ops = &nv40_bl_ops; return 0; } @@ -154,7 +138,7 @@ nv50_set_intensity(struct backlight_device *bd) u32 val = (bd->props.brightness * div) / 100; nvif_wr32(device, NV50_PDISP_SOR_PWM_CTL(or), - NV50_PDISP_SOR_PWM_CTL_NEW | val); + NV50_PDISP_SOR_PWM_CTL_NEW | val); return 0; } @@ -194,9 +178,10 @@ nva3_set_intensity(struct backlight_device *bd) div = nvif_rd32(device, NV50_PDISP_SOR_PWM_DIV(or)); val = (bd->props.brightness * div) / 100; if (div) { - nvif_wr32(device, NV50_PDISP_SOR_PWM_CTL(or), val | - NV50_PDISP_SOR_PWM_CTL_NEW | - NVA3_PDISP_SOR_PWM_CTL_UNK); + nvif_wr32(device, NV50_PDISP_SOR_PWM_CTL(or), + val | + NV50_PDISP_SOR_PWM_CTL_NEW | + NVA3_PDISP_SOR_PWM_CTL_UNK); return 0; } @@ -210,110 +195,119 @@ static const struct backlight_ops nva3_bl_ops = { }; static int -nv50_backlight_init(struct drm_connector *connector) +nv50_backlight_init(struct nouveau_encoder *nv_encoder, + struct backlight_properties *props, + const struct backlight_ops **ops) { - struct nouveau_drm *drm = nouveau_drm(connector->dev); + struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); struct nvif_object *device = &drm->client.device.object; - struct nouveau_encoder *nv_encoder; - struct backlight_properties props; - struct backlight_device *bd; - const struct backlight_ops *ops; - struct backlight_connector bl_connector; - char backlight_name[BL_NAME_SIZE]; - - nv_encoder = find_encoder(connector, DCB_OUTPUT_LVDS); - if (!nv_encoder) { - nv_encoder = find_encoder(connector, DCB_OUTPUT_DP); - if (!nv_encoder) - return -ENODEV; - } if (!nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(ffs(nv_encoder->dcb->or) - 1))) - return 0; + return -ENODEV; if (drm->client.device.info.chipset <= 0xa0 || drm->client.device.info.chipset == 0xaa || drm->client.device.info.chipset == 0xac) - ops = &nv50_bl_ops; + *ops = &nv50_bl_ops; else - ops = &nva3_bl_ops; - - memset(&props, 0, sizeof(struct backlight_properties)); - props.type = BACKLIGHT_RAW; - props.max_brightness = 100; - if (!nouveau_get_backlight_name(backlight_name, &bl_connector)) { - NV_ERROR(drm, "Failed to retrieve a unique name for the backlight interface\n"); - return 0; - } - bd = backlight_device_register(backlight_name , connector->kdev, - nv_encoder, ops, &props); + *ops = &nva3_bl_ops; - if (IS_ERR(bd)) { - if (bl_connector.id > 0) - ida_simple_remove(&bl_ida, bl_connector.id); - return PTR_ERR(bd); - } + props->type = BACKLIGHT_RAW; + props->max_brightness = 100; - list_add(&bl_connector.head, &drm->bl_connectors); - drm->backlight = bd; - bd->props.brightness = bd->ops->get_brightness(bd); - backlight_update_status(bd); return 0; } int -nouveau_backlight_init(struct drm_device *dev) +nouveau_backlight_init(struct drm_connector *connector) { - struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_drm *drm = nouveau_drm(connector->dev); + struct nouveau_backlight *bl; + struct nouveau_encoder *nv_encoder = NULL; struct nvif_device *device = &drm->client.device; - struct drm_connector *connector; - struct drm_connector_list_iter conn_iter; - - INIT_LIST_HEAD(&drm->bl_connectors); + char backlight_name[BL_NAME_SIZE]; + struct backlight_properties props = {0}; + const struct backlight_ops *ops; + int ret; if (apple_gmux_present()) { - NV_INFO(drm, "Apple GMUX detected: not registering Nouveau backlight interface\n"); + NV_INFO_ONCE(drm, "Apple GMUX detected: not registering Nouveau backlight interface\n"); return 0; } - drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { - if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && - connector->connector_type != DRM_MODE_CONNECTOR_eDP) - continue; - - switch (device->info.family) { - case NV_DEVICE_INFO_V0_CURIE: - return nv40_backlight_init(connector); - case NV_DEVICE_INFO_V0_TESLA: - case NV_DEVICE_INFO_V0_FERMI: - case NV_DEVICE_INFO_V0_KEPLER: - case NV_DEVICE_INFO_V0_MAXWELL: - return nv50_backlight_init(connector); - default: - break; - } + if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) + nv_encoder = find_encoder(connector, DCB_OUTPUT_LVDS); + else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) + nv_encoder = find_encoder(connector, DCB_OUTPUT_DP); + else + return 0; + + if (!nv_encoder) + return 0; + + switch (device->info.family) { + case NV_DEVICE_INFO_V0_CURIE: + ret = nv40_backlight_init(nv_encoder, &props, &ops); + break; + case NV_DEVICE_INFO_V0_TESLA: + case NV_DEVICE_INFO_V0_FERMI: + case NV_DEVICE_INFO_V0_KEPLER: + case NV_DEVICE_INFO_V0_MAXWELL: + ret = nv50_backlight_init(nv_encoder, &props, &ops); + break; + default: + return 0; } - drm_connector_list_iter_end(&conn_iter); + + if (ret == -ENODEV) + return 0; + else if (ret) + return ret; + + bl = kzalloc(sizeof(*bl), GFP_KERNEL); + if (!bl) + return -ENOMEM; + + 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_simple_remove(&bl_ida, bl->id); + ret = PTR_ERR(bl->dev); + goto fail_alloc; + } + + nouveau_connector(connector)->backlight = bl; + bl->dev->props.brightness = bl->dev->ops->get_brightness(bl->dev); + backlight_update_status(bl->dev); return 0; + +fail_alloc: + kfree(bl); + return ret; } void -nouveau_backlight_exit(struct drm_device *dev) +nouveau_backlight_fini(struct drm_connector *connector) { - struct nouveau_drm *drm = nouveau_drm(dev); - struct backlight_connector *connector; + struct nouveau_connector *nv_conn = nouveau_connector(connector); + struct nouveau_backlight *bl = nv_conn->backlight; - list_for_each_entry(connector, &drm->bl_connectors, head) { - if (connector->id >= 0) - ida_simple_remove(&bl_ida, connector->id); - } + if (!bl) + return; - if (drm->backlight) { - backlight_device_unregister(drm->backlight); - drm->backlight = NULL; - } + if (bl->id >= 0) + ida_simple_remove(&bl_ida, bl->id); + + backlight_device_unregister(bl->dev); + nv_conn->backlight = NULL; + kfree(bl); } void |