xref: /openbsd-src/sys/dev/pci/drm/apple/dcp_backlight.c (revision 44a5d259eb2e2c1d2059a3a6540874f61a82e453)
15dd0baa8Skettenis // SPDX-License-Identifier: GPL-2.0-only OR MIT
25dd0baa8Skettenis /* Copyright (C) The Asahi Linux Contributors */
35dd0baa8Skettenis 
45dd0baa8Skettenis #include <drm/drm_atomic.h>
55dd0baa8Skettenis #include <drm/drm_crtc.h>
65dd0baa8Skettenis #include <drm/drm_drv.h>
75dd0baa8Skettenis #include <drm/drm_modeset_lock.h>
85dd0baa8Skettenis 
95dd0baa8Skettenis #include <linux/backlight.h>
105dd0baa8Skettenis #include <linux/completion.h>
115dd0baa8Skettenis #include <linux/delay.h>
125dd0baa8Skettenis #include "linux/jiffies.h"
135dd0baa8Skettenis 
145dd0baa8Skettenis #include "dcp.h"
155dd0baa8Skettenis #include "dcp-internal.h"
165dd0baa8Skettenis 
175dd0baa8Skettenis #define MIN_BRIGHTNESS_PART1	2U
185dd0baa8Skettenis #define MAX_BRIGHTNESS_PART1	99U
195dd0baa8Skettenis #define MIN_BRIGHTNESS_PART2	103U
205dd0baa8Skettenis #define MAX_BRIGHTNESS_PART2	510U
215dd0baa8Skettenis 
225dd0baa8Skettenis /*
235dd0baa8Skettenis  * lookup for display brightness 2 to 99 nits
245dd0baa8Skettenis  * */
255dd0baa8Skettenis static u32 brightness_part1[] = {
265dd0baa8Skettenis 	0x0000000, 0x0810038, 0x0f000bd, 0x143011c,
275dd0baa8Skettenis 	0x1850165, 0x1bc01a1, 0x1eb01d4, 0x2140200,
285dd0baa8Skettenis 	0x2380227, 0x2590249, 0x2770269, 0x2930285,
295dd0baa8Skettenis 	0x2ac02a0, 0x2c402b8, 0x2d902cf, 0x2ee02e4,
305dd0baa8Skettenis 	0x30102f8, 0x314030b, 0x325031c, 0x335032d,
315dd0baa8Skettenis 	0x345033d, 0x354034d, 0x362035b, 0x3700369,
325dd0baa8Skettenis 	0x37d0377, 0x38a0384, 0x3960390, 0x3a2039c,
335dd0baa8Skettenis 	0x3ad03a7, 0x3b803b3, 0x3c303bd, 0x3cd03c8,
345dd0baa8Skettenis 	0x3d703d2, 0x3e103dc, 0x3ea03e5, 0x3f303ef,
355dd0baa8Skettenis 	0x3fc03f8, 0x4050400, 0x40d0409, 0x4150411,
365dd0baa8Skettenis 	0x41d0419, 0x4250421, 0x42d0429, 0x4340431,
375dd0baa8Skettenis 	0x43c0438, 0x443043f, 0x44a0446, 0x451044d,
385dd0baa8Skettenis 	0x4570454, 0x45e045b, 0x4640461, 0x46b0468,
395dd0baa8Skettenis 	0x471046e, 0x4770474, 0x47d047a, 0x4830480,
405dd0baa8Skettenis 	0x4890486, 0x48e048b, 0x4940491, 0x4990497,
415dd0baa8Skettenis 	0x49f049c, 0x4a404a1, 0x4a904a7, 0x4ae04ac,
425dd0baa8Skettenis 	0x4b304b1, 0x4b804b6, 0x4bd04bb, 0x4c204c0,
435dd0baa8Skettenis 	0x4c704c5, 0x4cc04c9, 0x4d004ce, 0x4d504d3,
445dd0baa8Skettenis 	0x4d904d7, 0x4de04dc, 0x4e204e0, 0x4e704e4,
455dd0baa8Skettenis 	0x4eb04e9, 0x4ef04ed, 0x4f304f1, 0x4f704f5,
465dd0baa8Skettenis 	0x4fb04f9, 0x4ff04fd, 0x5030501, 0x5070505,
475dd0baa8Skettenis 	0x50b0509, 0x50f050d, 0x5130511, 0x5160515,
485dd0baa8Skettenis 	0x51a0518, 0x51e051c, 0x5210520, 0x5250523,
495dd0baa8Skettenis 	0x5290527, 0x52c052a, 0x52f052e, 0x5330531,
505dd0baa8Skettenis 	0x5360535, 0x53a0538, 0x53d053b, 0x540053f,
515dd0baa8Skettenis 	0x5440542, 0x5470545, 0x54a0548, 0x54d054c,
525dd0baa8Skettenis 	0x550054f, 0x5530552, 0x5560555, 0x5590558,
535dd0baa8Skettenis 	0x55c055b, 0x55f055e, 0x5620561, 0x5650564,
545dd0baa8Skettenis 	0x5680567, 0x56b056a, 0x56e056d, 0x571056f,
555dd0baa8Skettenis 	0x5740572, 0x5760575, 0x5790578, 0x57c057b,
565dd0baa8Skettenis 	0x57f057d, 0x5810580, 0x5840583, 0x5870585,
575dd0baa8Skettenis 	0x5890588, 0x58c058b, 0x58f058d
585dd0baa8Skettenis };
595dd0baa8Skettenis 
605dd0baa8Skettenis static u32 brightness_part12[] = { 0x58f058d, 0x59d058f };
615dd0baa8Skettenis 
625dd0baa8Skettenis /*
635dd0baa8Skettenis  * lookup table for display brightness 103.3 to 510 nits
645dd0baa8Skettenis  * */
655dd0baa8Skettenis static u32 brightness_part2[] = {
665dd0baa8Skettenis 	0x59d058f, 0x5b805ab, 0x5d105c5, 0x5e805dd,
675dd0baa8Skettenis 	0x5fe05f3, 0x6120608, 0x625061c, 0x637062e,
685dd0baa8Skettenis 	0x6480640, 0x6580650, 0x6680660, 0x677066f,
695dd0baa8Skettenis 	0x685067e, 0x693068c, 0x6a00699, 0x6ac06a6,
705dd0baa8Skettenis 	0x6b806b2, 0x6c406be, 0x6cf06ca, 0x6da06d5,
715dd0baa8Skettenis 	0x6e506df, 0x6ef06ea, 0x6f906f4, 0x70206fe,
725dd0baa8Skettenis 	0x70c0707, 0x7150710, 0x71e0719, 0x7260722,
735dd0baa8Skettenis 	0x72f072a, 0x7370733, 0x73f073b, 0x7470743,
745dd0baa8Skettenis 	0x74e074a, 0x7560752, 0x75d0759, 0x7640760,
755dd0baa8Skettenis 	0x76b0768, 0x772076e, 0x7780775, 0x77f077c,
765dd0baa8Skettenis 	0x7850782, 0x78c0789, 0x792078f, 0x7980795,
775dd0baa8Skettenis 	0x79e079b, 0x7a407a1, 0x7aa07a7, 0x7af07ac,
785dd0baa8Skettenis 	0x7b507b2, 0x7ba07b8, 0x7c007bd, 0x7c507c2,
795dd0baa8Skettenis 	0x7ca07c8, 0x7cf07cd, 0x7d407d2, 0x7d907d7,
805dd0baa8Skettenis 	0x7de07dc, 0x7e307e1, 0x7e807e5, 0x7ec07ea,
815dd0baa8Skettenis 	0x7f107ef, 0x7f607f3, 0x7fa07f8, 0x7fe07fc
825dd0baa8Skettenis };
835dd0baa8Skettenis 
845dd0baa8Skettenis 
dcp_get_brightness(struct backlight_device * bd)855dd0baa8Skettenis static int dcp_get_brightness(struct backlight_device *bd)
865dd0baa8Skettenis {
875dd0baa8Skettenis 	struct apple_dcp *dcp = bl_get_data(bd);
885dd0baa8Skettenis 
895dd0baa8Skettenis 	return dcp->brightness.nits;
905dd0baa8Skettenis }
915dd0baa8Skettenis 
925dd0baa8Skettenis #define SCALE_FACTOR (1 << 10)
935dd0baa8Skettenis 
interpolate(int val,int min,int max,u32 * tbl,size_t tbl_size)945dd0baa8Skettenis static u32 interpolate(int val, int min, int max, u32 *tbl, size_t tbl_size)
955dd0baa8Skettenis {
965dd0baa8Skettenis 	u32 frac;
975dd0baa8Skettenis 	u64 low, high;
985dd0baa8Skettenis 	u32 interpolated = (tbl_size - 1) * ((val - min) * SCALE_FACTOR) / (max - min);
995dd0baa8Skettenis 
1005dd0baa8Skettenis 	size_t index = interpolated / SCALE_FACTOR;
1015dd0baa8Skettenis 
102*44a5d259Skettenis 	if (WARN(index + 1 >= tbl_size, "invalid index %zu for brightness %u\n", index, val))
1035dd0baa8Skettenis 		return tbl[tbl_size / 2];
1045dd0baa8Skettenis 
1055dd0baa8Skettenis 	frac = interpolated & (SCALE_FACTOR - 1);
1065dd0baa8Skettenis 	low = tbl[index];
1075dd0baa8Skettenis 	high = tbl[index + 1];
1085dd0baa8Skettenis 
1095dd0baa8Skettenis 	return ((frac * high) + ((SCALE_FACTOR - frac) * low)) / SCALE_FACTOR;
1105dd0baa8Skettenis }
1115dd0baa8Skettenis 
calculate_dac(struct apple_dcp * dcp,int val)1125dd0baa8Skettenis static u32 calculate_dac(struct apple_dcp *dcp, int val)
1135dd0baa8Skettenis {
1145dd0baa8Skettenis 	u32 dac;
1155dd0baa8Skettenis 
1165dd0baa8Skettenis 	if (val <= MIN_BRIGHTNESS_PART1)
1175dd0baa8Skettenis 		return 16 * brightness_part1[0];
1185dd0baa8Skettenis 	else if (val == MAX_BRIGHTNESS_PART1)
1195dd0baa8Skettenis 		return 16 * brightness_part1[ARRAY_SIZE(brightness_part1) - 1];
1205dd0baa8Skettenis 	else if (val == MIN_BRIGHTNESS_PART2)
1215dd0baa8Skettenis 		return 16 * brightness_part2[0];
1225dd0baa8Skettenis 	else if (val >= MAX_BRIGHTNESS_PART2)
1235dd0baa8Skettenis 		return brightness_part2[ARRAY_SIZE(brightness_part2) - 1];
1245dd0baa8Skettenis 
1255dd0baa8Skettenis 	if (val < MAX_BRIGHTNESS_PART1) {
1265dd0baa8Skettenis 		dac = interpolate(val, MIN_BRIGHTNESS_PART1, MAX_BRIGHTNESS_PART1,
1275dd0baa8Skettenis 				  brightness_part1, ARRAY_SIZE(brightness_part1));
1285dd0baa8Skettenis 	} else if (val > MIN_BRIGHTNESS_PART2) {
1295dd0baa8Skettenis 		dac = interpolate(val, MIN_BRIGHTNESS_PART2, MAX_BRIGHTNESS_PART2,
1305dd0baa8Skettenis 				  brightness_part2, ARRAY_SIZE(brightness_part2));
1315dd0baa8Skettenis 	} else {
1325dd0baa8Skettenis 		dac = interpolate(val, MAX_BRIGHTNESS_PART1, MIN_BRIGHTNESS_PART2,
1335dd0baa8Skettenis 				  brightness_part12, ARRAY_SIZE(brightness_part12));
1345dd0baa8Skettenis 	}
1355dd0baa8Skettenis 
1365dd0baa8Skettenis 	return 16 * dac;
1375dd0baa8Skettenis }
1385dd0baa8Skettenis 
drm_crtc_set_brightness(struct apple_dcp * dcp)1395dd0baa8Skettenis static int drm_crtc_set_brightness(struct apple_dcp *dcp)
1405dd0baa8Skettenis {
1415dd0baa8Skettenis 	struct drm_atomic_state *state;
1425dd0baa8Skettenis 	struct drm_crtc_state *crtc_state;
1435dd0baa8Skettenis 	struct drm_modeset_acquire_ctx ctx;
1445dd0baa8Skettenis 	struct drm_crtc *crtc = &dcp->crtc->base;
1455dd0baa8Skettenis 	int ret = 0;
1465dd0baa8Skettenis 
1475dd0baa8Skettenis 	DRM_MODESET_LOCK_ALL_BEGIN(crtc->dev, ctx, 0, ret);
1485dd0baa8Skettenis 
1495dd0baa8Skettenis 	if (!dcp->brightness.update)
1505dd0baa8Skettenis 		goto done;
1515dd0baa8Skettenis 
1525dd0baa8Skettenis 	state = drm_atomic_state_alloc(crtc->dev);
1535dd0baa8Skettenis 	if (!state)
1545dd0baa8Skettenis 		return -ENOMEM;
1555dd0baa8Skettenis 
1565dd0baa8Skettenis 	state->acquire_ctx = &ctx;
1575dd0baa8Skettenis 	crtc_state = drm_atomic_get_crtc_state(state, crtc);
1585dd0baa8Skettenis 	if (IS_ERR(crtc_state)) {
1595dd0baa8Skettenis 		ret = PTR_ERR(crtc_state);
1605dd0baa8Skettenis 		goto fail;
1615dd0baa8Skettenis 	}
1625dd0baa8Skettenis 
1635dd0baa8Skettenis 	crtc_state->color_mgmt_changed |= true;
1645dd0baa8Skettenis 
1655dd0baa8Skettenis 	ret = drm_atomic_commit(state);
1665dd0baa8Skettenis 
1675dd0baa8Skettenis fail:
1685dd0baa8Skettenis 	drm_atomic_state_put(state);
1695dd0baa8Skettenis done:
1705dd0baa8Skettenis 	DRM_MODESET_LOCK_ALL_END(crtc->dev, ctx, ret);
1715dd0baa8Skettenis 
1725dd0baa8Skettenis 	return ret;
1735dd0baa8Skettenis }
1745dd0baa8Skettenis 
dcp_backlight_update(struct apple_dcp * dcp)17548fd60f3Skettenis int dcp_backlight_update(struct apple_dcp *dcp)
1765dd0baa8Skettenis {
1775dd0baa8Skettenis 	/*
1785dd0baa8Skettenis 	 * Do not actively try to change brightness if no mode is set.
1795dd0baa8Skettenis 	 * TODO: should this be reflected the in backlight's power property?
1805dd0baa8Skettenis 	 *       defer this hopefully until it becomes irrelevant due to proper
1815dd0baa8Skettenis 	 *       drm integrated backlight handling
1825dd0baa8Skettenis 	 */
1835dd0baa8Skettenis 	if (!dcp->valid_mode)
1845dd0baa8Skettenis 		return 0;
1855dd0baa8Skettenis 
1865dd0baa8Skettenis 	/* Wait 1 vblank cycle in the hope an atomic swap has already updated
1875dd0baa8Skettenis 	 * the brightness */
1885dd0baa8Skettenis 	drm_msleep((1001 + 23) / 24); // 42ms for 23.976 fps
1895dd0baa8Skettenis 
1905dd0baa8Skettenis 	return drm_crtc_set_brightness(dcp);
1915dd0baa8Skettenis }
1925dd0baa8Skettenis 
dcp_set_brightness(struct backlight_device * bd)19348fd60f3Skettenis static int dcp_set_brightness(struct backlight_device *bd)
19448fd60f3Skettenis {
19548fd60f3Skettenis 	int ret = 0;
19648fd60f3Skettenis 	struct apple_dcp *dcp = bl_get_data(bd);
19748fd60f3Skettenis 	struct drm_modeset_acquire_ctx ctx;
19848fd60f3Skettenis 	int brightness = backlight_get_brightness(bd);
19948fd60f3Skettenis 
20048fd60f3Skettenis 	DRM_MODESET_LOCK_ALL_BEGIN(dcp->crtc->base.dev, ctx, 0, ret);
20148fd60f3Skettenis 
20248fd60f3Skettenis 	dcp->brightness.dac = calculate_dac(dcp, brightness);
20348fd60f3Skettenis 	dcp->brightness.update = true;
20448fd60f3Skettenis 
20548fd60f3Skettenis 	DRM_MODESET_LOCK_ALL_END(dcp->crtc->base.dev, ctx, ret);
20648fd60f3Skettenis 
20748fd60f3Skettenis 	return dcp_backlight_update(dcp);
20848fd60f3Skettenis }
20948fd60f3Skettenis 
2105dd0baa8Skettenis static const struct backlight_ops dcp_backlight_ops = {
2115dd0baa8Skettenis 	.options = BL_CORE_SUSPENDRESUME,
2125dd0baa8Skettenis 	.get_brightness = dcp_get_brightness,
2135dd0baa8Skettenis 	.update_status = dcp_set_brightness,
2145dd0baa8Skettenis };
2155dd0baa8Skettenis 
dcp_backlight_register(struct apple_dcp * dcp)2165dd0baa8Skettenis int dcp_backlight_register(struct apple_dcp *dcp)
2175dd0baa8Skettenis {
2185dd0baa8Skettenis 	struct device *dev = dcp->dev;
2195dd0baa8Skettenis 	struct backlight_device *bl_dev;
2205dd0baa8Skettenis 	struct backlight_properties props = {
2215dd0baa8Skettenis 		.type = BACKLIGHT_PLATFORM,
2225dd0baa8Skettenis 		.brightness = dcp->brightness.nits,
2235dd0baa8Skettenis 		.scale = BACKLIGHT_SCALE_LINEAR,
2245dd0baa8Skettenis 	};
2255dd0baa8Skettenis 	props.max_brightness = min(dcp->brightness.maximum, MAX_BRIGHTNESS_PART2 - 1);
2265dd0baa8Skettenis 
2275dd0baa8Skettenis 	bl_dev = devm_backlight_device_register(dev, "apple-panel-bl", dev, dcp,
2285dd0baa8Skettenis 						&dcp_backlight_ops, &props);
2295dd0baa8Skettenis 	if (IS_ERR(bl_dev))
2305dd0baa8Skettenis 		return PTR_ERR(bl_dev);
2315dd0baa8Skettenis 
2325dd0baa8Skettenis 	dcp->brightness.bl_dev = bl_dev;
2335dd0baa8Skettenis 	dcp->brightness.dac = calculate_dac(dcp, dcp->brightness.nits);
2345dd0baa8Skettenis 
2355dd0baa8Skettenis 	return 0;
2365dd0baa8Skettenis }
237