Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amd: Query and use ACPI backlight caps

ACPI ATIF has a function called query
backlight transfer characteristics. Among the
information returned by this function is
the minimum and maximum input signals for the
backlight

Call that function on ACPI init. When DM
backlight device is updated, copy over the
backlight caps into DM, but only once. Use
the backlight caps in the backlight-to-dc
calculation

Signed-off-by: David Francis <David.Francis@amd.com>
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

David Francis and committed by
Alex Deucher
206bbafe 7349a3af

+170 -12
+3
drivers/gpu/drm/amd/amdgpu/amdgpu.h
··· 1252 1252 int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev, 1253 1253 u8 perf_req, bool advertise); 1254 1254 int amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device *adev); 1255 + 1256 + void amdgpu_acpi_get_backlight_caps(struct amdgpu_device *adev, 1257 + struct amdgpu_dm_backlight_caps *caps); 1255 1258 #else 1256 1259 static inline int amdgpu_acpi_init(struct amdgpu_device *adev) { return 0; } 1257 1260 static inline void amdgpu_acpi_fini(struct amdgpu_device *adev) { }
+83
drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
··· 65 65 struct amdgpu_atif_functions functions; 66 66 struct amdgpu_atif_notification_cfg notification_cfg; 67 67 struct amdgpu_encoder *encoder_for_bl; 68 + struct amdgpu_dm_backlight_caps backlight_caps; 68 69 }; 69 70 70 71 /* Call the ATIF method ··· 294 293 DRM_DEBUG_DRIVER("Notification %s, command code = %#x\n", 295 294 (n->enabled ? "enabled" : "disabled"), 296 295 n->command_code); 296 + kfree(info); 297 + return err; 298 + } 299 + 300 + /** 301 + * amdgpu_atif_query_backlight_caps - get min and max backlight input signal 302 + * 303 + * @handle: acpi handle 304 + * 305 + * Execute the QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS ATIF function 306 + * to determine the acceptable range of backlight values 307 + * 308 + * Backlight_caps.caps_valid will be set to true if the query is successful 309 + * 310 + * The input signals are in range 0-255 311 + * 312 + * This function assumes the display with backlight is the first LCD 313 + * 314 + * Returns 0 on success, error on failure. 315 + */ 316 + static int amdgpu_atif_query_backlight_caps(struct amdgpu_atif *atif) 317 + { 318 + union acpi_object *info; 319 + struct atif_qbtc_output characteristics; 320 + struct atif_qbtc_arguments arguments; 321 + struct acpi_buffer params; 322 + size_t size; 323 + int err = 0; 324 + 325 + arguments.size = sizeof(arguments); 326 + arguments.requested_display = ATIF_QBTC_REQUEST_LCD1; 327 + 328 + params.length = sizeof(arguments); 329 + params.pointer = (void *)&arguments; 330 + 331 + info = amdgpu_atif_call(atif, 332 + ATIF_FUNCTION_QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS, 333 + &params); 334 + if (!info) { 335 + err = -EIO; 336 + goto out; 337 + } 338 + 339 + size = *(u16 *) info->buffer.pointer; 340 + if (size < 10) { 341 + err = -EINVAL; 342 + goto out; 343 + } 344 + 345 + memset(&characteristics, 0, sizeof(characteristics)); 346 + size = min(sizeof(characteristics), size); 347 + memcpy(&characteristics, info->buffer.pointer, size); 348 + 349 + atif->backlight_caps.caps_valid = true; 350 + atif->backlight_caps.min_input_signal = 351 + characteristics.min_input_signal; 352 + atif->backlight_caps.max_input_signal = 353 + characteristics.max_input_signal; 354 + out: 297 355 kfree(info); 298 356 return err; 299 357 } ··· 846 786 } 847 787 } 848 788 789 + if (atif->functions.query_backlight_transfer_characteristics) { 790 + ret = amdgpu_atif_query_backlight_caps(atif); 791 + if (ret) { 792 + DRM_DEBUG_DRIVER("Call to QUERY_BACKLIGHT_TRANSFER_CHARACTERISTICS failed: %d\n", 793 + ret); 794 + atif->backlight_caps.caps_valid = false; 795 + } 796 + } else { 797 + atif->backlight_caps.caps_valid = false; 798 + } 799 + 849 800 out: 850 801 adev->acpi_nb.notifier_call = amdgpu_acpi_event; 851 802 register_acpi_notifier(&adev->acpi_nb); 852 803 853 804 return ret; 805 + } 806 + 807 + void amdgpu_acpi_get_backlight_caps(struct amdgpu_device *adev, 808 + struct amdgpu_dm_backlight_caps *caps) 809 + { 810 + if (!adev->atif) { 811 + caps->caps_valid = false; 812 + return; 813 + } 814 + caps->caps_valid = adev->atif->backlight_caps.caps_valid; 815 + caps->min_input_signal = adev->atif->backlight_caps.min_input_signal; 816 + caps->max_input_signal = adev->atif->backlight_caps.max_input_signal; 854 817 } 855 818 856 819 /**
+47 -12
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
··· 1589 1589 return 0; 1590 1590 } 1591 1591 1592 + #define AMDGPU_DM_DEFAULT_MIN_BACKLIGHT 12 1593 + #define AMDGPU_DM_DEFAULT_MAX_BACKLIGHT 255 1594 + 1592 1595 #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\ 1593 1596 defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) 1597 + 1598 + static void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm) 1599 + { 1600 + #if defined(CONFIG_ACPI) 1601 + struct amdgpu_dm_backlight_caps caps; 1602 + 1603 + if (dm->backlight_caps.caps_valid) 1604 + return; 1605 + 1606 + amdgpu_acpi_get_backlight_caps(dm->adev, &caps); 1607 + if (caps.caps_valid) { 1608 + dm->backlight_caps.min_input_signal = caps.min_input_signal; 1609 + dm->backlight_caps.max_input_signal = caps.max_input_signal; 1610 + dm->backlight_caps.caps_valid = true; 1611 + } else { 1612 + dm->backlight_caps.min_input_signal = 1613 + AMDGPU_DM_DEFAULT_MIN_BACKLIGHT; 1614 + dm->backlight_caps.max_input_signal = 1615 + AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; 1616 + } 1617 + #else 1618 + dm->backlight_min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT; 1619 + dm->backlight_max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; 1620 + #endif 1621 + } 1594 1622 1595 1623 static int amdgpu_dm_backlight_update_status(struct backlight_device *bd) 1596 1624 { 1597 1625 struct amdgpu_display_manager *dm = bl_get_data(bd); 1626 + struct amdgpu_dm_backlight_caps caps; 1627 + uint32_t brightness = bd->props.brightness; 1598 1628 1599 - /* backlight_pwm_u16_16 parameter is in unsigned 32 bit, 16 bit integer 1600 - * and 16 bit fractional, where 1.0 is max backlight value. 1601 - * bd->props.brightness is 8 bit format and needs to be converted by 1602 - * scaling via copy lower byte to upper byte of 16 bit value. 1603 - */ 1604 - uint32_t brightness = bd->props.brightness * 0x101; 1605 - 1629 + amdgpu_dm_update_backlight_caps(dm); 1630 + caps = dm->backlight_caps; 1606 1631 /* 1607 - * PWM interperts 0 as 100% rather than 0% because of HW 1608 - * limitation for level 0. So limiting minimum brightness level 1609 - * to 1. 1632 + * The brightness input is in the range 0-255 1633 + * It needs to be rescaled to be between the 1634 + * requested min and max input signal 1635 + * 1636 + * It also needs to be scaled up by 0x101 to 1637 + * match the DC interface which has a range of 1638 + * 0 to 0xffff 1610 1639 */ 1611 - if (bd->props.brightness < 1) 1612 - brightness = 0x101; 1640 + brightness = 1641 + brightness 1642 + * 0x101 1643 + * (caps.max_input_signal - caps.min_input_signal) 1644 + / AMDGPU_MAX_BL_LEVEL 1645 + + caps.min_input_signal * 0x101; 1613 1646 1614 1647 if (dc_link_set_backlight_level(dm->backlight_link, 1615 1648 brightness, 0, 0)) ··· 1671 1638 { 1672 1639 char bl_name[16]; 1673 1640 struct backlight_properties props = { 0 }; 1641 + 1642 + amdgpu_dm_update_backlight_caps(dm); 1674 1643 1675 1644 props.max_brightness = AMDGPU_MAX_BL_LEVEL; 1676 1645 props.brightness = AMDGPU_MAX_BL_LEVEL;
+13
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
··· 84 84 }; 85 85 86 86 /** 87 + * struct amdgpu_dm_backlight_caps - Usable range of backlight values from ACPI 88 + * @min_input_signal: minimum possible input in range 0-255 89 + * @max_input_signal: maximum possible input in range 0-255 90 + * @caps_valid: true if these values are from the ACPI interface 91 + */ 92 + struct amdgpu_dm_backlight_caps { 93 + int min_input_signal; 94 + int max_input_signal; 95 + bool caps_valid; 96 + }; 97 + 98 + /** 87 99 * struct amdgpu_display_manager - Central amdgpu display manager device 88 100 * 89 101 * @dc: Display Core control structure ··· 170 158 struct backlight_device *backlight_dev; 171 159 172 160 const struct dc_link *backlight_link; 161 + struct amdgpu_dm_backlight_caps backlight_caps; 173 162 174 163 struct mod_freesync *freesync_module; 175 164
+24
drivers/gpu/drm/amd/include/amd_acpi.h
··· 52 52 u8 backlight_level; /* panel backlight level (0-255) */ 53 53 } __packed; 54 54 55 + struct atif_qbtc_arguments { 56 + u16 size; /* structure size in bytes (includes size field) */ 57 + u8 requested_display; /* which display is requested */ 58 + } __packed; 59 + 60 + #define ATIF_QBTC_MAX_DATA_POINTS 99 61 + 62 + struct atif_qbtc_data_point { 63 + u8 luminance; /* luminance in percent */ 64 + u8 ipnut_signal; /* input signal in range 0-255 */ 65 + } __packed; 66 + 67 + struct atif_qbtc_output { 68 + u16 size; /* structure size in bytes (includes size field) */ 69 + u16 flags; /* all zeroes */ 70 + u8 error_code; /* error code */ 71 + u8 ac_level; /* default brightness on AC power */ 72 + u8 dc_level; /* default brightness on DC power */ 73 + u8 min_input_signal; /* max input signal in range 0-255 */ 74 + u8 max_input_signal; /* min input signal in range 0-255 */ 75 + u8 number_of_points; /* number of data points */ 76 + struct atif_qbtc_data_point data_points[ATIF_QBTC_MAX_DATA_POINTS]; 77 + } __packed; 78 + 55 79 #define ATIF_NOTIFY_MASK 0x3 56 80 #define ATIF_NOTIFY_NONE 0 57 81 #define ATIF_NOTIFY_81 1