From 6fce0ee56edf36bada99d6065a4998e51234f2d7 Mon Sep 17 00:00:00 2001 From: hrdl <31923882+hrdl-github@users.noreply.github.com> Date: Mon, 5 May 2025 21:29:59 +0200 Subject: [PATCH] rockchip_ebc: extend mode and add zero_waveform ioctl Extend mode ioctl to get/set the dither mode and the redraw delay. Add zero_waveform ioctl that causes the controller to drive the display with an all-neutral phase buffer. This allows measuring the VCOM using the following protocol: 1. Perform IOCTL zero_waveform(set_zero_waveform_mode=1, zero_waveform_mode=1) 2. Confirm that the phase buffer is all zero. zero_waveform_mode needs to be 1 after ICTL zero_waveform(set_zero_waveform_mode=0). 3. Perform the VCOM measurement. 4. Perform IOCTL zero_waveform(set_zero_waveform_mode=1, zero_waveform_mode=0) --- drivers/gpu/drm/rockchip/rockchip_ebc.c | 215 +++++++++++++++++++----- drivers/gpu/drm/rockchip/rockchip_ebc.h | 5 +- include/uapi/drm/rockchip_ebc_drm.h | 56 ++++-- 3 files changed, 218 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_ebc.c b/drivers/gpu/drm/rockchip/rockchip_ebc.c index 725b3b812268..5d287e24a617 100644 --- a/drivers/gpu/drm/rockchip/rockchip_ebc.c +++ b/drivers/gpu/drm/rockchip/rockchip_ebc.c @@ -166,13 +166,15 @@ MODULE_FIRMWARE(EBC_CUSTOM_WF); static const char *custom_wf_magic_version = "CLUT0002"; -#define ROCKCHIP_EBC_WORK_ITEM_CHANGE_LUT 1 -#define ROCKCHIP_EBC_WORK_ITEM_GLOBAL_REFRESH 2 -#define ROCKCHIP_EBC_WORK_ITEM_INIT 4 -#define ROCKCHIP_EBC_WORK_ITEM_SUSPEND 8 -#define ROCKCHIP_EBC_WORK_ITEM_RESCHEDULE 16 -#define ROCKCHIP_EBC_WORK_ITEM_ENABLE_FAST_MODE 32 -#define ROCKCHIP_EBC_WORK_ITEM_DISABLE_FAST_MODE 64 +#define ROCKCHIP_EBC_WORK_ITEM_CHANGE_LUT BIT(0) +#define ROCKCHIP_EBC_WORK_ITEM_GLOBAL_REFRESH BIT(1) +#define ROCKCHIP_EBC_WORK_ITEM_INIT BIT(2) +#define ROCKCHIP_EBC_WORK_ITEM_SUSPEND BIT(3) +#define ROCKCHIP_EBC_WORK_ITEM_RESCHEDULE BIT(4) +#define ROCKCHIP_EBC_WORK_ITEM_ENABLE_NORMAL_MODE BIT(5) +#define ROCKCHIP_EBC_WORK_ITEM_ENABLE_FAST_MODE BIT(6) +#define ROCKCHIP_EBC_WORK_ITEM_ENABLE_ZERO_WAVEFORM_MODE BIT(7) +#define ROCKCHIP_EBC_WORK_ITEM_DISABLE_ZERO_WAVEFORM_MODE BIT(8) static const u8 dither_bayer_04[] = { 7, 8, 2, 10, 7, 8, 2, 10, 7, 8, 2, 10, 7, 8, 2, 10, @@ -512,35 +514,90 @@ static int ioctl_mode(struct drm_device *dev, void *data, struct rockchip_ebc *ebc = dev_get_drvdata(dev->dev); int ret = 0; - if (mode->set_mode) { + if (mode->set_driver_mode) { spin_lock(&ebc->work_item_lock); - switch (mode->mode) { - case ROCKCHIP_EBC_MODE_NORMAL: + switch (mode->driver_mode) { + case ROCKCHIP_EBC_DRIVER_MODE_NORMAL: ebc->work_item |= - ROCKCHIP_EBC_WORK_ITEM_DISABLE_FAST_MODE; - ebc->work_item &= - ~ROCKCHIP_EBC_WORK_ITEM_ENABLE_FAST_MODE; + ROCKCHIP_EBC_WORK_ITEM_ENABLE_NORMAL_MODE; break; - case ROCKCHIP_EBC_MODE_FAST: + case ROCKCHIP_EBC_DRIVER_MODE_FAST: ebc->work_item |= ROCKCHIP_EBC_WORK_ITEM_ENABLE_FAST_MODE; - ebc->work_item &= - ~ROCKCHIP_EBC_WORK_ITEM_DISABLE_FAST_MODE; break; default: - ret = -EINVAL; + ret |= -EINVAL; } spin_unlock(&ebc->work_item_lock); } else { - if (ebc->fast_mode) - mode->mode = ROCKCHIP_EBC_MODE_FAST; - else - mode->mode = ROCKCHIP_EBC_MODE_NORMAL; + mode->driver_mode = ebc->driver_mode; + } + if (mode->set_dither_mode) { + switch (mode->dither_mode) { + case ROCKCHIP_EBC_DITHER_MODE_BAYER: + ebc->dithering_texture_size_hint = 4; + ebc->dithering_texture = dither_bayer_04; + break; + case ROCKCHIP_EBC_DITHER_MODE_BLUE_NOISE_16: + ebc->dithering_texture_size_hint = 4; + ebc->dithering_texture = dither_blue_noise_16; + ebc->dithering_texture_size_hint = 16; + break; + case ROCKCHIP_EBC_DITHER_MODE_BLUE_NOISE_32: + ebc->dithering_texture = dither_blue_noise_32; + ebc->dithering_texture_size_hint = 32; + break; + default: + ret |= -EINVAL; + } + } else { + if (ebc->dithering_texture == dither_bayer_04) + mode->dither_mode = ROCKCHIP_EBC_DITHER_MODE_BAYER; + else if (ebc->dithering_texture == dither_blue_noise_16) + mode->dither_mode = + ROCKCHIP_EBC_DITHER_MODE_BLUE_NOISE_16; + else if (ebc->dithering_texture == dither_blue_noise_32) + mode->dither_mode = + ROCKCHIP_EBC_DITHER_MODE_BLUE_NOISE_32; + } + if (mode->set_redraw_delay) { + if (mode->redraw_delay != redraw_delay) { + redraw_delay = mode->redraw_delay; + spin_lock(&ebc->work_item_lock); + ebc->work_item |= ROCKCHIP_EBC_WORK_ITEM_CHANGE_LUT; + spin_unlock(&ebc->work_item_lock); + } + } else { + mode->redraw_delay = ebc->redraw_delay; } return ret; } +static int ioctl_zero_waveform(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_rockchip_ebc_zero_waveform *zero_waveform = data; + struct rockchip_ebc *ebc = dev_get_drvdata(dev->dev); + + if (zero_waveform->set_zero_waveform_mode) { + spin_lock(&ebc->work_item_lock); + if (zero_waveform->zero_waveform_mode) + ebc->work_item |= + ROCKCHIP_EBC_WORK_ITEM_ENABLE_ZERO_WAVEFORM_MODE; + else + ebc->work_item |= + ROCKCHIP_EBC_WORK_ITEM_DISABLE_ZERO_WAVEFORM_MODE; + spin_unlock(&ebc->work_item_lock); + } else { + zero_waveform->zero_waveform_mode = + ebc->driver_mode == + ROCKCHIP_EBC_DRIVER_MODE_ZERO_WAVEFORM; + } + + return 0; +} + static const struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] = { DRM_IOCTL_DEF_DRV(ROCKCHIP_EBC_GLOBAL_REFRESH, ioctl_trigger_global_refresh, DRM_RENDER_ALLOW), @@ -551,6 +608,8 @@ static const struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] = DRM_IOCTL_DEF_DRV(ROCKCHIP_EBC_RECT_HINTS, ioctl_rect_hints, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(ROCKCHIP_EBC_MODE, ioctl_mode, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(ROCKCHIP_EBC_ZERO_WAVEFORM, ioctl_zero_waveform, + DRM_RENDER_ALLOW), }; static const struct drm_driver rockchip_ebc_drm_driver = { @@ -648,6 +707,7 @@ static void rockchip_ebc_change_lut(struct rockchip_ebc *ebc) } } } + ebc->redraw_delay = redraw_delay = redraw_delay - waiting_remaining; // TODO: generalise for temperature ranges for which more than 31 phases are required ebc->inner_0_15 = lut->lut[(0xf << ROCKCHIP_EBC_CUSTOM_WF_SEQ_SHIFT) + lut->offsets[ROCKCHIP_EBC_CUSTOM_WF_DU]]; @@ -680,7 +740,7 @@ static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc, struct drm_rect clip_ongoing = DRM_RECT_EMPTY_EXTANDABLE; struct drm_rect clip_ongoing_or_waiting = clip_ongoing; - u8 work_item = ebc->work_item; + u32 work_item = ebc->work_item; ktime_t time_last_start = ktime_get(); // TODO: move into logic setting these values @@ -709,7 +769,9 @@ static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc, bool awaiting_completion = false; bool awaiting_start = false; bool no_schedule_until_clip_empty = false; - bool is_enabling_fast_mode = false, is_disabling_fast_mode = false; + int enabling_mode = ebc->driver_mode; + int zero_waveform_mode_num_zero_phase_buffers = 0; + bool inhibit_suspend = false; bool is_suspending = false; ktime_t time_last_report = ktime_get(); int num_frames_since_last_report = 0; @@ -730,17 +792,50 @@ static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc, work_item |= ebc->work_item; ebc->work_item = 0; spin_unlock(&ebc->work_item_lock); + if (ebc->driver_mode == + ROCKCHIP_EBC_DRIVER_MODE_ZERO_WAVEFORM && + !(work_item & + ROCKCHIP_EBC_WORK_ITEM_DISABLE_ZERO_WAVEFORM_MODE)) { + pr_err("Ignoring work items until zero waveform mode is left explicitly"); + work_item = 0; + } if ((work_item & - ROCKCHIP_EBC_WORK_ITEM_ENABLE_FAST_MODE) && - !ebc->fast_mode) { + ROCKCHIP_EBC_WORK_ITEM_DISABLE_ZERO_WAVEFORM_MODE) && + (ebc->driver_mode == + ROCKCHIP_EBC_DRIVER_MODE_ZERO_WAVEFORM)) { + pr_warn("Disabling zero waveform mode"); + inhibit_suspend = false; + // Make sure to set a mode + if (!(work_item & + (ROCKCHIP_EBC_WORK_ITEM_ENABLE_ZERO_WAVEFORM_MODE | + ROCKCHIP_EBC_WORK_ITEM_ENABLE_FAST_MODE | + ROCKCHIP_EBC_WORK_ITEM_ENABLE_NORMAL_MODE))) { + work_item |= + ROCKCHIP_EBC_WORK_ITEM_ENABLE_NORMAL_MODE; + } + } + if ((work_item & + ROCKCHIP_EBC_WORK_ITEM_ENABLE_ZERO_WAVEFORM_MODE) && + (ebc->driver_mode != + ROCKCHIP_EBC_DRIVER_MODE_ZERO_WAVEFORM)) { + pr_info("Enabling zero waveform mode, finishing ongoing updates"); + // Finish ongoing updates to resume with a zero-only inner/outer buffer no_schedule_until_clip_empty = true; - is_enabling_fast_mode = true; + zero_waveform_mode_num_zero_phase_buffers = 0; + enabling_mode = + ROCKCHIP_EBC_DRIVER_MODE_ZERO_WAVEFORM; + inhibit_suspend = true; + } else if ((work_item & + ROCKCHIP_EBC_WORK_ITEM_ENABLE_FAST_MODE) && + ebc->driver_mode != ROCKCHIP_EBC_DRIVER_MODE_FAST) { + no_schedule_until_clip_empty = true; + enabling_mode = ROCKCHIP_EBC_DRIVER_MODE_FAST; work_item |= ROCKCHIP_EBC_WORK_ITEM_GLOBAL_REFRESH; } else if ((work_item & - ROCKCHIP_EBC_WORK_ITEM_DISABLE_FAST_MODE) && - ebc->fast_mode) { + ROCKCHIP_EBC_WORK_ITEM_ENABLE_NORMAL_MODE) && + ebc->driver_mode != ROCKCHIP_EBC_DRIVER_MODE_NORMAL) { no_schedule_until_clip_empty = true; - is_disabling_fast_mode = true; + enabling_mode = ROCKCHIP_EBC_DRIVER_MODE_NORMAL; } if (work_item & ROCKCHIP_EBC_WORK_ITEM_CHANGE_LUT) { rockchip_ebc_change_lut(ebc); @@ -769,9 +864,14 @@ static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc, ebc->suspend_was_requested = 1; } else if (work_item & ROCKCHIP_EBC_WORK_ITEM_GLOBAL_REFRESH) { - if (ebc->fast_mode || is_enabling_fast_mode) { - ebc->fast_mode = false; - is_enabling_fast_mode = true; + if (ebc->driver_mode == + ROCKCHIP_EBC_DRIVER_MODE_FAST || + enabling_mode == + ROCKCHIP_EBC_DRIVER_MODE_FAST) { + ebc->driver_mode = ROCKCHIP_EBC_DRIVER_MODE_NORMAL; + enabling_mode = + ROCKCHIP_EBC_DRIVER_MODE_FAST; + // TODO: use NEON implementation for (int i = 0; i < ebc->num_pixels; ++i) { u8 prelim = prelim_target[i] & 0xf0; prelim_target[i] = prelim | prelim >> 4; @@ -781,12 +881,14 @@ static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc, kernel_neon_begin(); rockchip_ebc_schedule_advance_neon(ebc, prelim_target, hints, phase_buffer, &clip_ongoing, &clip_ongoing_or_waiting, 0, ROCKCHIP_EBC_CUSTOM_WF_GC16, 0, ROCKCHIP_EBC_HINT_REDRAW, true); kernel_neon_end(); + // Skip a single advance as we have performed one just now skip_advance = true; no_schedule_until_clip_empty = true; ebc->suspend_was_requested = 0; } work_item = 0; } else if (drm_rect_width(&clip_ongoing_or_waiting) <= 0 && + !inhibit_suspend && (is_suspending || ((drm_rect_width(&clip_incoming) <= 0) && (ktime_ms_delta(ktime_get(), time_last_start) > @@ -799,10 +901,18 @@ static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc, &clip_ongoing_or_waiting, &clip_incoming); clip_incoming = DRM_RECT_EMPTY_EXTANDABLE; } - pr_debug("%s frame=%d clip_ongoing=" DRM_RECT_FMT " clip_ongoing_or_waiting=" DRM_RECT_FMT " work_item=%d no_schedule_until_clip_empty=%d time_elapsed_since_last_start=%llu", __func__, frame, DRM_RECT_ARG(&clip_ongoing), DRM_RECT_ARG(&clip_ongoing_or_waiting), work_item, no_schedule_until_clip_empty, ktime_ms_delta(ktime_get(), time_last_start)); + pr_debug( + "%s frame=%d clip_ongoing=" DRM_RECT_FMT + " clip_ongoing_or_waiting=" DRM_RECT_FMT + " work_item=%d no_schedule_until_clip_empty=%d time_elapsed_since_last_start=%llu", + __func__, frame, DRM_RECT_ARG(&clip_ongoing), + DRM_RECT_ARG(&clip_ongoing_or_waiting), work_item, + no_schedule_until_clip_empty, + ktime_ms_delta(ktime_get(), time_last_start)); + pr_debug("%s ebc->driver_mode=%d enabling_mode=%d", __func__, ebc->driver_mode, enabling_mode); if (drm_rect_width(&clip_ongoing_or_waiting) > 0 && !skip_advance) { - if (ebc->fast_mode) { + if (ebc->driver_mode == ROCKCHIP_EBC_DRIVER_MODE_FAST) { kernel_neon_begin(); rockchip_ebc_schedule_advance_fast_neon( ebc, prelim_target, hints, @@ -811,7 +921,7 @@ static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc, early_cancellation_addition, 0, 0, 0, !no_schedule_until_clip_empty && !work_item); kernel_neon_end(); - } else { + } else if (ebc->driver_mode == ROCKCHIP_EBC_DRIVER_MODE_NORMAL) { kernel_neon_begin(); rockchip_ebc_schedule_advance_neon( ebc, prelim_target, hints, @@ -824,14 +934,24 @@ static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc, } if (drm_rect_width(&clip_ongoing) <= 0 && no_schedule_until_clip_empty) { - no_schedule_until_clip_empty = false; - if (is_enabling_fast_mode) { - ebc->fast_mode = true; - is_enabling_fast_mode = false; - } - if (is_disabling_fast_mode) { - ebc->fast_mode = false; - is_disabling_fast_mode = false; + if (enabling_mode == + ROCKCHIP_EBC_DRIVER_MODE_ZERO_WAVEFORM && + zero_waveform_mode_num_zero_phase_buffers < 2) { + memset(phase_buffer, 0, ebc->phase_size); + if (++zero_waveform_mode_num_zero_phase_buffers >= + 2) { + ebc->driver_mode = + ROCKCHIP_EBC_DRIVER_MODE_ZERO_WAVEFORM; + pr_info("Zero waveform mode enabled"); + } + } else { + switch (enabling_mode) { + case ROCKCHIP_EBC_DRIVER_MODE_NORMAL: + case ROCKCHIP_EBC_DRIVER_MODE_FAST: + ebc->driver_mode = enabling_mode; + no_schedule_until_clip_empty = false; + break; + } } } pr_debug("%s schedul2 frame=%d clip_ongoing=" DRM_RECT_FMT " clip_ongoing_or_waiting=" DRM_RECT_FMT, @@ -854,7 +974,9 @@ static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc, num_frames_since_last_report = 0; max_advance_time_since_last_report = 0; } - awaiting_start = drm_rect_width(&clip_ongoing) > 0; + awaiting_start = drm_rect_width(&clip_ongoing) > 0 || + ebc->driver_mode == + ROCKCHIP_EBC_DRIVER_MODE_ZERO_WAVEFORM; if (awaiting_start) { // TODO: make sure we've synced all zeros as well int win_start = clip_ongoing.y1 * ebc->phase_pitch + (direct_mode ? clip_ongoing.x1 / 4 : clip_ongoing.x1); @@ -925,7 +1047,7 @@ static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc, s64 switch_buffer = 11700 - delta_advance - delta_wait - 1000; // TODO: consider adding || !work_item - while(!is_suspending) { + while(!is_suspending && ebc->driver_mode != ROCKCHIP_EBC_DRIVER_MODE_ZERO_WAVEFORM) { spin_lock(&ctx->buffer_switch_lock); ctx->refresh_index = ctx->next_refresh_index; for (int i = 0; i < 3; ++i) { @@ -2059,7 +2181,8 @@ static int rockchip_ebc_probe(struct platform_device *pdev) *((u32 *) ebc->hardware_wf + 32) = 0xaaaaaaaa; } - ebc->fast_mode = false; + ebc->driver_mode = ROCKCHIP_EBC_DRIVER_MODE_NORMAL; + ebc->redraw_delay = redraw_delay; // Sensible temperature default ebc->temperature = temp_override > 0 ? temp_override : 25; diff --git a/drivers/gpu/drm/rockchip/rockchip_ebc.h b/drivers/gpu/drm/rockchip/rockchip_ebc.h index 8d012ece1706..836a06afefa5 100644 --- a/drivers/gpu/drm/rockchip/rockchip_ebc.h +++ b/drivers/gpu/drm/rockchip/rockchip_ebc.h @@ -120,10 +120,11 @@ struct rockchip_ebc { u8 dithering_texture_size_hint; // whether we use direct mode or 3WIN mode. Only 3WIN mode is implemented right now bool direct_mode; - bool fast_mode; + int driver_mode; + int redraw_delay; // Used to change the driver LUT due to temperature update, trigger a global refresh, or buffer changes spinlock_t work_item_lock; - u8 work_item; + u32 work_item; // used to detect when we are suspending so we can do different things to // the ebc display depending on whether we are sleeping or suspending int suspend_was_requested; diff --git a/include/uapi/drm/rockchip_ebc_drm.h b/include/uapi/drm/rockchip_ebc_drm.h index 8fc969c3111a..f655c5b97176 100644 --- a/include/uapi/drm/rockchip_ebc_drm.h +++ b/include/uapi/drm/rockchip_ebc_drm.h @@ -17,8 +17,13 @@ extern "C" { #define ROCKCHIP_EBC_HINT_REDRAW 1 << 7 #define ROCKCHIP_EBC_HINT_MASK 0xf0 -#define ROCKCHIP_EBC_MODE_NORMAL 0 -#define ROCKCHIP_EBC_MODE_FAST 1 +#define ROCKCHIP_EBC_DRIVER_MODE_NORMAL 0 +#define ROCKCHIP_EBC_DRIVER_MODE_FAST 1 +#define ROCKCHIP_EBC_DRIVER_MODE_ZERO_WAVEFORM 8 + +#define ROCKCHIP_EBC_DITHER_MODE_BAYER 0 +#define ROCKCHIP_EBC_DITHER_MODE_BLUE_NOISE_16 1 +#define ROCKCHIP_EBC_DITHER_MODE_BLUE_NOISE_32 2 struct drm_rockchip_ebc_trigger_global_refresh { bool trigger_global_refresh; @@ -87,24 +92,55 @@ struct drm_rockchip_ebc_rect_hints { }; /** - * struct drm_rockchip_ebc_mode - Query and set driver mode. - * @set_mode: apply mode instead of reading it to the same field. - * @mode: one of ROCKCHIP_EBC_MODE_NORMAL or ROCKCHIP_EBC_MODE_FAST. - * @padding: 64bit alignment padding. + * struct drm_rockchip_ebc_mode - Query and set driver/dither modes and + * redraw delay + * @set_driver_mode: apply driver_mode instead of reading it to the same + * field. + * @driver_mode: one of ROCKCHIP_EBC_DRIVER_MODE_NORMAL or + * ROCKCHIP_EBC_DRIVER_MODE_FAST. + * @set_dither_mode: apply dither_mode instead of reading it to the same + * field. + * @dither_mode: one of ROCKCHIP_EBC_DITHER_MODE_BAYER, + * ROCKCHIP_EBC_DITHER_MODE_BLUE_NOISE_16, or + * ROCKCHIP_EBC_DITHER_MODE_BLUE_NOISE_32. + * @redraw_delay: number of hardware frames to delay redraws. + * @set_redraw_delay: apply redraw_delay instead of reading it to the same + * field. */ struct drm_rockchip_ebc_mode { - __u8 set_mode; - __u8 mode; - __u8 padding[6]; + __u8 set_driver_mode; + __u8 driver_mode; + __u8 set_dither_mode; + __u8 dither_mode; + __u16 redraw_delay; + __u8 set_redraw_delay; + __u8 _pad; }; -#define DRM_ROCKCHIP_EBC_NUM_IOCTLS 0x05 +/** + * struct drm_rockchip_ebc_zero_waveform- Query and enable/disable zero + * waveform mode + * @set_zero_waveform_mode: apply zero_waveform_mode instead of reading it to + * the same field. + * @zero_waveform_mode: 0 for disable(d), 1 for enable(d) + */ +struct drm_rockchip_ebc_zero_waveform { + __u8 set_zero_waveform_mode; + __u8 zero_waveform_mode; + __u8 _pad[6]; +}; + +#define DRM_ROCKCHIP_EBC_NUM_IOCTLS 0x06 #define DRM_IOCTL_ROCKCHIP_EBC_GLOBAL_REFRESH DRM_IOWR(DRM_COMMAND_BASE + 0x00, struct drm_rockchip_ebc_trigger_global_refresh) #define DRM_IOCTL_ROCKCHIP_EBC_OFF_SCREEN DRM_IOW(DRM_COMMAND_BASE + 0x01, struct drm_rockchip_ebc_off_screen) #define DRM_IOCTL_ROCKCHIP_EBC_EXTRACT_FBS DRM_IOWR(DRM_COMMAND_BASE + 0x02, struct drm_rockchip_ebc_extract_fbs) #define DRM_IOCTL_ROCKCHIP_EBC_RECT_HINTS DRM_IOW(DRM_COMMAND_BASE + 0x03, struct drm_rockchip_ebc_rect_hints) #define DRM_IOCTL_ROCKCHIP_EBC_MODE DRM_IOWR(DRM_COMMAND_BASE + 0x04, struct drm_rockchip_ebc_mode) +#define DRM_IOCTL_ROCKCHIP_EBC_ZERO_WAVEFORM DRM_IOWR(DRM_COMMAND_BASE + 0x05, struct drm_rockchip_ebc_zero_waveform) +#if defined(__cplusplus) +} +#endif #endif /* __ROCKCHIP_EBC_DRM_H__*/