compat: lower the eDP backlight floor and map nits linearly

The monitor's floor was 10% of full scale (level 205 of 2047) and the
kext's helpers mapped [min_nits, max_nits] affinely onto [floor, max].
If the panel's DPCD level is linear in luminance, the darkest macOS
request was ~50 nits: ten times the 5-nit minimum the A16's panel
table gives Windows (BrightnessRangeLevel0 5000..500000 millinits,
BrightnessRangeLowOffset 10000).

EDP_BL_FLOOR_PERMILLE is now 20: level 41, ~10 nits under the linear
model (the table's low offset), very dark but never off if the TCON
applied a 2.2 power law instead. Nothing has measured the panel's
curve; the header says so and the hardware run must check the bottom
of the slider. The helpers now model luminance proportional to level
(edp_bl_nits_to_level/edp_bl_level_to_nits with the top level at
max_nits) and edp_bl_min_nits_q16 raises the darkest request to the
floor's luminance; the slider helpers take 16.16 bounds.

The SNAP_EDP_BACKLIGHT=1 monitor built with run next1b's flags differs
from next1b's qualified one in one byte (same size, 200 bytes of code
budget left); without the define the monitor is byte-identical. The
model test checks the floor and the curve, and four new mutations (no
floor change back to 10%, an affine curve, a top short of max, a
minimum below the floor) must fail it.

The SnapAdreno kext with ADRENO_BACKLIGHT uses the new signatures; it
builds once the submodule pointer moves (next commit). The default
kext does not include this header.
This commit is contained in:
Acelogic committed 2026-10-24 19:46:34 -04:00
1 parent 67013604d7
commit b8e2e042f2
3 files changed
+121 -61

No files matched your search

+46 -31
View File
@@ -68,14 +68,25 @@
#define DPCD_EDP_PWMGEN_BITS_MASK 0x1Fu
/* ---- Policy ------------------------------------------------------------------------------------------------------ */
/* The lowest level the monitor writes, in thousandths of full scale (at least level 1). An OLED's DPCD level need
* not be linear in luminance: until a hardware run measures the curve, 10% keeps the panel visibly lit even if the
* TCON applies a 2.2 gamma (about 0.6% of peak). The guest cannot lower it; the top is the panel's own maximum. */
#define EDP_BL_FLOOR_PERMILLE 100u
/* The lowest level the monitor writes, in thousandths of full scale (at least level 1); the guest cannot go below it
* and the top is the panel's own maximum. What is known (run next1b and the A16 DSDT, AGENTS.md labels):
* - OBSERVED: 11-bit levels 0..2047; the firmware/Windows left level 716 (35% of full scale).
* - VERIFIED: the DSDT panel table for 0x834C/0x422C names it "Generic OLED Panel HDR" and gives Windows' nits-based
* brightness BrightnessRangeLevel0 "5000 500000 1000 2" and BrightnessRangeLowOffset 10000 (INFERRED: millinits,
* so 5..500 nits with a 10-nit low offset).
* - Nothing measures the panel's luminance per level. If it is linear in luminance (INFERRED: the table describes
* the panel to Windows only by a nits range; edp_bl_nits_to_level uses this model), the previous 10% floor
* (level 205) was ~50 nits, ten times Windows' minimum, so the bottom of the macOS slider could not be dim.
* 2% is level 41 on this panel: ~10 nits under the linear model, the table's low offset and twice Windows' minimum,
* so the bottom of the slider is dim but readable. If the TCON instead followed a 2.2 power law it would be ~0.02% of
* peak (very dark, never off); the hardware run must look at the bottom of the slider before this is relied on, and
* the kext's boot-arg adreno_backlight_min_nits raises the darkest request without rebuilding the monitor. */
#define EDP_BL_FLOOR_PERMILLE 20u
#define EDP_BL_MAX_FAILURES 3u /* consecutive failed SETs before the monitor stops for the boot */
#define EDP_BL_AUX_BUDGET_DIV 200u /* one transaction's completion budget: hz / 200 = 5 ms */
/* The kext's nominal range for CoreBrightness, from the panel table's millinit range (INFERRED); boot-args may
* narrow it within [EDP_BL_NITS_LIMIT_MIN, EDP_BL_NITS_LIMIT_MAX]. */
/* The kext's nominal range for CoreBrightness, from the panel table's millinit range (INFERRED). MAX is the luminance
* the model assigns to the top level; MIN is the darkest request, raised to the floor's luminance when below it.
* Boot-args adreno_backlight_min_nits / _max_nits may set either within [EDP_BL_NITS_LIMIT_MIN, EDP_BL_NITS_LIMIT_MAX]. */
#define EDP_BL_NITS_MIN_DEFAULT 5u
#define EDP_BL_NITS_MAX_DEFAULT 500u
#define EDP_BL_NITS_LIMIT_MIN 1u
@@ -184,39 +195,43 @@ static inline uint32_t edp_bl_decode(const uint8_t in[2], int lsb)
return lsb ? (uint32_t)in[0] << 8 | in[1] : in[0];
}
/* Nits (16.16 fixed point, as CoreBrightness's "brightness-nits") to a level: linear from [min_nits, max_nits] onto
* [floor, max], clamped at both ends. The panel's luminance curve is not known (INFERRED linear); the floor holds
* whatever is asked. */
static inline uint32_t edp_bl_nits_to_level(uint64_t nits_q16, uint32_t min_nits, uint32_t max_nits,
uint32_t floor, uint32_t max)
/* The luminance model the kext maps CoreBrightness's requests with: luminance proportional to the level, the top
* level being max_nits (INFERRED, see EDP_BL_FLOOR_PERMILLE). Nits are 16.16 fixed point throughout, the unit of
* BrightnessControl's "brightness-nits". A request maps to the nearest level, clamped into [floor, max]: the bottom
* of the slider lands on (or near) the floor and the top on the panel's maximum. Callers keep max_nits within
* EDP_BL_NITS_LIMIT_MAX and max within 16 bits, so no product below exceeds 2^42. */
static inline uint32_t edp_bl_nits_to_level(uint64_t nits_q16, uint32_t max_nits, uint32_t floor, uint32_t max)
{
uint64_t lo = (uint64_t)min_nits << 16, hi = (uint64_t)max_nits << 16;
if (hi <= lo || max <= floor) return floor;
if (nits_q16 <= lo) return floor;
if (nits_q16 >= hi) return max;
return floor + (uint32_t)(((nits_q16 - lo) * (max - floor) + (hi - lo) / 2) / (hi - lo));
uint64_t full = (uint64_t)max_nits << 16;
if (!full || max <= floor) return floor;
if (nits_q16 >= full) return max;
return edp_bl_clamp((nits_q16 * max + full / 2) / full, floor, max);
}
static inline uint64_t edp_bl_level_to_nits(uint32_t level, uint32_t min_nits, uint32_t max_nits,
uint32_t floor, uint32_t max)
/* A level's luminance under the same model (levels above max count as max). */
static inline uint64_t edp_bl_level_to_nits(uint32_t level, uint32_t max_nits, uint32_t max)
{
uint64_t lo = (uint64_t)min_nits << 16, hi = (uint64_t)max_nits << 16;
if (hi <= lo || max <= floor || level <= floor) return lo;
if (level >= max) return hi;
return lo + ((uint64_t)(level - floor) * (hi - lo) + (max - floor) / 2) / (max - floor);
if (!max) return 0;
if (level > max) level = max;
return ((uint64_t)level * ((uint64_t)max_nits << 16) + max / 2) / max;
}
/* IODisplayParameters "brightness" (0..EDP_BL_SLIDER_MAX) as nits, linear between the nominal ends. */
static inline uint64_t edp_bl_slider_to_nits(uint64_t slider, uint32_t min_nits, uint32_t max_nits)
/* The darkest luminance the kext offers CoreBrightness (BrightnessMilliNits "min"): the configured minimum, raised to
* the floor's luminance, since nothing below the floor can be shown. */
static inline uint64_t edp_bl_min_nits_q16(uint32_t min_nits, uint32_t max_nits, uint32_t floor, uint32_t max)
{
uint64_t at_floor = edp_bl_level_to_nits(floor, max_nits, max), configured = (uint64_t)min_nits << 16;
return configured > at_floor ? configured : at_floor;
}
/* IODisplayParameters "brightness" (0..EDP_BL_SLIDER_MAX) as nits, linear between lo and hi (16.16), and back. */
static inline uint64_t edp_bl_slider_to_nits(uint64_t slider, uint64_t lo_q16, uint64_t hi_q16)
{
uint64_t lo = (uint64_t)min_nits << 16, hi = (uint64_t)max_nits << 16;
if (slider > EDP_BL_SLIDER_MAX) slider = EDP_BL_SLIDER_MAX;
return hi <= lo ? lo : lo + ((hi - lo) * slider + EDP_BL_SLIDER_MAX / 2) / EDP_BL_SLIDER_MAX;
return hi_q16 <= lo_q16 ? lo_q16 : lo_q16 + ((hi_q16 - lo_q16) * slider + EDP_BL_SLIDER_MAX / 2) / EDP_BL_SLIDER_MAX;
}
static inline uint32_t edp_bl_nits_to_slider(uint64_t nits_q16, uint32_t min_nits, uint32_t max_nits)
static inline uint32_t edp_bl_nits_to_slider(uint64_t nits_q16, uint64_t lo_q16, uint64_t hi_q16)
{
uint64_t lo = (uint64_t)min_nits << 16, hi = (uint64_t)max_nits << 16;
if (hi <= lo || nits_q16 <= lo) return 0;
if (nits_q16 >= hi) return EDP_BL_SLIDER_MAX;
return (uint32_t)(((nits_q16 - lo) * EDP_BL_SLIDER_MAX + (hi - lo) / 2) / (hi - lo));
if (hi_q16 <= lo_q16 || nits_q16 <= lo_q16) return 0;
if (nits_q16 >= hi_q16) return EDP_BL_SLIDER_MAX;
return (uint32_t)(((nits_q16 - lo_q16) * EDP_BL_SLIDER_MAX + (hi_q16 - lo_q16) / 2) / (hi_q16 - lo_q16));
}
/* ---- Allow-lists: every MMIO access and every DPCD transaction the monitor makes passes one of these ----------- */
+64 -27
View File
@@ -187,6 +187,61 @@ static uint32_t level_of(const uint64_t r[4]) { return (uint32_t)r[3]; }
static uint32_t state_of(const uint64_t r[4]) { return edp_bl_reply_state(r[1]); }
static uint32_t panel_level(void) { return (uint32_t)M.dpcd[0x722] << 8 | M.dpcd[0x723]; }
/* The kext's nits -> level curve (luminance proportional to level, the top level = max_nits), on the A16's 11-bit
* panel with the default 5..500 nits: the bottom of CoreBrightness's range is the floor, the top is the panel's
* maximum, and everything between is proportional, so the slider's lower half is genuinely dim. */
#define Q(n) ((uint64_t)(n) << 16)
static void test_curve(void)
{
const uint32_t max = 2047, floor = edp_bl_floor_level(max), maxn = EDP_BL_NITS_MAX_DEFAULT;
CHECK(floor == 41 && maxn == 500);
uint32_t prev = 0;
for (uint64_t q = 0; q <= Q(600); q += 1u << 12) { /* monotonic, inside [floor, max] */
uint32_t l = edp_bl_nits_to_level(q, maxn, floor, max);
CHECK(l >= floor && l <= max && l >= prev);
prev = l;
}
CHECK(edp_bl_nits_to_level(0, maxn, floor, max) == floor);
CHECK(edp_bl_nits_to_level(Q(5), maxn, floor, max) == floor); /* Windows' minimum is below the floor */
CHECK(edp_bl_nits_to_level(Q(10), maxn, floor, max) == floor); /* the table's low offset is the floor */
CHECK(edp_bl_nits_to_level(Q(11), maxn, floor, max) == 45);
CHECK(edp_bl_nits_to_level(Q(250), maxn, floor, max) == 1024); /* half the luminance, half the levels */
CHECK(edp_bl_nits_to_level(Q(140), maxn, floor, max) == 573); /* CoreBrightness's default, 28% */
CHECK(edp_bl_nits_to_level(Q(500), maxn, floor, max) == max);
CHECK(edp_bl_nits_to_level(Q(500) - 1, maxn, floor, max) == max);
CHECK(edp_bl_nits_to_level(Q(1000), maxn, floor, max) == max);
CHECK(edp_bl_nits_to_level(UINT64_MAX, maxn, floor, max) == max);
CHECK(edp_bl_nits_to_level(Q(100), 0, floor, max) == floor); /* degenerate: the floor */
CHECK(edp_bl_nits_to_level(Q(100), maxn, max, max) == max && edp_bl_nits_to_level(Q(100), maxn, 9, 9) == 9);
/* The configured top moves the scale: with 400 nits as full scale, 200 nits is half. */
CHECK(edp_bl_nits_to_level(Q(200), 400, floor, max) == 1024 && edp_bl_nits_to_level(Q(400), 400, floor, max) == max);
/* Level -> nits is the same line; every level from the floor up survives the round trip. */
CHECK(edp_bl_level_to_nits(0, maxn, max) == 0 && edp_bl_level_to_nits(max, maxn, max) == Q(500) &&
edp_bl_level_to_nits(max + 100, maxn, max) == Q(500) && edp_bl_level_to_nits(5, maxn, 0) == 0);
CHECK(edp_bl_level_to_nits(716, maxn, max) >> 16 == 174); /* where Windows left the panel */
for (uint32_t l = floor; l <= max; l++) {
uint64_t n = edp_bl_level_to_nits(l, maxn, max), exact = (uint64_t)l * Q(maxn);
CHECK(n * max + max >= exact && n * max <= exact + max); /* within half a q16 step of the line */
CHECK(edp_bl_nits_to_level(n, maxn, floor, max) == l);
}
/* The darkest offer: the configured minimum, never below what the floor shows. */
uint64_t lo = edp_bl_min_nits_q16(EDP_BL_NITS_MIN_DEFAULT, maxn, floor, max);
CHECK(lo == edp_bl_level_to_nits(floor, maxn, max) && lo >> 16 == 10 && edp_bl_nits_to_level(lo, maxn, floor, max) == floor);
CHECK(edp_bl_min_nits_q16(20, maxn, floor, max) == Q(20) && edp_bl_nits_to_level(Q(20), maxn, floor, max) == 82);
/* The slider scale between the published ends. */
CHECK(edp_bl_slider_to_nits(0, lo, Q(500)) == lo && edp_bl_slider_to_nits(65536, lo, Q(500)) == Q(500) &&
edp_bl_slider_to_nits(1u << 20, lo, Q(500)) == Q(500) && edp_bl_slider_to_nits(77, Q(9), Q(9)) == Q(9));
CHECK(edp_bl_nits_to_slider(lo, lo, Q(500)) == 0 && edp_bl_nits_to_slider(Q(500), lo, Q(500)) == 65536 &&
edp_bl_nits_to_slider(Q(3), lo, Q(500)) == 0 && edp_bl_nits_to_slider(Q(9), Q(9), Q(9)) == 0);
for (uint32_t v = 0; v <= 65536; v += 512) {
uint32_t back = edp_bl_nits_to_slider(edp_bl_slider_to_nits(v, lo, Q(500)), lo, Q(500));
CHECK(back + 1 >= v && back <= v + 1);
}
/* The bottom of the slider is the floor, its top the panel's maximum. */
CHECK(edp_bl_nits_to_level(edp_bl_slider_to_nits(0, lo, Q(500)), maxn, floor, max) == floor);
CHECK(edp_bl_nits_to_level(edp_bl_slider_to_nits(65536, lo, Q(500)), maxn, floor, max) == max);
}
static void test_helpers(void)
{
uint32_t bits = 0;
@@ -204,37 +259,19 @@ static void test_helpers(void)
CHECK(edp_bl_bits(10, 10, 10, 0, &bits)); /* above 8 without the LSB register */
CHECK(!edp_bl_bits(8, 8, 8, 0, &bits) && bits == 8);
CHECK(edp_bl_max_level(11) == 2047 && edp_bl_max_level(8) == 255 && edp_bl_max_level(16) == 65535);
CHECK(edp_bl_floor_level(2047) == 205 && edp_bl_floor_level(255) == 26 && edp_bl_floor_level(1) == 1);
/* The floor is 2% of full scale, rounded up (EDP_BL_FLOOR_PERMILLE): level 41 of the A16's 2047. */
CHECK(edp_bl_floor_level(2047) == 41 && edp_bl_floor_level(255) == 6 && edp_bl_floor_level(1) == 1);
for (uint32_t n = 1; n <= 16; n++) {
uint32_t max = edp_bl_max_level(n), floor = edp_bl_floor_level(max);
CHECK(floor >= 1 && floor <= max);
CHECK((uint64_t)floor * 1000 >= (uint64_t)max * EDP_BL_FLOOR_PERMILLE);
CHECK(floor == 1 || (uint64_t)(floor - 1) * 1000 < (uint64_t)max * 20); /* the first level at 2%, no more */
}
CHECK(edp_bl_clamp(0, 205, 2047) == 205 && edp_bl_clamp(5000, 205, 2047) == 2047 &&
edp_bl_clamp(1000, 205, 2047) == 1000 && edp_bl_clamp(UINT64_MAX, 205, 2047) == 2047);
CHECK(edp_bl_clamp(0, 41, 2047) == 41 && edp_bl_clamp(5000, 41, 2047) == 2047 &&
edp_bl_clamp(1000, 41, 2047) == 1000 && edp_bl_clamp(UINT64_MAX, 41, 2047) == 2047);
CHECK(edp_bl_encode(0x5A3, 1, b) == 2 && b[0] == 0x05 && b[1] == 0xA3 && edp_bl_decode(b, 1) == 0x5A3);
CHECK(edp_bl_encode(0xC8, 0, b) == 1 && b[0] == 0xC8 && edp_bl_decode(b, 0) == 0xC8);
/* nits -> level: ends map onto floor and max, monotonic, round trip within one level */
uint32_t prev = 0;
for (uint64_t q = 0; q <= (600ull << 16); q += 1u << 12) {
uint32_t l = edp_bl_nits_to_level(q, 5, 500, 205, 2047);
CHECK(l >= 205 && l <= 2047 && l >= prev);
prev = l;
}
CHECK(edp_bl_nits_to_level(5ull << 16, 5, 500, 205, 2047) == 205);
CHECK(edp_bl_nits_to_level(500ull << 16, 5, 500, 205, 2047) == 2047);
CHECK(edp_bl_nits_to_level(0, 5, 500, 205, 2047) == 205);
CHECK(edp_bl_nits_to_level(UINT64_MAX >> 20, 5, 500, 205, 2047) == 2047);
CHECK(edp_bl_nits_to_level(100ull << 16, 500, 5, 205, 2047) == 205); /* inverted range: the floor */
for (uint32_t l = 205; l <= 2047; l += 7)
CHECK(edp_bl_nits_to_level(edp_bl_level_to_nits(l, 5, 500, 205, 2047), 5, 500, 205, 2047) == l);
CHECK(edp_bl_slider_to_nits(0, 5, 500) == 5ull << 16 && edp_bl_slider_to_nits(65536, 5, 500) == 500ull << 16 &&
edp_bl_slider_to_nits(1u << 20, 5, 500) == 500ull << 16);
CHECK(edp_bl_nits_to_slider(5ull << 16, 5, 500) == 0 && edp_bl_nits_to_slider(500ull << 16, 5, 500) == 65536);
for (uint32_t v = 0; v <= 65536; v += 512) {
uint32_t back = edp_bl_nits_to_slider(edp_bl_slider_to_nits(v, 5, 500), 5, 500);
CHECK(back + 1 >= v && back <= v + 1);
}
test_curve();
uint8_t caps[4] = {0x03, 0x07, 0x06, 0x10};
uint64_t x1 = edp_bl_reply_x1(EDP_BL_STATE_MODE, EDP_BL_DETAIL_BITS, caps, 0x12);
CHECK(edp_bl_reply_abi(x1) == EDP_BL_ABI && edp_bl_reply_state(x1) == EDP_BL_STATE_MODE &&
@@ -260,14 +297,14 @@ static void test_probe_and_set(void)
M.status = ST_DONE; /* a status the firmware left behind */
CHECK(call(EDP_BL_QUERY, 0, 0, r) == 0);
CHECK(edp_bl_reply_abi(r[1]) == EDP_BL_ABI && state_of(r) == EDP_BL_STATE_READY);
CHECK((uint32_t)r[2] == 205 && r[2] >> 32 == 2047 && level_of(r) == 768 && (r[3] >> 32 & 0xff) == 11 &&
CHECK((uint32_t)r[2] == 41 && r[2] >> 32 == 2047 && level_of(r) == 768 && (r[3] >> 32 & 0xff) == 11 &&
(r[3] >> 40 & 1) == 1);
CHECK(M.dpcd_writes == 0 && M.gos == 3 && M.violations == 0);
CHECK(call(EDP_BL_SET, 1500, 0, r) == 0 && level_of(r) == 1500 && panel_level() == 1500 && !(r[3] >> 41 & 1));
CHECK(M.last_write_addr == 0x722 && M.last_write_len == 2 && M.last_write[0] == 0x05 && M.last_write[1] == 0xDC);
unsigned gos = M.gos;
CHECK(call(EDP_BL_SET, 1500, 0, r) == 0 && M.gos == gos); /* unchanged: no traffic */
CHECK(call(EDP_BL_SET, 0, 0, r) == 0 && panel_level() == 205 && (r[3] >> 41 & 1)); /* never black */
CHECK(call(EDP_BL_SET, 0, 0, r) == 0 && panel_level() == 41 && (r[3] >> 41 & 1)); /* never black */
CHECK(call(EDP_BL_SET, 70000, 0, r) == 0 && panel_level() == 2047 && (r[3] >> 41 & 1)); /* never past max */
CHECK(M.dpcd[0x721] == 0x12 && M.violations == 0);
}
@@ -280,7 +317,7 @@ static void test_byte_panel(void)
M.dpcd[0x722] = 0x80; M.dpcd[0x723] = 0x55;
M.dpcd[0x724] = 8; M.dpcd[0x725] = 8; M.dpcd[0x726] = 8;
CHECK(call(EDP_BL_QUERY, 0, 0, r) == 0 && state_of(r) == EDP_BL_STATE_READY && level_of(r) == 0x80 &&
r[2] >> 32 == 255 && (uint32_t)r[2] == 26);
r[2] >> 32 == 255 && (uint32_t)r[2] == 6);
CHECK(call(EDP_BL_SET, 200, 0, r) == 0 && M.dpcd[0x722] == 200 && M.dpcd[0x723] == 0x55 && M.last_write_len == 1);
CHECK(M.violations == 0);
}
+11 -3
View File
@@ -8,8 +8,8 @@ opt-in wiring, and (on request) the default-build identity of the monitor and th
python3 tools/test-edp-backlight.py --kext-reference DIR # + kext: default sections == DIR's
Model: tools/test-edp-backlight.c runs compat/edp-backlight.{h,c} against a model of the eDP controller's AUX FIFO and a
DPCD panel and must PASS (ASan/UBSan). Each MUTATIONS entry weakens one safety property in a copy of the engine; the
same program must FAIL on every one.
DPCD panel, and checks the kext's nits -> level curve, and must PASS (ASan/UBSan). Each MUTATIONS entry weakens one
safety property or bends the curve in a copy of the engine; the same program must FAIL on every one.
Wiring: probes/xnuboot.c defaults SNAP_EDP_BACKLIGHT to 0 and every monitor use sits under it; compat/edp-backlight.c is
linked only through probes/run.py OPTIONAL; the call number and event number are unique; the kext's backlight code sits
@@ -45,7 +45,15 @@ _ap.add_argument('--out')
ARGS, REST = _ap.parse_known_args() if __name__ == '__main__' else (_ap.parse_args([]), [])
ENGINE = ('compat/edp-backlight.h', 'compat/edp-backlight.c', 'compat/dpu-intf.h')
MUTATIONS = (
('no floor', 'compat/edp-backlight.h', '#define EDP_BL_FLOOR_PERMILLE 100u', '#define EDP_BL_FLOOR_PERMILLE 0u'),
('no floor', 'compat/edp-backlight.h', '#define EDP_BL_FLOOR_PERMILLE 20u', '#define EDP_BL_FLOOR_PERMILLE 0u'),
('bright floor', 'compat/edp-backlight.h', '#define EDP_BL_FLOOR_PERMILLE 20u',
'#define EDP_BL_FLOOR_PERMILLE 100u'),
('affine curve', 'compat/edp-backlight.h', 'return edp_bl_clamp((nits_q16 * max + full / 2) / full, floor, max);',
'return floor + (uint32_t)((nits_q16 * (max - floor) + full / 2) / full);'),
('top short of max', 'compat/edp-backlight.h', 'if (nits_q16 >= full) return max;',
'if (nits_q16 >= full) return max - 1;'),
('minimum below the floor', 'compat/edp-backlight.h', 'return configured > at_floor ? configured : at_floor;',
'return configured + 0 * at_floor;'),
('no clamp', 'compat/edp-backlight.c', 'uint32_t level = edp_bl_clamp(request, s->floor, s->max);',
'uint32_t level = (uint32_t)request;'),
('mask bits dropped', 'compat/edp-backlight.c', ' << 1 | (status & EDP_INTR_MASK_BITS));', ' << 1);'),