Commit 8961ca44 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'drm-fixes-for-v4.16-rc3' of git://people.freedesktop.org/~airlied/linux

Pull drm fixes from Dave Airlie:
 "A bunch of fixes for rc3:

  Exynos:
   - fixes for using monotonic timestamps
   - register definitions
   - removal of unused file

  ipu-v3L
   - minor changes
   - make some register arrays const+static
   - fix some leaks

  meson:
   - fix for vsync

  atomic:
   - fix for memory leak

  EDID parser:
   - add quirks for some more non-desktop devices
   - 6-bit panel fix.

  drm_mm:
   - fix a bug in the core drm mm hole handling

  cirrus:
   - fix lut loading regression

  Lastly there is a deadlock fix around runtime suspend for secondary
  GPUs.

  There was a deadlock between one thread trying to wait for a workqueue
  job to finish in the runtime suspend path, and the workqueue job it
  was waiting for in turn waiting for a runtime_get_sync to return.

  The fixes avoids it by not doing the runtime sync in the workqueue as
  then we always wait for all those tasks to complete before we runtime
  suspend"

* tag 'drm-fixes-for-v4.16-rc3' of git://people.freedesktop.org/~airlied/linux: (25 commits)
  drm/tve200: fix kernel-doc documentation comment include
  drm/edid: quirk Sony PlayStation VR headset as non-desktop
  drm/edid: quirk Windows Mixed Reality headsets as non-desktop
  drm/edid: quirk Oculus Rift headsets as non-desktop
  drm/meson: fix vsync buffer update
  drm: Handle unexpected holes in color-eviction
  drm: exynos: Use proper macro definition for HDMI_I2S_PIN_SEL_1
  drm/exynos: remove exynos_drm_rotator.h
  drm/exynos: g2d: Delete an error message for a failed memory allocation in two functions
  drm/exynos: fix comparison to bitshift when dealing with a mask
  drm/exynos: g2d: use monotonic timestamps
  drm/edid: Add 6 bpc quirk for CPT panel in Asus UX303LA
  gpu: ipu-csi: add 10/12-bit grayscale support to mbus_code_to_bus_cfg
  gpu: ipu-cpmem: add 16-bit grayscale support to ipu_cpmem_set_image
  gpu: ipu-v3: prg: fix device node leak in ipu_prg_lookup_by_phandle
  gpu: ipu-v3: pre: fix device node leak in ipu_pre_lookup_by_phandle
  drm/amdgpu: Fix deadlock on runtime suspend
  drm/radeon: Fix deadlock on runtime suspend
  drm/nouveau: Fix deadlock on runtime suspend
  drm: Allow determining if current task is output poll worker
  ...
parents 0f9da844 b17800e9
...@@ -3,4 +3,4 @@ ...@@ -3,4 +3,4 @@
================================== ==================================
.. kernel-doc:: drivers/gpu/drm/tve200/tve200_drv.c .. kernel-doc:: drivers/gpu/drm/tve200/tve200_drv.c
:doc: Faraday TV Encoder 200 :doc: Faraday TV Encoder TVE200 DRM Driver
...@@ -736,9 +736,11 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force) ...@@ -736,9 +736,11 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force)
enum drm_connector_status ret = connector_status_disconnected; enum drm_connector_status ret = connector_status_disconnected;
int r; int r;
if (!drm_kms_helper_is_poll_worker()) {
r = pm_runtime_get_sync(connector->dev->dev); r = pm_runtime_get_sync(connector->dev->dev);
if (r < 0) if (r < 0)
return connector_status_disconnected; return connector_status_disconnected;
}
if (encoder) { if (encoder) {
struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
...@@ -757,8 +759,12 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force) ...@@ -757,8 +759,12 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force)
/* check acpi lid status ??? */ /* check acpi lid status ??? */
amdgpu_connector_update_scratch_regs(connector, ret); amdgpu_connector_update_scratch_regs(connector, ret);
if (!drm_kms_helper_is_poll_worker()) {
pm_runtime_mark_last_busy(connector->dev->dev); pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev); pm_runtime_put_autosuspend(connector->dev->dev);
}
return ret; return ret;
} }
...@@ -868,9 +874,11 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force) ...@@ -868,9 +874,11 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force)
enum drm_connector_status ret = connector_status_disconnected; enum drm_connector_status ret = connector_status_disconnected;
int r; int r;
if (!drm_kms_helper_is_poll_worker()) {
r = pm_runtime_get_sync(connector->dev->dev); r = pm_runtime_get_sync(connector->dev->dev);
if (r < 0) if (r < 0)
return connector_status_disconnected; return connector_status_disconnected;
}
encoder = amdgpu_connector_best_single_encoder(connector); encoder = amdgpu_connector_best_single_encoder(connector);
if (!encoder) if (!encoder)
...@@ -924,8 +932,10 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force) ...@@ -924,8 +932,10 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force)
amdgpu_connector_update_scratch_regs(connector, ret); amdgpu_connector_update_scratch_regs(connector, ret);
out: out:
if (!drm_kms_helper_is_poll_worker()) {
pm_runtime_mark_last_busy(connector->dev->dev); pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev); pm_runtime_put_autosuspend(connector->dev->dev);
}
return ret; return ret;
} }
...@@ -988,9 +998,11 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) ...@@ -988,9 +998,11 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force)
enum drm_connector_status ret = connector_status_disconnected; enum drm_connector_status ret = connector_status_disconnected;
bool dret = false, broken_edid = false; bool dret = false, broken_edid = false;
if (!drm_kms_helper_is_poll_worker()) {
r = pm_runtime_get_sync(connector->dev->dev); r = pm_runtime_get_sync(connector->dev->dev);
if (r < 0) if (r < 0)
return connector_status_disconnected; return connector_status_disconnected;
}
if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) { if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
ret = connector->status; ret = connector->status;
...@@ -1115,8 +1127,10 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) ...@@ -1115,8 +1127,10 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force)
amdgpu_connector_update_scratch_regs(connector, ret); amdgpu_connector_update_scratch_regs(connector, ret);
exit: exit:
if (!drm_kms_helper_is_poll_worker()) {
pm_runtime_mark_last_busy(connector->dev->dev); pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev); pm_runtime_put_autosuspend(connector->dev->dev);
}
return ret; return ret;
} }
...@@ -1359,9 +1373,11 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force) ...@@ -1359,9 +1373,11 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force)
struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector); struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
int r; int r;
if (!drm_kms_helper_is_poll_worker()) {
r = pm_runtime_get_sync(connector->dev->dev); r = pm_runtime_get_sync(connector->dev->dev);
if (r < 0) if (r < 0)
return connector_status_disconnected; return connector_status_disconnected;
}
if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) { if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
ret = connector->status; ret = connector->status;
...@@ -1429,8 +1445,10 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force) ...@@ -1429,8 +1445,10 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force)
amdgpu_connector_update_scratch_regs(connector, ret); amdgpu_connector_update_scratch_regs(connector, ret);
out: out:
if (!drm_kms_helper_is_poll_worker()) {
pm_runtime_mark_last_busy(connector->dev->dev); pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev); pm_runtime_put_autosuspend(connector->dev->dev);
}
return ret; return ret;
} }
......
...@@ -294,22 +294,7 @@ static void cirrus_crtc_prepare(struct drm_crtc *crtc) ...@@ -294,22 +294,7 @@ static void cirrus_crtc_prepare(struct drm_crtc *crtc)
{ {
} }
/* static void cirrus_crtc_load_lut(struct drm_crtc *crtc)
* This is called after a mode is programmed. It should reverse anything done
* by the prepare function
*/
static void cirrus_crtc_commit(struct drm_crtc *crtc)
{
}
/*
* The core can pass us a set of gamma values to program. We actually only
* use this for 8-bit mode so can't perform smooth fades on deeper modes,
* but it's a requirement that we provide the function
*/
static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
u16 *blue, uint32_t size,
struct drm_modeset_acquire_ctx *ctx)
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct cirrus_device *cdev = dev->dev_private; struct cirrus_device *cdev = dev->dev_private;
...@@ -317,7 +302,7 @@ static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, ...@@ -317,7 +302,7 @@ static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
int i; int i;
if (!crtc->enabled) if (!crtc->enabled)
return 0; return;
r = crtc->gamma_store; r = crtc->gamma_store;
g = r + crtc->gamma_size; g = r + crtc->gamma_size;
...@@ -330,6 +315,27 @@ static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, ...@@ -330,6 +315,27 @@ static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
WREG8(PALETTE_DATA, *g++ >> 8); WREG8(PALETTE_DATA, *g++ >> 8);
WREG8(PALETTE_DATA, *b++ >> 8); WREG8(PALETTE_DATA, *b++ >> 8);
} }
}
/*
* This is called after a mode is programmed. It should reverse anything done
* by the prepare function
*/
static void cirrus_crtc_commit(struct drm_crtc *crtc)
{
cirrus_crtc_load_lut(crtc);
}
/*
* The core can pass us a set of gamma values to program. We actually only
* use this for 8-bit mode so can't perform smooth fades on deeper modes,
* but it's a requirement that we provide the function
*/
static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
u16 *blue, uint32_t size,
struct drm_modeset_acquire_ctx *ctx)
{
cirrus_crtc_load_lut(crtc);
return 0; return 0;
} }
......
...@@ -1878,6 +1878,8 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, ...@@ -1878,6 +1878,8 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
new_crtc_state->event->base.completion = &commit->flip_done; new_crtc_state->event->base.completion = &commit->flip_done;
new_crtc_state->event->base.completion_release = release_crtc_commit; new_crtc_state->event->base.completion_release = release_crtc_commit;
drm_crtc_commit_get(commit); drm_crtc_commit_get(commit);
commit->abort_completion = true;
} }
for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) { for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) {
...@@ -3421,8 +3423,21 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state); ...@@ -3421,8 +3423,21 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state) void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state)
{ {
if (state->commit) { if (state->commit) {
/*
* In the event that a non-blocking commit returns
* -ERESTARTSYS before the commit_tail work is queued, we will
* have an extra reference to the commit object. Release it, if
* the event has not been consumed by the worker.
*
* state->event may be freed, so we can't directly look at
* state->event->base.completion.
*/
if (state->event && state->commit->abort_completion)
drm_crtc_commit_put(state->commit);
kfree(state->commit->event); kfree(state->commit->event);
state->commit->event = NULL; state->commit->event = NULL;
drm_crtc_commit_put(state->commit); drm_crtc_commit_put(state->commit);
} }
......
...@@ -113,6 +113,9 @@ static const struct edid_quirk { ...@@ -113,6 +113,9 @@ static const struct edid_quirk {
/* AEO model 0 reports 8 bpc, but is a 6 bpc panel */ /* AEO model 0 reports 8 bpc, but is a 6 bpc panel */
{ "AEO", 0, EDID_QUIRK_FORCE_6BPC }, { "AEO", 0, EDID_QUIRK_FORCE_6BPC },
/* CPT panel of Asus UX303LA reports 8 bpc, but is a 6 bpc panel */
{ "CPT", 0x17df, EDID_QUIRK_FORCE_6BPC },
/* Belinea 10 15 55 */ /* Belinea 10 15 55 */
{ "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 }, { "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 },
{ "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 }, { "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 },
...@@ -162,6 +165,24 @@ static const struct edid_quirk { ...@@ -162,6 +165,24 @@ static const struct edid_quirk {
/* HTC Vive VR Headset */ /* HTC Vive VR Headset */
{ "HVR", 0xaa01, EDID_QUIRK_NON_DESKTOP }, { "HVR", 0xaa01, EDID_QUIRK_NON_DESKTOP },
/* Oculus Rift DK1, DK2, and CV1 VR Headsets */
{ "OVR", 0x0001, EDID_QUIRK_NON_DESKTOP },
{ "OVR", 0x0003, EDID_QUIRK_NON_DESKTOP },
{ "OVR", 0x0004, EDID_QUIRK_NON_DESKTOP },
/* Windows Mixed Reality Headsets */
{ "ACR", 0x7fce, EDID_QUIRK_NON_DESKTOP },
{ "HPN", 0x3515, EDID_QUIRK_NON_DESKTOP },
{ "LEN", 0x0408, EDID_QUIRK_NON_DESKTOP },
{ "LEN", 0xb800, EDID_QUIRK_NON_DESKTOP },
{ "FUJ", 0x1970, EDID_QUIRK_NON_DESKTOP },
{ "DEL", 0x7fce, EDID_QUIRK_NON_DESKTOP },
{ "SEC", 0x144a, EDID_QUIRK_NON_DESKTOP },
{ "AUS", 0xc102, EDID_QUIRK_NON_DESKTOP },
/* Sony PlayStation VR Headset */
{ "SNY", 0x0704, EDID_QUIRK_NON_DESKTOP },
}; };
/* /*
......
...@@ -836,10 +836,25 @@ struct drm_mm_node *drm_mm_scan_color_evict(struct drm_mm_scan *scan) ...@@ -836,10 +836,25 @@ struct drm_mm_node *drm_mm_scan_color_evict(struct drm_mm_scan *scan)
if (!mm->color_adjust) if (!mm->color_adjust)
return NULL; return NULL;
hole = list_first_entry(&mm->hole_stack, typeof(*hole), hole_stack); /*
* The hole found during scanning should ideally be the first element
* in the hole_stack list, but due to side-effects in the driver it
* may not be.
*/
list_for_each_entry(hole, &mm->hole_stack, hole_stack) {
hole_start = __drm_mm_hole_node_start(hole); hole_start = __drm_mm_hole_node_start(hole);
hole_end = hole_start + hole->hole_size; hole_end = hole_start + hole->hole_size;
if (hole_start <= scan->hit_start &&
hole_end >= scan->hit_end)
break;
}
/* We should only be called after we found the hole previously */
DRM_MM_BUG_ON(&hole->hole_stack == &mm->hole_stack);
if (unlikely(&hole->hole_stack == &mm->hole_stack))
return NULL;
DRM_MM_BUG_ON(hole_start > scan->hit_start); DRM_MM_BUG_ON(hole_start > scan->hit_start);
DRM_MM_BUG_ON(hole_end < scan->hit_end); DRM_MM_BUG_ON(hole_end < scan->hit_end);
......
...@@ -653,6 +653,26 @@ static void output_poll_execute(struct work_struct *work) ...@@ -653,6 +653,26 @@ static void output_poll_execute(struct work_struct *work)
schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD); schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD);
} }
/**
* drm_kms_helper_is_poll_worker - is %current task an output poll worker?
*
* Determine if %current task is an output poll worker. This can be used
* to select distinct code paths for output polling versus other contexts.
*
* One use case is to avoid a deadlock between the output poll worker and
* the autosuspend worker wherein the latter waits for polling to finish
* upon calling drm_kms_helper_poll_disable(), while the former waits for
* runtime suspend to finish upon calling pm_runtime_get_sync() in a
* connector ->detect hook.
*/
bool drm_kms_helper_is_poll_worker(void)
{
struct work_struct *work = current_work();
return work && work->func == output_poll_execute;
}
EXPORT_SYMBOL(drm_kms_helper_is_poll_worker);
/** /**
* drm_kms_helper_poll_disable - disable output polling * drm_kms_helper_poll_disable - disable output polling
* @dev: drm_device * @dev: drm_device
......
...@@ -286,7 +286,6 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) ...@@ -286,7 +286,6 @@ static int g2d_init_cmdlist(struct g2d_data *g2d)
node = kcalloc(G2D_CMDLIST_NUM, sizeof(*node), GFP_KERNEL); node = kcalloc(G2D_CMDLIST_NUM, sizeof(*node), GFP_KERNEL);
if (!node) { if (!node) {
dev_err(dev, "failed to allocate memory\n");
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;
} }
...@@ -926,7 +925,7 @@ static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no) ...@@ -926,7 +925,7 @@ static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no)
struct drm_device *drm_dev = g2d->subdrv.drm_dev; struct drm_device *drm_dev = g2d->subdrv.drm_dev;
struct g2d_runqueue_node *runqueue_node = g2d->runqueue_node; struct g2d_runqueue_node *runqueue_node = g2d->runqueue_node;
struct drm_exynos_pending_g2d_event *e; struct drm_exynos_pending_g2d_event *e;
struct timeval now; struct timespec64 now;
if (list_empty(&runqueue_node->event_list)) if (list_empty(&runqueue_node->event_list))
return; return;
...@@ -934,9 +933,9 @@ static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no) ...@@ -934,9 +933,9 @@ static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no)
e = list_first_entry(&runqueue_node->event_list, e = list_first_entry(&runqueue_node->event_list,
struct drm_exynos_pending_g2d_event, base.link); struct drm_exynos_pending_g2d_event, base.link);
do_gettimeofday(&now); ktime_get_ts64(&now);
e->event.tv_sec = now.tv_sec; e->event.tv_sec = now.tv_sec;
e->event.tv_usec = now.tv_usec; e->event.tv_usec = now.tv_nsec / NSEC_PER_USEC;
e->event.cmdlist_no = cmdlist_no; e->event.cmdlist_no = cmdlist_no;
drm_send_event(drm_dev, &e->base); drm_send_event(drm_dev, &e->base);
...@@ -1358,10 +1357,9 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data, ...@@ -1358,10 +1357,9 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data,
return -EFAULT; return -EFAULT;
runqueue_node = kmem_cache_alloc(g2d->runqueue_slab, GFP_KERNEL); runqueue_node = kmem_cache_alloc(g2d->runqueue_slab, GFP_KERNEL);
if (!runqueue_node) { if (!runqueue_node)
dev_err(dev, "failed to allocate memory\n");
return -ENOMEM; return -ENOMEM;
}
run_cmdlist = &runqueue_node->run_cmdlist; run_cmdlist = &runqueue_node->run_cmdlist;
event_list = &runqueue_node->event_list; event_list = &runqueue_node->event_list;
INIT_LIST_HEAD(run_cmdlist); INIT_LIST_HEAD(run_cmdlist);
......
/*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
*
* Authors:
* YoungJun Cho <yj44.cho@samsung.com>
* Eunchul Kim <chulspro.kim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DRM_ROTATOR_H_
#define _EXYNOS_DRM_ROTATOR_H_
/* TODO */
#endif
...@@ -1068,10 +1068,13 @@ static void hdmi_audio_config(struct hdmi_context *hdata) ...@@ -1068,10 +1068,13 @@ static void hdmi_audio_config(struct hdmi_context *hdata)
/* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */ /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5) hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
| HDMI_I2S_SEL_LRCK(6)); | HDMI_I2S_SEL_LRCK(6));
hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
| HDMI_I2S_SEL_SDATA2(4)); hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(3)
| HDMI_I2S_SEL_SDATA0(4));
hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1) hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
| HDMI_I2S_SEL_SDATA2(2)); | HDMI_I2S_SEL_SDATA2(2));
hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0)); hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
/* I2S_CON_1 & 2 */ /* I2S_CON_1 & 2 */
......
...@@ -569,7 +569,7 @@ ...@@ -569,7 +569,7 @@
#define EXYNOS_CIIMGEFF_FIN_EMBOSSING (4 << 26) #define EXYNOS_CIIMGEFF_FIN_EMBOSSING (4 << 26)
#define EXYNOS_CIIMGEFF_FIN_SILHOUETTE (5 << 26) #define EXYNOS_CIIMGEFF_FIN_SILHOUETTE (5 << 26)
#define EXYNOS_CIIMGEFF_FIN_MASK (7 << 26) #define EXYNOS_CIIMGEFF_FIN_MASK (7 << 26)
#define EXYNOS_CIIMGEFF_PAT_CBCR_MASK ((0xff < 13) | (0xff < 0)) #define EXYNOS_CIIMGEFF_PAT_CBCR_MASK ((0xff << 13) | (0xff << 0))
/* Real input DMA size register */ /* Real input DMA size register */
#define EXYNOS_CIREAL_ISIZE_AUTOLOAD_ENABLE (1 << 31) #define EXYNOS_CIREAL_ISIZE_AUTOLOAD_ENABLE (1 << 31)
......
...@@ -464,7 +464,7 @@ ...@@ -464,7 +464,7 @@
/* I2S_PIN_SEL_1 */ /* I2S_PIN_SEL_1 */
#define HDMI_I2S_SEL_SDATA1(x) (((x) & 0x7) << 4) #define HDMI_I2S_SEL_SDATA1(x) (((x) & 0x7) << 4)
#define HDMI_I2S_SEL_SDATA2(x) ((x) & 0x7) #define HDMI_I2S_SEL_SDATA0(x) ((x) & 0x7)
/* I2S_PIN_SEL_2 */ /* I2S_PIN_SEL_2 */
#define HDMI_I2S_SEL_SDATA3(x) (((x) & 0x7) << 4) #define HDMI_I2S_SEL_SDATA3(x) (((x) & 0x7) << 4)
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "meson_venc.h" #include "meson_venc.h"
#include "meson_vpp.h" #include "meson_vpp.h"
#include "meson_viu.h" #include "meson_viu.h"
#include "meson_canvas.h"
#include "meson_registers.h" #include "meson_registers.h"
/* CRTC definition */ /* CRTC definition */
...@@ -192,6 +193,11 @@ void meson_crtc_irq(struct meson_drm *priv) ...@@ -192,6 +193,11 @@ void meson_crtc_irq(struct meson_drm *priv)
} else } else
meson_vpp_disable_interlace_vscaler_osd1(priv); meson_vpp_disable_interlace_vscaler_osd1(priv);
meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1,
priv->viu.osd1_addr, priv->viu.osd1_stride,
priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE,
MESON_CANVAS_BLKMODE_LINEAR);
/* Enable OSD1 */ /* Enable OSD1 */
writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND,
priv->io_base + _REG(VPP_MISC)); priv->io_base + _REG(VPP_MISC));
......
...@@ -43,6 +43,9 @@ struct meson_drm { ...@@ -43,6 +43,9 @@ struct meson_drm {
bool osd1_commit; bool osd1_commit;
uint32_t osd1_ctrl_stat; uint32_t osd1_ctrl_stat;
uint32_t osd1_blk0_cfg[5]; uint32_t osd1_blk0_cfg[5];
uint32_t osd1_addr;
uint32_t osd1_stride;
uint32_t osd1_height;
} viu; } viu;
struct { struct {
......
...@@ -164,10 +164,9 @@ static void meson_plane_atomic_update(struct drm_plane *plane, ...@@ -164,10 +164,9 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
/* Update Canvas with buffer address */ /* Update Canvas with buffer address */
gem = drm_fb_cma_get_gem_obj(fb, 0); gem = drm_fb_cma_get_gem_obj(fb, 0);
meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1, priv->viu.osd1_addr = gem->paddr;
gem->paddr, fb->pitches[0], priv->viu.osd1_stride = fb->pitches[0];
fb->height, MESON_CANVAS_WRAP_NONE, priv->viu.osd1_height = fb->height;
MESON_CANVAS_BLKMODE_LINEAR);
spin_unlock_irqrestore(&priv->drm->event_lock, flags); spin_unlock_irqrestore(&priv->drm->event_lock, flags);
} }
......
...@@ -570,9 +570,15 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) ...@@ -570,9 +570,15 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
nv_connector->edid = NULL; nv_connector->edid = NULL;
} }
/* Outputs are only polled while runtime active, so acquiring a
* runtime PM ref here is unnecessary (and would deadlock upon
* runtime suspend because it waits for polling to finish).
*/
if (!drm_kms_helper_is_poll_worker()) {
ret = pm_runtime_get_sync(connector->dev->dev); ret = pm_runtime_get_sync(connector->dev->dev);
if (ret < 0 && ret != -EACCES) if (ret < 0 && ret != -EACCES)
return conn_status; return conn_status;
}
nv_encoder = nouveau_connector_ddc_detect(connector); nv_encoder = nouveau_connector_ddc_detect(connector);
if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) { if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) {
...@@ -647,8 +653,10 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) ...@@ -647,8 +653,10 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
out: out:
if (!drm_kms_helper_is_poll_worker()) {
pm_runtime_mark_last_busy(connector->dev->dev); pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev); pm_runtime_put_autosuspend(connector->dev->dev);
}
return conn_status; return conn_status;
} }
......
...@@ -899,9 +899,11 @@ radeon_lvds_detect(struct drm_connector *connector, bool force) ...@@ -899,9 +899,11 @@ radeon_lvds_detect(struct drm_connector *connector, bool force)
enum drm_connector_status ret = connector_status_disconnected; enum drm_connector_status ret = connector_status_disconnected;
int r; int r;
if (!drm_kms_helper_is_poll_worker()) {
r = pm_runtime_get_sync(connector->dev->dev); r = pm_runtime_get_sync(connector->dev->dev);
if (r < 0) if (r < 0)
return connector_status_disconnected; return connector_status_disconnected;
}
if (encoder) { if (encoder) {
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
...@@ -924,8 +926,12 @@ radeon_lvds_detect(struct drm_connector *connector, bool force) ...@@ -924,8 +926,12 @@ radeon_lvds_detect(struct drm_connector *connector, bool force)
/* check acpi lid status ??? */ /* check acpi lid status ??? */
radeon_connector_update_scratch_regs(connector, ret); radeon_connector_update_scratch_regs(connector, ret);
if (!drm_kms_helper_is_poll_worker()) {
pm_runtime_mark_last_busy(connector->dev->dev); pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev); pm_runtime_put_autosuspend(connector->dev->dev);
}
return ret; return ret;
} }
...@@ -1039,9 +1045,11 @@ radeon_vga_detect(struct drm_connector *connector, bool force) ...@@ -1039,9 +1045,11 @@ radeon_vga_detect(struct drm_connector *connector, bool force)
enum drm_connector_status ret = connector_status_disconnected; enum drm_connector_status ret = connector_status_disconnected;
int r; int r;
if (!drm_kms_helper_is_poll_worker()) {
r = pm_runtime_get_sync(connector->dev->dev); r = pm_runtime_get_sync(connector->dev->dev);
if (r < 0) if (r < 0)
return connector_status_disconnected; return connector_status_disconnected;
}
encoder = radeon_best_single_encoder(connector); encoder = radeon_best_single_encoder(connector);
if (!encoder) if (!encoder)
...@@ -1108,8 +1116,10 @@ radeon_vga_detect(struct drm_connector *connector, bool force) ...@@ -1108,8 +1116,10 @@ radeon_vga_detect(struct drm_connector *connector, bool force)
radeon_connector_update_scratch_regs(connector, ret); radeon_connector_update_scratch_regs(connector, ret);
out: out:
if (!drm_kms_helper_is_poll_worker()) {
pm_runtime_mark_last_busy(connector->dev->dev); pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev); pm_runtime_put_autosuspend(connector->dev->dev);
}
return ret; return ret;
} }
...@@ -1173,9 +1183,11 @@ radeon_tv_detect(struct drm_connector *connector, bool force) ...@@ -1173,9 +1183,11 @@ radeon_tv_detect(struct drm_connector *connector, bool force)
if (!radeon_connector->dac_load_detect) if (!radeon_connector->dac_load_detect)
return ret; return ret;
if (!drm_kms_helper_is_poll_worker()) {
r = pm_runtime_get_sync(connector->dev->dev); r = pm_runtime_get_sync(connector->dev->dev);
if (r < 0) if (r < 0)
return connector_status_disconnected; return connector_status_disconnected;
}
encoder = radeon_best_single_encoder(connector); encoder = radeon_best_single_encoder(connector);
if (!encoder) if (!encoder)
...@@ -1187,8 +1199,12 @@ radeon_tv_detect(struct drm_connector *connector, bool force) ...@@ -1187,8 +1199,12 @@ radeon_tv_detect(struct drm_connector *connector, bool force)
if (ret == connector_status_connected) if (ret == connector_status_connected)
ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false); ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false);
radeon_connector_update_scratch_regs(connector, ret); radeon_connector_update_scratch_regs(connector, ret);
if (!drm_kms_helper_is_poll_worker()) {
pm_runtime_mark_last_busy(connector->dev->dev); pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev); pm_runtime_put_autosuspend(connector->dev->dev);
}
return ret; return ret;
} }
...@@ -1251,9 +1267,11 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) ...@@ -1251,9 +1267,11 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
enum drm_connector_status ret = connector_status_disconnected; enum drm_connector_status ret = connector_status_disconnected;
bool dret = false, broken_edid = false; bool dret = false, broken_edid = false;
if (!drm_kms_helper_is_poll_worker()) {
r = pm_runtime_get_sync(connector->dev->dev); r = pm_runtime_get_sync(connector->dev->dev);
if (r < 0) if (r < 0)
return connector_status_disconnected; return connector_status_disconnected;
}
if (radeon_connector->detected_hpd_without_ddc) { if (radeon_connector->detected_hpd_without_ddc) {
force = true; force = true;
...@@ -1436,8 +1454,10 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) ...@@ -1436,8 +1454,10 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
} }
exit: exit:
if (!drm_kms_helper_is_poll_worker()) {
pm_runtime_mark_last_busy(connector->dev->dev); pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev); pm_runtime_put_autosuspend(connector->dev->dev);
}
return ret; return ret;
} }
...@@ -1688,9 +1708,11 @@ radeon_dp_detect(struct drm_connector *connector, bool force) ...@@ -1688,9 +1708,11 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
if (radeon_dig_connector->is_mst) if (radeon_dig_connector->is_mst)
return connector_status_disconnected; return connector_status_disconnected;
if (!drm_kms_helper_is_poll_worker()) {
r = pm_runtime_get_sync(connector->dev->dev); r = pm_runtime_get_sync(connector->dev->dev);
if (r < 0) if (r < 0)
return connector_status_disconnected; return connector_status_disconnected;
}
if (!force && radeon_check_hpd_status_unchanged(connector)) { if (!force && radeon_check_hpd_status_unchanged(connector)) {
ret = connector->status; ret = connector->status;
...@@ -1777,8 +1799,10 @@ radeon_dp_detect(struct drm_connector *connector, bool force) ...@@ -1777,8 +1799,10 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
} }
out: out:
if (!drm_kms_helper_is_poll_worker()) {
pm_runtime_mark_last_busy(connector->dev->dev); pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev); pm_runtime_put_autosuspend(connector->dev->dev);
}
return ret; return ret;
} }
......
...@@ -1089,7 +1089,7 @@ static void ipu_irq_handler(struct irq_desc *desc) ...@@ -1089,7 +1089,7 @@ static void ipu_irq_handler(struct irq_desc *desc)
{ {
struct ipu_soc *ipu = irq_desc_get_handler_data(desc); struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc); struct irq_chip *chip = irq_desc_get_chip(desc);
const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14}; static const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14};
chained_irq_enter(chip, desc); chained_irq_enter(chip, desc);
...@@ -1102,7 +1102,7 @@ static void ipu_err_irq_handler(struct irq_desc *desc) ...@@ -1102,7 +1102,7 @@ static void ipu_err_irq_handler(struct irq_desc *desc)
{ {
struct ipu_soc *ipu = irq_desc_get_handler_data(desc); struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc); struct irq_chip *chip = irq_desc_get_chip(desc);
const int int_reg[] = { 4, 5, 8, 9}; static const int int_reg[] = { 4, 5, 8, 9};
chained_irq_enter(chip, desc); chained_irq_enter(chip, desc);
......
...@@ -788,12 +788,14 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image) ...@@ -788,12 +788,14 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
case V4L2_PIX_FMT_SGBRG8: case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8: case V4L2_PIX_FMT_SGRBG8:
case V4L2_PIX_FMT_SRGGB8: case V4L2_PIX_FMT_SRGGB8:
case V4L2_PIX_FMT_GREY:
offset = image->rect.left + image->rect.top * pix->bytesperline; offset = image->rect.left + image->rect.top * pix->bytesperline;
break; break;
case V4L2_PIX_FMT_SBGGR16: case V4L2_PIX_FMT_SBGGR16:
case V4L2_PIX_FMT_SGBRG16: case V4L2_PIX_FMT_SGBRG16:
case V4L2_PIX_FMT_SGRBG16: case V4L2_PIX_FMT_SGRBG16:
case V4L2_PIX_FMT_SRGGB16: case V4L2_PIX_FMT_SRGGB16:
case V4L2_PIX_FMT_Y16:
offset = image->rect.left * 2 + offset = image->rect.left * 2 +
image->rect.top * pix->bytesperline; image->rect.top * pix->bytesperline;
break; break;
......
...@@ -288,6 +288,7 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code) ...@@ -288,6 +288,7 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code)
case MEDIA_BUS_FMT_SGBRG10_1X10: case MEDIA_BUS_FMT_SGBRG10_1X10:
case MEDIA_BUS_FMT_SGRBG10_1X10: case MEDIA_BUS_FMT_SGRBG10_1X10:
case MEDIA_BUS_FMT_SRGGB10_1X10: case MEDIA_BUS_FMT_SRGGB10_1X10:
case MEDIA_BUS_FMT_Y10_1X10:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
cfg->mipi_dt = MIPI_DT_RAW10; cfg->mipi_dt = MIPI_DT_RAW10;
cfg->data_width = IPU_CSI_DATA_WIDTH_10; cfg->data_width = IPU_CSI_DATA_WIDTH_10;
...@@ -296,6 +297,7 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code) ...@@ -296,6 +297,7 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code)
case MEDIA_BUS_FMT_SGBRG12_1X12: case MEDIA_BUS_FMT_SGBRG12_1X12:
case MEDIA_BUS_FMT_SGRBG12_1X12: case MEDIA_BUS_FMT_SGRBG12_1X12:
case MEDIA_BUS_FMT_SRGGB12_1X12: case MEDIA_BUS_FMT_SRGGB12_1X12:
case MEDIA_BUS_FMT_Y12_1X12:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
cfg->mipi_dt = MIPI_DT_RAW12; cfg->mipi_dt = MIPI_DT_RAW12;
cfg->data_width = IPU_CSI_DATA_WIDTH_12; cfg->data_width = IPU_CSI_DATA_WIDTH_12;
......
...@@ -129,11 +129,14 @@ ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index) ...@@ -129,11 +129,14 @@ ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index)
if (pre_node == pre->dev->of_node) { if (pre_node == pre->dev->of_node) {
mutex_unlock(&ipu_pre_list_mutex); mutex_unlock(&ipu_pre_list_mutex);
device_link_add(dev, pre->dev, DL_FLAG_AUTOREMOVE); device_link_add(dev, pre->dev, DL_FLAG_AUTOREMOVE);
of_node_put(pre_node);
return pre; return pre;
} }
} }
mutex_unlock(&ipu_pre_list_mutex); mutex_unlock(&ipu_pre_list_mutex);
of_node_put(pre_node);
return NULL; return NULL;
} }
......
...@@ -102,11 +102,14 @@ ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id) ...@@ -102,11 +102,14 @@ ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id)
mutex_unlock(&ipu_prg_list_mutex); mutex_unlock(&ipu_prg_list_mutex);
device_link_add(dev, prg->dev, DL_FLAG_AUTOREMOVE); device_link_add(dev, prg->dev, DL_FLAG_AUTOREMOVE);
prg->id = ipu_id; prg->id = ipu_id;
of_node_put(prg_node);
return prg; return prg;
} }
} }
mutex_unlock(&ipu_prg_list_mutex); mutex_unlock(&ipu_prg_list_mutex);
of_node_put(prg_node);
return NULL; return NULL;
} }
......
...@@ -134,6 +134,15 @@ struct drm_crtc_commit { ...@@ -134,6 +134,15 @@ struct drm_crtc_commit {
* &drm_pending_vblank_event pointer to clean up private events. * &drm_pending_vblank_event pointer to clean up private events.
*/ */
struct drm_pending_vblank_event *event; struct drm_pending_vblank_event *event;
/**
* @abort_completion:
*
* A flag that's set after drm_atomic_helper_setup_commit takes a second
* reference for the completion of $drm_crtc_state.event. It's used by
* the free code to remove the second reference if commit fails.
*/
bool abort_completion;
}; };
struct __drm_planes_state { struct __drm_planes_state {
......
...@@ -77,5 +77,6 @@ void drm_kms_helper_hotplug_event(struct drm_device *dev); ...@@ -77,5 +77,6 @@ void drm_kms_helper_hotplug_event(struct drm_device *dev);
void drm_kms_helper_poll_disable(struct drm_device *dev); void drm_kms_helper_poll_disable(struct drm_device *dev);
void drm_kms_helper_poll_enable(struct drm_device *dev); void drm_kms_helper_poll_enable(struct drm_device *dev);
bool drm_kms_helper_is_poll_worker(void);
#endif #endif
...@@ -465,6 +465,7 @@ extern bool cancel_delayed_work_sync(struct delayed_work *dwork); ...@@ -465,6 +465,7 @@ extern bool cancel_delayed_work_sync(struct delayed_work *dwork);
extern void workqueue_set_max_active(struct workqueue_struct *wq, extern void workqueue_set_max_active(struct workqueue_struct *wq,
int max_active); int max_active);
extern struct work_struct *current_work(void);
extern bool current_is_workqueue_rescuer(void); extern bool current_is_workqueue_rescuer(void);
extern bool workqueue_congested(int cpu, struct workqueue_struct *wq); extern bool workqueue_congested(int cpu, struct workqueue_struct *wq);
extern unsigned int work_busy(struct work_struct *work); extern unsigned int work_busy(struct work_struct *work);
......
...@@ -4179,6 +4179,22 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active) ...@@ -4179,6 +4179,22 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active)
} }
EXPORT_SYMBOL_GPL(workqueue_set_max_active); EXPORT_SYMBOL_GPL(workqueue_set_max_active);
/**
* current_work - retrieve %current task's work struct
*
* Determine if %current task is a workqueue worker and what it's working on.
* Useful to find out the context that the %current task is running in.
*
* Return: work struct if %current task is a workqueue worker, %NULL otherwise.
*/
struct work_struct *current_work(void)
{
struct worker *worker = current_wq_worker();
return worker ? worker->current_work : NULL;
}
EXPORT_SYMBOL(current_work);
/** /**
* current_is_workqueue_rescuer - is %current workqueue rescuer? * current_is_workqueue_rescuer - is %current workqueue rescuer?
* *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment