rockchip_ebc: add phase_sequence mode
This commit is contained in:
parent
9a0ab7b283
commit
c98b91eaff
4 changed files with 202 additions and 2 deletions
|
|
@ -175,6 +175,7 @@ static const char *custom_wf_magic_version = "CLUT0002";
|
|||
#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)
|
||||
#define ROCKCHIP_EBC_WORK_ITEM_ENABLE_PHASE_SEQUENCE_MODE BIT(9)
|
||||
|
||||
static const u8 dither_bayer_04[] = {
|
||||
7, 8, 2, 10, 7, 8, 2, 10, 7, 8, 2, 10, 7, 8, 2, 10,
|
||||
|
|
@ -595,6 +596,34 @@ static int ioctl_zero_waveform(struct drm_device *dev, void *data,
|
|||
ROCKCHIP_EBC_DRIVER_MODE_ZERO_WAVEFORM;
|
||||
}
|
||||
|
||||
wake_up_process(ebc->refresh_thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ioctl_phase_sequence(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct rockchip_ebc *ebc = dev_get_drvdata(dev->dev);
|
||||
|
||||
spin_lock(&ebc->phase_sequence_lock);
|
||||
memcpy(ebc->phase_sequence, data,
|
||||
sizeof(struct drm_rockchip_ebc_phase_sequence));
|
||||
|
||||
// Driving
|
||||
ebc->phase_sequence->num_seqs = min(ebc->phase_sequence->num_seqs,
|
||||
ROCKCHIP_EBC_MAX_PHASE_SEQUENCES);
|
||||
for (int i = 0; i < ebc->phase_sequence->num_seqs; ++i) {
|
||||
ebc->phase_sequence->elms[i].num_regions =
|
||||
min(ebc->phase_sequence->elms[i].num_regions,
|
||||
ROCKCHIP_EBC_MAX_REGIONS);
|
||||
}
|
||||
spin_unlock(&ebc->phase_sequence_lock);
|
||||
spin_lock(&ebc->work_item_lock);
|
||||
ebc->work_item |= ROCKCHIP_EBC_WORK_ITEM_ENABLE_PHASE_SEQUENCE_MODE;
|
||||
spin_unlock(&ebc->work_item_lock);
|
||||
|
||||
wake_up_process(ebc->refresh_thread);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -610,6 +639,8 @@ static const struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] =
|
|||
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),
|
||||
DRM_IOCTL_DEF_DRV(ROCKCHIP_EBC_PHASE_SEQUENCE, ioctl_phase_sequence,
|
||||
DRM_RENDER_ALLOW),
|
||||
};
|
||||
|
||||
static const struct drm_driver rockchip_ebc_drm_driver = {
|
||||
|
|
@ -724,6 +755,132 @@ static void print_lut(struct rockchip_ebc *ebc)
|
|||
pr_info("%s lut=%64ph", __func__, lut + 15 * 64);
|
||||
}
|
||||
|
||||
static void rockchip_ebc_blit_direct_phase(struct rockchip_ebc *ebc,
|
||||
u8 *phase_buffer,
|
||||
struct drm_mode_rect *rect, u8 phase)
|
||||
{
|
||||
u8 phases[3] = {0x00, 0x55, 0xaa};
|
||||
phase = phases[phase & 3];
|
||||
int x1 = max(0, rect->x1);
|
||||
int x2 = min((int) ebc->pixel_pitch, rect->x2);
|
||||
|
||||
u8 *line = phase_buffer;
|
||||
for (int y = max(0, rect->y1); y < min((int) ebc->height, rect->y2); ++y) {
|
||||
memset(line + y * ebc->phase_pitch + (x1 >> 2), phase, (x2 >> 2) - (x1 >> 2));
|
||||
}
|
||||
}
|
||||
|
||||
static void rockchip_ebc_phase_sequence(struct rockchip_ebc *ebc)
|
||||
{
|
||||
struct drm_device *drm = &ebc->drm;
|
||||
struct device *dev = drm->dev;
|
||||
|
||||
spin_lock(&ebc->phase_sequence_lock);
|
||||
struct drm_rockchip_ebc_phase_sequence *ps = ebc->phase_sequence;
|
||||
|
||||
int previous_temp_override = temp_override;
|
||||
u32 frame_counter;
|
||||
if (ps->do_force_temperature)
|
||||
temp_override = ps->force_temperature;
|
||||
|
||||
if (ps->do_init || ps->do_gc16)
|
||||
rockchip_ebc_change_lut(ebc);
|
||||
|
||||
struct drm_epd_lut_temp_v2 *lut = ebc->lut_custom_active;
|
||||
u8 phases[3] = { 0x00, 0x55, 0xaa };
|
||||
u32 frame = 0;
|
||||
bool awaiting_completion = false;
|
||||
|
||||
// TODO: consider performing do_init and go_gc16 in partial_refresh function
|
||||
if (ps->do_init) {
|
||||
u8 outer = lut->offsets[ROCKCHIP_EBC_CUSTOM_WF_INIT];
|
||||
u8 inner = lut->lut[outer];
|
||||
for (frame = 0;; frame++) {
|
||||
u8 phase = phases[(inner & 0xc0) >> 6];
|
||||
dma_addr_t phase_handle = ebc->phase_handles[phase % 2];
|
||||
if (inner & 0x1f) {
|
||||
memset(ebc->phase[frame % 2], phase, ebc->phase_size);
|
||||
inner -= 1;
|
||||
}
|
||||
if (!(inner & 0x1f)) {
|
||||
if (inner & 0x20)
|
||||
break;
|
||||
else
|
||||
inner = lut->lut[++outer];
|
||||
}
|
||||
dma_sync_single_for_device(dev, phase_handle,
|
||||
ebc->phase_size,
|
||||
DMA_TO_DEVICE);
|
||||
if (awaiting_completion && !wait_for_completion_timeout(&ebc->display_end, EBC_FRAME_TIMEOUT)) {
|
||||
pr_err("Frame %d timed out!\n", frame);
|
||||
}
|
||||
awaiting_completion = false;
|
||||
regmap_write(ebc->regmap, EBC_WIN_MST0, phase_handle);
|
||||
regmap_write(ebc->regmap, EBC_CONFIG_DONE,
|
||||
EBC_CONFIG_DONE_REG_CONFIG_DONE);
|
||||
regmap_write(ebc->regmap, EBC_DSP_START,
|
||||
ebc->dsp_start |
|
||||
EBC_DSP_START_DSP_FRM_START);
|
||||
awaiting_completion = true;
|
||||
}
|
||||
fsleep(ps->delay_ms * 1000);
|
||||
}
|
||||
if (awaiting_completion && !wait_for_completion_timeout(&ebc->display_end, EBC_FRAME_TIMEOUT)) {
|
||||
pr_err("Frame %d timed out!\n", frame);
|
||||
}
|
||||
awaiting_completion = false;
|
||||
|
||||
if (ps->do_gc16) {
|
||||
// TODO:
|
||||
fsleep(ps->delay_ms * 1000);
|
||||
}
|
||||
|
||||
frame = 0;
|
||||
for (int i_seq = 0; i_seq < ps->num_seqs; ++i_seq) {
|
||||
struct drm_rockchip_ebc_phase_sequence_element *elm =
|
||||
ps->elms + i_seq;
|
||||
for (int i_frame = 0; i_frame < elm->num_frames;
|
||||
++i_frame, ++frame) {
|
||||
ktime_t t1 = ktime_get();
|
||||
if (i_frame < 2) {
|
||||
for (int i_region = 0;
|
||||
i_region < elm->num_regions; ++i_region) {
|
||||
rockchip_ebc_blit_direct_phase(
|
||||
ebc, ebc->phase[frame % 2],
|
||||
elm->rect + i_region,
|
||||
elm->phase[i_region]);
|
||||
}
|
||||
}
|
||||
dma_sync_single_for_device(dev, ebc->phase_handles[frame % 2],
|
||||
ebc->phase_size,
|
||||
DMA_TO_DEVICE);
|
||||
if (awaiting_completion && !wait_for_completion_timeout(&ebc->display_end, EBC_FRAME_TIMEOUT)) {
|
||||
pr_err("Frame %d timed out!\n", frame);
|
||||
}
|
||||
awaiting_completion = false;
|
||||
regmap_write(ebc->regmap, EBC_WIN_MST0,
|
||||
ebc->phase_handles[frame % 2]);
|
||||
regmap_write(ebc->regmap, EBC_CONFIG_DONE,
|
||||
EBC_CONFIG_DONE_REG_CONFIG_DONE);
|
||||
s64 delay_frame = elm->delay_ms * 1000 -
|
||||
ktime_us_delta(ktime_get(), t1);
|
||||
if (delay_frame > 0)
|
||||
fsleep(delay_frame);
|
||||
regmap_write(ebc->regmap, EBC_DSP_START,
|
||||
ebc->dsp_start |
|
||||
EBC_DSP_START_DSP_FRM_START);
|
||||
awaiting_completion = true;
|
||||
}
|
||||
|
||||
}
|
||||
if (ps->do_force_temperature) {
|
||||
temp_override = previous_temp_override;
|
||||
rockchip_ebc_change_lut(ebc);
|
||||
}
|
||||
|
||||
spin_unlock(&ebc->phase_sequence_lock);
|
||||
}
|
||||
|
||||
static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc,
|
||||
struct rockchip_ebc_ctx *ctx)
|
||||
{
|
||||
|
|
@ -836,6 +993,10 @@ static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc,
|
|||
ebc->driver_mode != ROCKCHIP_EBC_DRIVER_MODE_NORMAL) {
|
||||
no_schedule_until_clip_empty = true;
|
||||
enabling_mode = ROCKCHIP_EBC_DRIVER_MODE_NORMAL;
|
||||
} else if (work_item &
|
||||
ROCKCHIP_EBC_WORK_ITEM_ENABLE_PHASE_SEQUENCE_MODE) {
|
||||
no_schedule_until_clip_empty = true;
|
||||
enabling_mode = ROCKCHIP_EBC_DRIVER_MODE_PHASE_SEQUENCE;
|
||||
}
|
||||
if (work_item & ROCKCHIP_EBC_WORK_ITEM_CHANGE_LUT) {
|
||||
rockchip_ebc_change_lut(ebc);
|
||||
|
|
@ -962,6 +1123,10 @@ static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc,
|
|||
ebc->driver_mode = enabling_mode;
|
||||
no_schedule_until_clip_empty = false;
|
||||
break;
|
||||
case ROCKCHIP_EBC_DRIVER_MODE_PHASE_SEQUENCE:
|
||||
rockchip_ebc_phase_sequence(ebc);
|
||||
enabling_mode = ROCKCHIP_EBC_DRIVER_MODE_ZERO_WAVEFORM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2154,6 +2319,11 @@ static int rockchip_ebc_probe(struct platform_device *pdev)
|
|||
ebc->phase[1])) {
|
||||
return dev_err_probe(dev, -ENOMEM, "Failed to allocate buffers\n");
|
||||
}
|
||||
ebc->phase_sequence = drmm_kzalloc(
|
||||
&ebc->drm, sizeof(struct drm_rockchip_ebc_phase_sequence),
|
||||
GFP_KERNEL);
|
||||
if (!ebc->phase_sequence)
|
||||
return dev_err_probe(dev, -ENOMEM, "Failed to allocate phase_sequence buffer\n");
|
||||
ebc->phase_handles[0] = dma_map_single(dev, ebc->phase[0], ebc->phase_size,
|
||||
DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(dev, ebc->phase_handles[0])) {
|
||||
|
|
@ -2199,6 +2369,7 @@ static int rockchip_ebc_probe(struct platform_device *pdev)
|
|||
|
||||
spin_lock_init(&ebc->work_item_lock);
|
||||
spin_lock_init(&ebc->hints_ioctl_lock);
|
||||
spin_lock_init(&ebc->phase_sequence_lock);
|
||||
ebc->suspend_was_requested = 0;
|
||||
|
||||
platform_set_drvdata(pdev, ebc);
|
||||
|
|
|
|||
|
|
@ -130,6 +130,8 @@ struct rockchip_ebc {
|
|||
int suspend_was_requested;
|
||||
// Cached temperature in deg C
|
||||
int temperature;
|
||||
struct drm_rockchip_ebc_phase_sequence *phase_sequence;
|
||||
spinlock_t phase_sequence_lock;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -107,7 +107,8 @@ void rockchip_ebc_schedule_advance_fast_neon(
|
|||
uint8x16_t q8_inner_new =
|
||||
vbslq_u8(q8_0x1f, q8_inner_num_new, q8_inner);
|
||||
|
||||
// These can be scheduled, send to WAITING (hint changed in the meantime)
|
||||
// These can be scheduled (next != target, next != prelim) or sent to WAITING (next == prelim, next != target)
|
||||
// TODO: merge these into a single q8_inner_num <= 1
|
||||
uint8x16_t q8_idle = vceqzq_u8(q8_inner);
|
||||
uint8x16_t q8_idle_finish =
|
||||
vorrq_u8(q8_idle, q8_inner_num_is_1);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ extern "C" {
|
|||
#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_DRIVER_MODE_PHASE_SEQUENCE 9
|
||||
|
||||
#define ROCKCHIP_EBC_DITHER_MODE_BAYER 0
|
||||
#define ROCKCHIP_EBC_DITHER_MODE_BLUE_NOISE_16 1
|
||||
|
|
@ -130,7 +131,31 @@ struct drm_rockchip_ebc_zero_waveform {
|
|||
__u8 _pad[6];
|
||||
};
|
||||
|
||||
#define DRM_ROCKCHIP_EBC_NUM_IOCTLS 0x06
|
||||
#define ROCKCHIP_EBC_MAX_PHASE_SEQUENCES 96
|
||||
#define ROCKCHIP_EBC_MAX_REGIONS 8
|
||||
|
||||
struct drm_rockchip_ebc_phase_sequence_element {
|
||||
__u32 delay_ms;
|
||||
__u8 num_frames;
|
||||
__u8 _pad[3];
|
||||
__u32 num_regions;
|
||||
struct drm_mode_rect rect[ROCKCHIP_EBC_MAX_REGIONS];
|
||||
__u8 phase[ROCKCHIP_EBC_MAX_REGIONS];
|
||||
};
|
||||
|
||||
struct drm_rockchip_ebc_phase_sequence {
|
||||
__u8 num_seqs;
|
||||
__u8 do_init;
|
||||
__u8 do_gc16;
|
||||
__u8 gc_target;
|
||||
__u8 do_force_temperature;
|
||||
__u8 force_temperature;
|
||||
__u8 _pad[6];
|
||||
__u32 delay_ms;
|
||||
struct drm_rockchip_ebc_phase_sequence_element elms[ROCKCHIP_EBC_MAX_PHASE_SEQUENCES];
|
||||
};
|
||||
|
||||
#define DRM_ROCKCHIP_EBC_NUM_IOCTLS 0x07
|
||||
|
||||
#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)
|
||||
|
|
@ -138,6 +163,7 @@ struct drm_rockchip_ebc_zero_waveform {
|
|||
#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)
|
||||
#define DRM_IOCTL_ROCKCHIP_EBC_PHASE_SEQUENCE DRM_IOW(DRM_COMMAND_BASE + 0x06, struct drm_rockchip_ebc_phase_sequence)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue