Merge tag 'topic/drm-misc-2016-02-18' of git://anongit.freedesktop.org/drm-intel into drm-next

Misc stuff all over:
- more mode_fixup removal from Carlos, there's another final pile still
  left.
- final bits of vgaswitcheroo from Lukas for apple gmux, we're still
  discussing an api cleanup patch to make it a bit more abuse-safe as a
  follow-up
- dp aux interface for userspace for tools&tests from Rafael Antognolli
- actual interface parts for dma-buf flushing for userspace mmap
- few small bits all over

- vgaswitcheroo support for apple gmux from Lukas Wunner
- checks for ->mode_fixup in non-atomic helpers from Carlos Palminha, plus
  removing dummy funcs from drivers. Carlos promised to follow up with
  more, since there's lots more silly dummy functions around.
- dma-buf patches from Tiago, except the ioctl itself (that needed a
  respin to address review from David Herrmann)
- encoder mask for atomic from Maarten
- bunch of random things all over.

* tag 'topic/drm-misc-2016-02-18' of git://anongit.freedesktop.org/drm-intel: (57 commits)
  drm/udl: Use module_usb_driver
  drm: fixes crct set_mode when crtc mode_fixup is null.
  drm/tilcdc: removed optional dummy encoder mode_fixup function.
  drm/sti: removed optional dummy encoder mode_fixup function.
  drm/rockchip: removed optional dummy encoder mode_fixup function.
  drm/qxl: removed optional dummy encoder mode_fixup function.
  drm/mgag200: removed optional dummy encoder mode_fixup function.
  drm/msm/mdp: removed optional dummy encoder mode_fixup function.
  drm/imx: removed optional dummy encoder mode_fixup function.
  drm/gma500: removed optional dummy encoder mode_fixup function.
  drm/radeon: removed optional dummy encoder mode_fixup function.
  drm/cirrus: removed optional dummy encoder mode_fixup function.
  drm/bochs: removed optional dummy encoder mode_fixup function.
  drm/ast: removed optional dummy encoder mode_fixup function.
  drm/amdgpu: removed optional dummy encoder mode_fixup function.
  drm/exynos: removed optional dummy encoder mode_fixup function.
  drm/udl: removed optional dummy encoder mode_fixup function.
  drm/virtio: removed optional dummy encoder mode_fixup function.
  drm/fb_helper: Use add_one_connector in add_all_connectors.
  drm/fb_helper: Use correct allocation count for arrays.
  ...
This commit is contained in:
Dave Airlie 2016-02-19 10:57:44 +10:00
commit 08244c0085
83 changed files with 1262 additions and 430 deletions

View File

@ -3422,6 +3422,7 @@ int num_ioctls;</synopsis>
</sect1> </sect1>
<sect1> <sect1>
<title>Public constants</title> <title>Public constants</title>
!Finclude/linux/vga_switcheroo.h vga_switcheroo_handler_flags_t
!Finclude/linux/vga_switcheroo.h vga_switcheroo_client_id !Finclude/linux/vga_switcheroo.h vga_switcheroo_client_id
!Finclude/linux/vga_switcheroo.h vga_switcheroo_state !Finclude/linux/vga_switcheroo.h vga_switcheroo_state
</sect1> </sect1>
@ -3450,6 +3451,10 @@ int num_ioctls;</synopsis>
<title>Backlight control</title> <title>Backlight control</title>
!Pdrivers/platform/x86/apple-gmux.c Backlight control !Pdrivers/platform/x86/apple-gmux.c Backlight control
</sect2> </sect2>
<sect2>
<title>Public functions</title>
!Iinclude/linux/apple-gmux.h
</sect2>
</sect1> </sect1>
</chapter> </chapter>

View File

@ -257,17 +257,15 @@ Access to a dma_buf from the kernel context involves three steps:
Interface: Interface:
int dma_buf_begin_cpu_access(struct dma_buf *dmabuf, int dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
size_t start, size_t len,
enum dma_data_direction direction) enum dma_data_direction direction)
This allows the exporter to ensure that the memory is actually available for This allows the exporter to ensure that the memory is actually available for
cpu access - the exporter might need to allocate or swap-in and pin the cpu access - the exporter might need to allocate or swap-in and pin the
backing storage. The exporter also needs to ensure that cpu access is backing storage. The exporter also needs to ensure that cpu access is
coherent for the given range and access direction. The range and access coherent for the access direction. The direction can be used by the exporter
direction can be used by the exporter to optimize the cache flushing, i.e. to optimize the cache flushing, i.e. access with a different direction (read
access outside of the range or with a different direction (read instead of instead of write) might return stale or even bogus data (e.g. when the
write) might return stale or even bogus data (e.g. when the exporter needs to exporter needs to copy the data to temporary storage).
copy the data to temporary storage).
This step might fail, e.g. in oom conditions. This step might fail, e.g. in oom conditions.
@ -322,14 +320,13 @@ Access to a dma_buf from the kernel context involves three steps:
3. Finish access 3. Finish access
When the importer is done accessing the range specified in begin_cpu_access, When the importer is done accessing the CPU, it needs to announce this to
it needs to announce this to the exporter (to facilitate cache flushing and the exporter (to facilitate cache flushing and unpinning of any pinned
unpinning of any pinned resources). The result of any dma_buf kmap calls resources). The result of any dma_buf kmap calls after end_cpu_access is
after end_cpu_access is undefined. undefined.
Interface: Interface:
void dma_buf_end_cpu_access(struct dma_buf *dma_buf, void dma_buf_end_cpu_access(struct dma_buf *dma_buf,
size_t start, size_t len,
enum dma_data_direction dir); enum dma_data_direction dir);
@ -353,7 +350,26 @@ Being able to mmap an export dma-buf buffer object has 2 main use-cases:
handles, too). So it's beneficial to support this in a similar fashion on handles, too). So it's beneficial to support this in a similar fashion on
dma-buf to have a good transition path for existing Android userspace. dma-buf to have a good transition path for existing Android userspace.
No special interfaces, userspace simply calls mmap on the dma-buf fd. No special interfaces, userspace simply calls mmap on the dma-buf fd, making
sure that the cache synchronization ioctl (DMA_BUF_IOCTL_SYNC) is *always*
used when the access happens. This is discussed next paragraphs.
Some systems might need some sort of cache coherency management e.g. when
CPU and GPU domains are being accessed through dma-buf at the same time. To
circumvent this problem there are begin/end coherency markers, that forward
directly to existing dma-buf device drivers vfunc hooks. Userspace can make
use of those markers through the DMA_BUF_IOCTL_SYNC ioctl. The sequence
would be used like following:
- mmap dma-buf fd
- for each drawing/upload cycle in CPU 1. SYNC_START ioctl, 2. read/write
to mmap area 3. SYNC_END ioctl. This can be repeated as often as you
want (with the new data being consumed by the GPU or say scanout device)
- munmap once you don't need the buffer any more
Therefore, for correctness and optimal performance, systems with the memory
cache shared by the GPU and CPU i.e. the "coherent" and also the
"incoherent" are always required to use SYNC_START and SYNC_END before and
after, respectively, when accessing the mapped address.
2. Supporting existing mmap interfaces in importers 2. Supporting existing mmap interfaces in importers

View File

@ -34,6 +34,8 @@
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/reservation.h> #include <linux/reservation.h>
#include <uapi/linux/dma-buf.h>
static inline int is_dma_buf_file(struct file *); static inline int is_dma_buf_file(struct file *);
struct dma_buf_list { struct dma_buf_list {
@ -251,11 +253,54 @@ out:
return events; return events;
} }
static long dma_buf_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct dma_buf *dmabuf;
struct dma_buf_sync sync;
enum dma_data_direction direction;
dmabuf = file->private_data;
switch (cmd) {
case DMA_BUF_IOCTL_SYNC:
if (copy_from_user(&sync, (void __user *) arg, sizeof(sync)))
return -EFAULT;
if (sync.flags & ~DMA_BUF_SYNC_VALID_FLAGS_MASK)
return -EINVAL;
switch (sync.flags & DMA_BUF_SYNC_RW) {
case DMA_BUF_SYNC_READ:
direction = DMA_FROM_DEVICE;
break;
case DMA_BUF_SYNC_WRITE:
direction = DMA_TO_DEVICE;
break;
case DMA_BUF_SYNC_RW:
direction = DMA_BIDIRECTIONAL;
break;
default:
return -EINVAL;
}
if (sync.flags & DMA_BUF_SYNC_END)
dma_buf_end_cpu_access(dmabuf, direction);
else
dma_buf_begin_cpu_access(dmabuf, direction);
return 0;
default:
return -ENOTTY;
}
}
static const struct file_operations dma_buf_fops = { static const struct file_operations dma_buf_fops = {
.release = dma_buf_release, .release = dma_buf_release,
.mmap = dma_buf_mmap_internal, .mmap = dma_buf_mmap_internal,
.llseek = dma_buf_llseek, .llseek = dma_buf_llseek,
.poll = dma_buf_poll, .poll = dma_buf_poll,
.unlocked_ioctl = dma_buf_ioctl,
}; };
/* /*
@ -539,13 +584,11 @@ EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment);
* preparations. Coherency is only guaranteed in the specified range for the * preparations. Coherency is only guaranteed in the specified range for the
* specified access direction. * specified access direction.
* @dmabuf: [in] buffer to prepare cpu access for. * @dmabuf: [in] buffer to prepare cpu access for.
* @start: [in] start of range for cpu access.
* @len: [in] length of range for cpu access.
* @direction: [in] length of range for cpu access. * @direction: [in] length of range for cpu access.
* *
* Can return negative error values, returns 0 on success. * Can return negative error values, returns 0 on success.
*/ */
int dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start, size_t len, int dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
enum dma_data_direction direction) enum dma_data_direction direction)
{ {
int ret = 0; int ret = 0;
@ -554,8 +597,7 @@ int dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start, size_t len,
return -EINVAL; return -EINVAL;
if (dmabuf->ops->begin_cpu_access) if (dmabuf->ops->begin_cpu_access)
ret = dmabuf->ops->begin_cpu_access(dmabuf, start, ret = dmabuf->ops->begin_cpu_access(dmabuf, direction);
len, direction);
return ret; return ret;
} }
@ -567,19 +609,17 @@ EXPORT_SYMBOL_GPL(dma_buf_begin_cpu_access);
* actions. Coherency is only guaranteed in the specified range for the * actions. Coherency is only guaranteed in the specified range for the
* specified access direction. * specified access direction.
* @dmabuf: [in] buffer to complete cpu access for. * @dmabuf: [in] buffer to complete cpu access for.
* @start: [in] start of range for cpu access.
* @len: [in] length of range for cpu access.
* @direction: [in] length of range for cpu access. * @direction: [in] length of range for cpu access.
* *
* This call must always succeed. * This call must always succeed.
*/ */
void dma_buf_end_cpu_access(struct dma_buf *dmabuf, size_t start, size_t len, void dma_buf_end_cpu_access(struct dma_buf *dmabuf,
enum dma_data_direction direction) enum dma_data_direction direction)
{ {
WARN_ON(!dmabuf); WARN_ON(!dmabuf);
if (dmabuf->ops->end_cpu_access) if (dmabuf->ops->end_cpu_access)
dmabuf->ops->end_cpu_access(dmabuf, start, len, direction); dmabuf->ops->end_cpu_access(dmabuf, direction);
} }
EXPORT_SYMBOL_GPL(dma_buf_end_cpu_access); EXPORT_SYMBOL_GPL(dma_buf_end_cpu_access);

View File

@ -25,6 +25,14 @@ config DRM_MIPI_DSI
bool bool
depends on DRM depends on DRM
config DRM_DP_AUX_CHARDEV
bool "DRM DP AUX Interface"
depends on DRM
help
Choose this option to enable a /dev/drm_dp_auxN node that allows to
read and write values to arbitrary DPCD registers on the DP aux
channel.
config DRM_KMS_HELPER config DRM_KMS_HELPER
tristate tristate
depends on DRM depends on DRM

View File

@ -22,10 +22,13 @@ drm-$(CONFIG_OF) += drm_of.o
drm-$(CONFIG_AGP) += drm_agpsupport.o drm-$(CONFIG_AGP) += drm_agpsupport.o
drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \
drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
drm_kms_helper_common.o
drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o
drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o
obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o

View File

@ -552,13 +552,14 @@ static bool amdgpu_atpx_detect(void)
void amdgpu_register_atpx_handler(void) void amdgpu_register_atpx_handler(void)
{ {
bool r; bool r;
enum vga_switcheroo_handler_flags_t handler_flags = 0;
/* detect if we have any ATPX + 2 VGA in the system */ /* detect if we have any ATPX + 2 VGA in the system */
r = amdgpu_atpx_detect(); r = amdgpu_atpx_detect();
if (!r) if (!r)
return; return;
vga_switcheroo_register_handler(&amdgpu_atpx_handler); vga_switcheroo_register_handler(&amdgpu_atpx_handler, handler_flags);
} }
/** /**

View File

@ -3624,16 +3624,8 @@ dce_v10_0_ext_dpms(struct drm_encoder *encoder, int mode)
} }
static bool dce_v10_0_ext_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static const struct drm_encoder_helper_funcs dce_v10_0_ext_helper_funcs = { static const struct drm_encoder_helper_funcs dce_v10_0_ext_helper_funcs = {
.dpms = dce_v10_0_ext_dpms, .dpms = dce_v10_0_ext_dpms,
.mode_fixup = dce_v10_0_ext_mode_fixup,
.prepare = dce_v10_0_ext_prepare, .prepare = dce_v10_0_ext_prepare,
.mode_set = dce_v10_0_ext_mode_set, .mode_set = dce_v10_0_ext_mode_set,
.commit = dce_v10_0_ext_commit, .commit = dce_v10_0_ext_commit,

View File

@ -3619,16 +3619,8 @@ dce_v11_0_ext_dpms(struct drm_encoder *encoder, int mode)
} }
static bool dce_v11_0_ext_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static const struct drm_encoder_helper_funcs dce_v11_0_ext_helper_funcs = { static const struct drm_encoder_helper_funcs dce_v11_0_ext_helper_funcs = {
.dpms = dce_v11_0_ext_dpms, .dpms = dce_v11_0_ext_dpms,
.mode_fixup = dce_v11_0_ext_mode_fixup,
.prepare = dce_v11_0_ext_prepare, .prepare = dce_v11_0_ext_prepare,
.mode_set = dce_v11_0_ext_mode_set, .mode_set = dce_v11_0_ext_mode_set,
.commit = dce_v11_0_ext_commit, .commit = dce_v11_0_ext_commit,

View File

@ -3554,16 +3554,8 @@ dce_v8_0_ext_dpms(struct drm_encoder *encoder, int mode)
} }
static bool dce_v8_0_ext_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static const struct drm_encoder_helper_funcs dce_v8_0_ext_helper_funcs = { static const struct drm_encoder_helper_funcs dce_v8_0_ext_helper_funcs = {
.dpms = dce_v8_0_ext_dpms, .dpms = dce_v8_0_ext_dpms,
.mode_fixup = dce_v8_0_ext_mode_fixup,
.prepare = dce_v8_0_ext_prepare, .prepare = dce_v8_0_ext_prepare,
.mode_set = dce_v8_0_ext_mode_set, .mode_set = dce_v8_0_ext_mode_set,
.commit = dce_v8_0_ext_commit, .commit = dce_v8_0_ext_commit,

View File

@ -710,13 +710,6 @@ static void ast_encoder_dpms(struct drm_encoder *encoder, int mode)
} }
static bool ast_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void ast_encoder_mode_set(struct drm_encoder *encoder, static void ast_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
@ -736,7 +729,6 @@ static void ast_encoder_commit(struct drm_encoder *encoder)
static const struct drm_encoder_helper_funcs ast_enc_helper_funcs = { static const struct drm_encoder_helper_funcs ast_enc_helper_funcs = {
.dpms = ast_encoder_dpms, .dpms = ast_encoder_dpms,
.mode_fixup = ast_mode_fixup,
.prepare = ast_encoder_prepare, .prepare = ast_encoder_prepare,
.commit = ast_encoder_commit, .commit = ast_encoder_commit,
.mode_set = ast_encoder_mode_set, .mode_set = ast_encoder_mode_set,

View File

@ -152,13 +152,6 @@ static void bochs_crtc_init(struct drm_device *dev)
drm_crtc_helper_add(crtc, &bochs_helper_funcs); drm_crtc_helper_add(crtc, &bochs_helper_funcs);
} }
static bool bochs_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void bochs_encoder_mode_set(struct drm_encoder *encoder, static void bochs_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
@ -179,7 +172,6 @@ static void bochs_encoder_commit(struct drm_encoder *encoder)
static const struct drm_encoder_helper_funcs bochs_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs bochs_encoder_helper_funcs = {
.dpms = bochs_encoder_dpms, .dpms = bochs_encoder_dpms,
.mode_fixup = bochs_encoder_mode_fixup,
.mode_set = bochs_encoder_mode_set, .mode_set = bochs_encoder_mode_set,
.prepare = bochs_encoder_prepare, .prepare = bochs_encoder_prepare,
.commit = bochs_encoder_commit, .commit = bochs_encoder_commit,

View File

@ -1391,13 +1391,6 @@ static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
mutex_unlock(&hdmi->mutex); mutex_unlock(&hdmi->mutex);
} }
static bool dw_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void dw_hdmi_bridge_disable(struct drm_bridge *bridge) static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
{ {
struct dw_hdmi *hdmi = bridge->driver_private; struct dw_hdmi *hdmi = bridge->driver_private;
@ -1546,7 +1539,6 @@ static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
.pre_enable = dw_hdmi_bridge_nop, .pre_enable = dw_hdmi_bridge_nop,
.post_disable = dw_hdmi_bridge_nop, .post_disable = dw_hdmi_bridge_nop,
.mode_set = dw_hdmi_bridge_mode_set, .mode_set = dw_hdmi_bridge_mode_set,
.mode_fixup = dw_hdmi_bridge_mode_fixup,
}; };
static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id) static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)

View File

@ -430,14 +430,6 @@ void cirrus_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
*blue = cirrus_crtc->lut_b[regno]; *blue = cirrus_crtc->lut_b[regno];
} }
static bool cirrus_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void cirrus_encoder_mode_set(struct drm_encoder *encoder, static void cirrus_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
@ -466,7 +458,6 @@ static void cirrus_encoder_destroy(struct drm_encoder *encoder)
static const struct drm_encoder_helper_funcs cirrus_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs cirrus_encoder_helper_funcs = {
.dpms = cirrus_encoder_dpms, .dpms = cirrus_encoder_dpms,
.mode_fixup = cirrus_encoder_mode_fixup,
.mode_set = cirrus_encoder_mode_set, .mode_set = cirrus_encoder_mode_set,
.prepare = cirrus_encoder_prepare, .prepare = cirrus_encoder_prepare,
.commit = cirrus_encoder_commit, .commit = cirrus_encoder_commit,

View File

@ -125,6 +125,47 @@ get_current_crtc_for_encoder(struct drm_device *dev,
return NULL; return NULL;
} }
static void
set_best_encoder(struct drm_atomic_state *state,
struct drm_connector_state *conn_state,
struct drm_encoder *encoder)
{
struct drm_crtc_state *crtc_state;
struct drm_crtc *crtc;
if (conn_state->best_encoder) {
/* Unset the encoder_mask in the old crtc state. */
crtc = conn_state->connector->state->crtc;
/* A NULL crtc is an error here because we should have
* duplicated a NULL best_encoder when crtc was NULL.
* As an exception restoring duplicated atomic state
* during resume is allowed, so don't warn when
* best_encoder is equal to encoder we intend to set.
*/
WARN_ON(!crtc && encoder != conn_state->best_encoder);
if (crtc) {
crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
crtc_state->encoder_mask &=
~(1 << drm_encoder_index(conn_state->best_encoder));
}
}
if (encoder) {
crtc = conn_state->crtc;
WARN_ON(!crtc);
if (crtc) {
crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
crtc_state->encoder_mask |=
1 << drm_encoder_index(encoder);
}
}
conn_state->best_encoder = encoder;
}
static int static int
steal_encoder(struct drm_atomic_state *state, steal_encoder(struct drm_atomic_state *state,
struct drm_encoder *encoder, struct drm_encoder *encoder,
@ -134,7 +175,6 @@ steal_encoder(struct drm_atomic_state *state,
struct drm_crtc_state *crtc_state; struct drm_crtc_state *crtc_state;
struct drm_connector *connector; struct drm_connector *connector;
struct drm_connector_state *connector_state; struct drm_connector_state *connector_state;
int ret;
/* /*
* We can only steal an encoder coming from a connector, which means we * We can only steal an encoder coming from a connector, which means we
@ -165,10 +205,10 @@ steal_encoder(struct drm_atomic_state *state,
if (IS_ERR(connector_state)) if (IS_ERR(connector_state))
return PTR_ERR(connector_state); return PTR_ERR(connector_state);
ret = drm_atomic_set_crtc_for_connector(connector_state, NULL); if (connector_state->best_encoder != encoder)
if (ret) continue;
return ret;
connector_state->best_encoder = NULL; set_best_encoder(state, connector_state, NULL);
} }
return 0; return 0;
@ -216,7 +256,7 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
connector->base.id, connector->base.id,
connector->name); connector->name);
connector_state->best_encoder = NULL; set_best_encoder(state, connector_state, NULL);
return 0; return 0;
} }
@ -245,6 +285,8 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
} }
if (new_encoder == connector_state->best_encoder) { if (new_encoder == connector_state->best_encoder) {
set_best_encoder(state, connector_state, new_encoder);
DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d:%s]\n", DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d:%s]\n",
connector->base.id, connector->base.id,
connector->name, connector->name,
@ -279,7 +321,8 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
if (WARN_ON(!connector_state->crtc)) if (WARN_ON(!connector_state->crtc))
return -EINVAL; return -EINVAL;
connector_state->best_encoder = new_encoder; set_best_encoder(state, connector_state, new_encoder);
idx = drm_crtc_index(connector_state->crtc); idx = drm_crtc_index(connector_state->crtc);
crtc_state = state->crtc_states[idx]; crtc_state = state->crtc_states[idx];

View File

@ -1160,6 +1160,29 @@ out_unlock:
} }
EXPORT_SYMBOL(drm_encoder_init); EXPORT_SYMBOL(drm_encoder_init);
/**
* drm_encoder_index - find the index of a registered encoder
* @encoder: encoder to find index for
*
* Given a registered encoder, return the index of that encoder within a DRM
* device's list of encoders.
*/
unsigned int drm_encoder_index(struct drm_encoder *encoder)
{
unsigned int index = 0;
struct drm_encoder *tmp;
drm_for_each_encoder(tmp, encoder->dev) {
if (tmp == encoder)
return index;
index++;
}
BUG();
}
EXPORT_SYMBOL(drm_encoder_index);
/** /**
* drm_encoder_cleanup - cleans up an initialised encoder * drm_encoder_cleanup - cleans up an initialised encoder
* @encoder: encoder to cleanup * @encoder: encoder to cleanup
@ -5714,6 +5737,48 @@ int drm_format_vert_chroma_subsampling(uint32_t format)
} }
EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
/**
* drm_format_plane_width - width of the plane given the first plane
* @width: width of the first plane
* @format: pixel format
* @plane: plane index
*
* Returns:
* The width of @plane, given that the width of the first plane is @width.
*/
int drm_format_plane_width(int width, uint32_t format, int plane)
{
if (plane >= drm_format_num_planes(format))
return 0;
if (plane == 0)
return width;
return width / drm_format_horz_chroma_subsampling(format);
}
EXPORT_SYMBOL(drm_format_plane_width);
/**
* drm_format_plane_height - height of the plane given the first plane
* @height: height of the first plane
* @format: pixel format
* @plane: plane index
*
* Returns:
* The height of @plane, given that the height of the first plane is @height.
*/
int drm_format_plane_height(int height, uint32_t format, int plane)
{
if (plane >= drm_format_num_planes(format))
return 0;
if (plane == 0)
return height;
return height / drm_format_vert_chroma_subsampling(format);
}
EXPORT_SYMBOL(drm_format_plane_height);
/** /**
* drm_rotation_simplify() - Try to simplify the rotation * drm_rotation_simplify() - Try to simplify the rotation
* @rotation: Rotation to be simplified * @rotation: Rotation to be simplified

View File

@ -73,9 +73,6 @@
* &drm_crtc_helper_funcs, struct &drm_encoder_helper_funcs and struct * &drm_crtc_helper_funcs, struct &drm_encoder_helper_funcs and struct
* &drm_connector_helper_funcs. * &drm_connector_helper_funcs.
*/ */
MODULE_AUTHOR("David Airlie, Jesse Barnes");
MODULE_DESCRIPTION("DRM KMS helper");
MODULE_LICENSE("GPL and additional rights");
/** /**
* drm_helper_move_panel_connectors_to_head() - move panels to the front in the * drm_helper_move_panel_connectors_to_head() - move panels to the front in the
@ -337,17 +334,22 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
} }
encoder_funcs = encoder->helper_private; encoder_funcs = encoder->helper_private;
if (encoder_funcs->mode_fixup) {
if (!(ret = encoder_funcs->mode_fixup(encoder, mode, if (!(ret = encoder_funcs->mode_fixup(encoder, mode,
adjusted_mode))) { adjusted_mode))) {
DRM_DEBUG_KMS("Encoder fixup failed\n"); DRM_DEBUG_KMS("Encoder fixup failed\n");
goto done; goto done;
} }
} }
}
if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) { if (crtc_funcs->mode_fixup) {
if (!(ret = crtc_funcs->mode_fixup(crtc, mode,
adjusted_mode))) {
DRM_DEBUG_KMS("CRTC fixup failed\n"); DRM_DEBUG_KMS("CRTC fixup failed\n");
goto done; goto done;
} }
}
DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
crtc->hwmode = *adjusted_mode; crtc->hwmode = *adjusted_mode;

View File

@ -0,0 +1,368 @@
/*
* Copyright © 2015 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Authors:
* Rafael Antognolli <rafael.antognolli@intel.com>
*
*/
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drmP.h>
struct drm_dp_aux_dev {
unsigned index;
struct drm_dp_aux *aux;
struct device *dev;
struct kref refcount;
atomic_t usecount;
};
#define DRM_AUX_MINORS 256
#define AUX_MAX_OFFSET (1 << 20)
static DEFINE_IDR(aux_idr);
static DEFINE_MUTEX(aux_idr_mutex);
static struct class *drm_dp_aux_dev_class;
static int drm_dev_major = -1;
static struct drm_dp_aux_dev *drm_dp_aux_dev_get_by_minor(unsigned index)
{
struct drm_dp_aux_dev *aux_dev = NULL;
mutex_lock(&aux_idr_mutex);
aux_dev = idr_find(&aux_idr, index);
if (!kref_get_unless_zero(&aux_dev->refcount))
aux_dev = NULL;
mutex_unlock(&aux_idr_mutex);
return aux_dev;
}
static struct drm_dp_aux_dev *alloc_drm_dp_aux_dev(struct drm_dp_aux *aux)
{
struct drm_dp_aux_dev *aux_dev;
int index;
aux_dev = kzalloc(sizeof(*aux_dev), GFP_KERNEL);
if (!aux_dev)
return ERR_PTR(-ENOMEM);
aux_dev->aux = aux;
atomic_set(&aux_dev->usecount, 1);
kref_init(&aux_dev->refcount);
mutex_lock(&aux_idr_mutex);
index = idr_alloc_cyclic(&aux_idr, aux_dev, 0, DRM_AUX_MINORS,
GFP_KERNEL);
mutex_unlock(&aux_idr_mutex);
if (index < 0) {
kfree(aux_dev);
return ERR_PTR(index);
}
aux_dev->index = index;
return aux_dev;
}
static void release_drm_dp_aux_dev(struct kref *ref)
{
struct drm_dp_aux_dev *aux_dev =
container_of(ref, struct drm_dp_aux_dev, refcount);
kfree(aux_dev);
}
static ssize_t name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t res;
struct drm_dp_aux_dev *aux_dev =
drm_dp_aux_dev_get_by_minor(MINOR(dev->devt));
if (!aux_dev)
return -ENODEV;
res = sprintf(buf, "%s\n", aux_dev->aux->name);
kref_put(&aux_dev->refcount, release_drm_dp_aux_dev);
return res;
}
static DEVICE_ATTR_RO(name);
static struct attribute *drm_dp_aux_attrs[] = {
&dev_attr_name.attr,
NULL,
};
ATTRIBUTE_GROUPS(drm_dp_aux);
static int auxdev_open(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
struct drm_dp_aux_dev *aux_dev;
aux_dev = drm_dp_aux_dev_get_by_minor(minor);
if (!aux_dev)
return -ENODEV;
file->private_data = aux_dev;
return 0;
}
static loff_t auxdev_llseek(struct file *file, loff_t offset, int whence)
{
return fixed_size_llseek(file, offset, whence, AUX_MAX_OFFSET);
}
static ssize_t auxdev_read(struct file *file, char __user *buf, size_t count,
loff_t *offset)
{
size_t bytes_pending, num_bytes_processed = 0;
struct drm_dp_aux_dev *aux_dev = file->private_data;
ssize_t res = 0;
if (!atomic_inc_not_zero(&aux_dev->usecount))
return -ENODEV;
bytes_pending = min((loff_t)count, AUX_MAX_OFFSET - (*offset));
if (!access_ok(VERIFY_WRITE, buf, bytes_pending)) {
res = -EFAULT;
goto out;
}
while (bytes_pending > 0) {
uint8_t localbuf[DP_AUX_MAX_PAYLOAD_BYTES];
ssize_t todo = min_t(size_t, bytes_pending, sizeof(localbuf));
res = drm_dp_dpcd_read(aux_dev->aux, *offset, localbuf, todo);
if (res <= 0) {
res = num_bytes_processed ? num_bytes_processed : res;
goto out;
}
if (__copy_to_user(buf + num_bytes_processed, localbuf, res)) {
res = num_bytes_processed ?
num_bytes_processed : -EFAULT;
goto out;
}
bytes_pending -= res;
*offset += res;
num_bytes_processed += res;
res = num_bytes_processed;
}
out:
atomic_dec(&aux_dev->usecount);
wake_up_atomic_t(&aux_dev->usecount);
return res;
}
static ssize_t auxdev_write(struct file *file, const char __user *buf,
size_t count, loff_t *offset)
{
size_t bytes_pending, num_bytes_processed = 0;
struct drm_dp_aux_dev *aux_dev = file->private_data;
ssize_t res = 0;
if (!atomic_inc_not_zero(&aux_dev->usecount))
return -ENODEV;
bytes_pending = min((loff_t)count, AUX_MAX_OFFSET - *offset);
if (!access_ok(VERIFY_READ, buf, bytes_pending)) {
res = -EFAULT;
goto out;
}
while (bytes_pending > 0) {
uint8_t localbuf[DP_AUX_MAX_PAYLOAD_BYTES];
ssize_t todo = min_t(size_t, bytes_pending, sizeof(localbuf));
if (__copy_from_user(localbuf,
buf + num_bytes_processed, todo)) {
res = num_bytes_processed ?
num_bytes_processed : -EFAULT;
goto out;
}
res = drm_dp_dpcd_write(aux_dev->aux, *offset, localbuf, todo);
if (res <= 0) {
res = num_bytes_processed ? num_bytes_processed : res;
goto out;
}
bytes_pending -= res;
*offset += res;
num_bytes_processed += res;
res = num_bytes_processed;
}
out:
atomic_dec(&aux_dev->usecount);
wake_up_atomic_t(&aux_dev->usecount);
return res;
}
static int auxdev_release(struct inode *inode, struct file *file)
{
struct drm_dp_aux_dev *aux_dev = file->private_data;
kref_put(&aux_dev->refcount, release_drm_dp_aux_dev);
return 0;
}
static const struct file_operations auxdev_fops = {
.owner = THIS_MODULE,
.llseek = auxdev_llseek,
.read = auxdev_read,
.write = auxdev_write,
.open = auxdev_open,
.release = auxdev_release,
};
#define to_auxdev(d) container_of(d, struct drm_dp_aux_dev, aux)
static struct drm_dp_aux_dev *drm_dp_aux_dev_get_by_aux(struct drm_dp_aux *aux)
{
struct drm_dp_aux_dev *iter, *aux_dev = NULL;
int id;
/* don't increase kref count here because this function should only be
* used by drm_dp_aux_unregister_devnode. Thus, it will always have at
* least one reference - the one that drm_dp_aux_register_devnode
* created
*/
mutex_lock(&aux_idr_mutex);
idr_for_each_entry(&aux_idr, iter, id) {
if (iter->aux == aux) {
aux_dev = iter;
break;
}
}
mutex_unlock(&aux_idr_mutex);
return aux_dev;
}
static int auxdev_wait_atomic_t(atomic_t *p)
{
schedule();
return 0;
}
/**
* drm_dp_aux_unregister_devnode() - unregister a devnode for this aux channel
* @aux: DisplayPort AUX channel
*
* Returns 0 on success or a negative error code on failure.
*/
void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux)
{
struct drm_dp_aux_dev *aux_dev;
unsigned int minor;
aux_dev = drm_dp_aux_dev_get_by_aux(aux);
if (!aux_dev) /* attach must have failed */
return;
mutex_lock(&aux_idr_mutex);
idr_remove(&aux_idr, aux_dev->index);
mutex_unlock(&aux_idr_mutex);
atomic_dec(&aux_dev->usecount);
wait_on_atomic_t(&aux_dev->usecount, auxdev_wait_atomic_t,
TASK_UNINTERRUPTIBLE);
minor = aux_dev->index;
if (aux_dev->dev)
device_destroy(drm_dp_aux_dev_class,
MKDEV(drm_dev_major, minor));
DRM_DEBUG("drm_dp_aux_dev: aux [%s] unregistering\n", aux->name);
kref_put(&aux_dev->refcount, release_drm_dp_aux_dev);
}
EXPORT_SYMBOL(drm_dp_aux_unregister_devnode);
/**
* drm_dp_aux_register_devnode() - register a devnode for this aux channel
* @aux: DisplayPort AUX channel
*
* Returns 0 on success or a negative error code on failure.
*/
int drm_dp_aux_register_devnode(struct drm_dp_aux *aux)
{
struct drm_dp_aux_dev *aux_dev;
int res;
aux_dev = alloc_drm_dp_aux_dev(aux);
if (IS_ERR(aux_dev))
return PTR_ERR(aux_dev);
aux_dev->dev = device_create(drm_dp_aux_dev_class, aux->dev,
MKDEV(drm_dev_major, aux_dev->index), NULL,
"drm_dp_aux%d", aux_dev->index);
if (IS_ERR(aux_dev->dev)) {
res = PTR_ERR(aux_dev->dev);
aux_dev->dev = NULL;
goto error;
}
DRM_DEBUG("drm_dp_aux_dev: aux [%s] registered as minor %d\n",
aux->name, aux_dev->index);
return 0;
error:
drm_dp_aux_unregister_devnode(aux);
return res;
}
EXPORT_SYMBOL(drm_dp_aux_register_devnode);
int drm_dp_aux_dev_init(void)
{
int res;
drm_dp_aux_dev_class = class_create(THIS_MODULE, "drm_dp_aux_dev");
if (IS_ERR(drm_dp_aux_dev_class)) {
res = PTR_ERR(drm_dp_aux_dev_class);
goto out;
}
drm_dp_aux_dev_class->dev_groups = drm_dp_aux_groups;
res = register_chrdev(0, "aux", &auxdev_fops);
if (res < 0)
goto out;
drm_dev_major = res;
return 0;
out:
class_destroy(drm_dp_aux_dev_class);
return res;
}
EXPORT_SYMBOL(drm_dp_aux_dev_init);
void drm_dp_aux_dev_exit(void)
{
unregister_chrdev(drm_dev_major, "aux");
class_destroy(drm_dp_aux_dev_class);
}
EXPORT_SYMBOL(drm_dp_aux_dev_exit);

View File

@ -28,6 +28,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <drm/drm_dp_helper.h> #include <drm/drm_dp_helper.h>
#include <drm/drm_dp_aux_dev.h>
#include <drm/drmP.h> #include <drm/drmP.h>
/** /**
@ -754,6 +755,8 @@ static const struct i2c_algorithm drm_dp_i2c_algo = {
*/ */
int drm_dp_aux_register(struct drm_dp_aux *aux) int drm_dp_aux_register(struct drm_dp_aux *aux)
{ {
int ret;
mutex_init(&aux->hw_mutex); mutex_init(&aux->hw_mutex);
aux->ddc.algo = &drm_dp_i2c_algo; aux->ddc.algo = &drm_dp_i2c_algo;
@ -768,7 +771,17 @@ int drm_dp_aux_register(struct drm_dp_aux *aux)
strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev), strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev),
sizeof(aux->ddc.name)); sizeof(aux->ddc.name));
return i2c_add_adapter(&aux->ddc); ret = drm_dp_aux_register_devnode(aux);
if (ret)
return ret;
ret = i2c_add_adapter(&aux->ddc);
if (ret) {
drm_dp_aux_unregister_devnode(aux);
return ret;
}
return 0;
} }
EXPORT_SYMBOL(drm_dp_aux_register); EXPORT_SYMBOL(drm_dp_aux_register);
@ -778,6 +791,7 @@ EXPORT_SYMBOL(drm_dp_aux_register);
*/ */
void drm_dp_aux_unregister(struct drm_dp_aux *aux) void drm_dp_aux_unregister(struct drm_dp_aux *aux)
{ {
drm_dp_aux_unregister_devnode(aux);
i2c_del_adapter(&aux->ddc); i2c_del_adapter(&aux->ddc);
} }
EXPORT_SYMBOL(drm_dp_aux_unregister); EXPORT_SYMBOL(drm_dp_aux_unregister);

View File

@ -32,6 +32,7 @@
#include <linux/hdmi.h> #include <linux/hdmi.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/vga_switcheroo.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_edid.h> #include <drm/drm_edid.h>
#include <drm/drm_displayid.h> #include <drm/drm_displayid.h>
@ -1394,6 +1395,31 @@ struct edid *drm_get_edid(struct drm_connector *connector,
} }
EXPORT_SYMBOL(drm_get_edid); EXPORT_SYMBOL(drm_get_edid);
/**
* drm_get_edid_switcheroo - get EDID data for a vga_switcheroo output
* @connector: connector we're probing
* @adapter: I2C adapter to use for DDC
*
* Wrapper around drm_get_edid() for laptops with dual GPUs using one set of
* outputs. The wrapper adds the requisite vga_switcheroo calls to temporarily
* switch DDC to the GPU which is retrieving EDID.
*
* Return: Pointer to valid EDID or %NULL if we couldn't find any.
*/
struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
struct i2c_adapter *adapter)
{
struct pci_dev *pdev = connector->dev->pdev;
struct edid *edid;
vga_switcheroo_lock_ddc(pdev);
edid = drm_get_edid(connector, adapter);
vga_switcheroo_unlock_ddc(pdev);
return edid;
}
EXPORT_SYMBOL(drm_get_edid_switcheroo);
/** /**
* drm_edid_duplicate - duplicate an EDID and the extensions * drm_edid_duplicate - duplicate an EDID and the extensions
* @edid: EDID to duplicate * @edid: EDID to duplicate

View File

@ -140,6 +140,9 @@ bool drm_i2c_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode, const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
{ {
if (!get_slave_funcs(encoder)->mode_fixup)
return true;
return get_slave_funcs(encoder)->mode_fixup(encoder, mode, adjusted_mode); return get_slave_funcs(encoder)->mode_fixup(encoder, mode, adjusted_mode);
} }
EXPORT_SYMBOL(drm_i2c_encoder_mode_fixup); EXPORT_SYMBOL(drm_i2c_encoder_mode_fixup);

View File

@ -104,21 +104,17 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
{ {
struct drm_device *dev = fb_helper->dev; struct drm_device *dev = fb_helper->dev;
struct drm_connector *connector; struct drm_connector *connector;
int i; int i, ret;
if (!drm_fbdev_emulation) if (!drm_fbdev_emulation)
return 0; return 0;
mutex_lock(&dev->mode_config.mutex); mutex_lock(&dev->mode_config.mutex);
drm_for_each_connector(connector, dev) { drm_for_each_connector(connector, dev) {
struct drm_fb_helper_connector *fb_helper_connector; ret = drm_fb_helper_add_one_connector(fb_helper, connector);
fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL); if (ret)
if (!fb_helper_connector)
goto fail; goto fail;
fb_helper_connector->connector = connector;
fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector;
} }
mutex_unlock(&dev->mode_config.mutex); mutex_unlock(&dev->mode_config.mutex);
return 0; return 0;
@ -130,7 +126,7 @@ fail:
fb_helper->connector_count = 0; fb_helper->connector_count = 0;
mutex_unlock(&dev->mode_config.mutex); mutex_unlock(&dev->mode_config.mutex);
return -ENOMEM; return ret;
} }
EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
@ -1989,13 +1985,13 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
width = dev->mode_config.max_width; width = dev->mode_config.max_width;
height = dev->mode_config.max_height; height = dev->mode_config.max_height;
crtcs = kcalloc(dev->mode_config.num_connector, crtcs = kcalloc(fb_helper->connector_count,
sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
modes = kcalloc(dev->mode_config.num_connector, modes = kcalloc(fb_helper->connector_count,
sizeof(struct drm_display_mode *), GFP_KERNEL); sizeof(struct drm_display_mode *), GFP_KERNEL);
offsets = kcalloc(dev->mode_config.num_connector, offsets = kcalloc(fb_helper->connector_count,
sizeof(struct drm_fb_offset), GFP_KERNEL); sizeof(struct drm_fb_offset), GFP_KERNEL);
enabled = kcalloc(dev->mode_config.num_connector, enabled = kcalloc(fb_helper->connector_count,
sizeof(bool), GFP_KERNEL); sizeof(bool), GFP_KERNEL);
if (!crtcs || !modes || !enabled || !offsets) { if (!crtcs || !modes || !enabled || !offsets) {
DRM_ERROR("Memory allocation failed\n"); DRM_ERROR("Memory allocation failed\n");
@ -2009,9 +2005,9 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
fb_helper->funcs->initial_config(fb_helper, crtcs, modes, fb_helper->funcs->initial_config(fb_helper, crtcs, modes,
offsets, offsets,
enabled, width, height))) { enabled, width, height))) {
memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0])); memset(modes, 0, fb_helper->connector_count*sizeof(modes[0]));
memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0])); memset(crtcs, 0, fb_helper->connector_count*sizeof(crtcs[0]));
memset(offsets, 0, dev->mode_config.num_connector*sizeof(offsets[0])); memset(offsets, 0, fb_helper->connector_count*sizeof(offsets[0]));
if (!drm_target_cloned(fb_helper, modes, offsets, if (!drm_target_cloned(fb_helper, modes, offsets,
enabled, width, height) && enabled, width, height) &&
@ -2196,9 +2192,9 @@ EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
* but the module doesn't depend on any fb console symbols. At least * but the module doesn't depend on any fb console symbols. At least
* attempt to load fbcon to avoid leaving the system without a usable console. * attempt to load fbcon to avoid leaving the system without a usable console.
*/ */
#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT) int __init drm_fb_helper_modinit(void)
static int __init drm_fb_helper_modinit(void)
{ {
#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
const char *name = "fbcon"; const char *name = "fbcon";
struct module *fbcon; struct module *fbcon;
@ -2208,8 +2204,7 @@ static int __init drm_fb_helper_modinit(void)
if (!fbcon) if (!fbcon)
request_module_nowait(name); request_module_nowait(name);
#endif
return 0; return 0;
} }
EXPORT_SYMBOL(drm_fb_helper_modinit);
module_init(drm_fb_helper_modinit);
#endif

View File

@ -0,0 +1,60 @@
/*
* Copyright © 2015 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Authors:
* Rafael Antognolli <rafael.antognolli@intel.com>
*
*/
#include <drm/drmP.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_dp_aux_dev.h>
MODULE_AUTHOR("David Airlie, Jesse Barnes");
MODULE_DESCRIPTION("DRM KMS helper");
MODULE_LICENSE("GPL and additional rights");
static int __init drm_kms_helper_init(void)
{
int ret;
/* Call init functions from specific kms helpers here */
ret = drm_fb_helper_modinit();
if (ret < 0)
goto out;
ret = drm_dp_aux_dev_init();
if (ret < 0)
goto out;
out:
return ret;
}
static void __exit drm_kms_helper_exit(void)
{
/* Call exit functions from specific kms helpers here */
drm_dp_aux_dev_exit();
}
module_init(drm_kms_helper_init);
module_exit(drm_kms_helper_exit);

View File

@ -1371,8 +1371,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
} }
done: done:
if (i >= 0) { if (i >= 0) {
printk(KERN_WARNING pr_warn("[drm] parse error at position %i in video mode '%s'\n",
"parse error at position %i in video mode '%s'\n",
i, name); i, name);
mode->specified = false; mode->specified = false;
return false; return false;

View File

@ -329,7 +329,7 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = {
* drm_gem_prime_export - helper library implementation of the export callback * drm_gem_prime_export - helper library implementation of the export callback
* @dev: drm_device to export from * @dev: drm_device to export from
* @obj: GEM object to export * @obj: GEM object to export
* @flags: flags like DRM_CLOEXEC * @flags: flags like DRM_CLOEXEC and DRM_RDWR
* *
* This is the implementation of the gem_prime_export functions for GEM drivers * This is the implementation of the gem_prime_export functions for GEM drivers
* using the PRIME helpers. * using the PRIME helpers.
@ -628,7 +628,6 @@ int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
struct drm_prime_handle *args = data; struct drm_prime_handle *args = data;
uint32_t flags;
if (!drm_core_check_feature(dev, DRIVER_PRIME)) if (!drm_core_check_feature(dev, DRIVER_PRIME))
return -EINVAL; return -EINVAL;
@ -637,14 +636,11 @@ int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
return -ENOSYS; return -ENOSYS;
/* check flags are valid */ /* check flags are valid */
if (args->flags & ~DRM_CLOEXEC) if (args->flags & ~(DRM_CLOEXEC | DRM_RDWR))
return -EINVAL; return -EINVAL;
/* we only want to pass DRM_CLOEXEC which is == O_CLOEXEC */
flags = args->flags & DRM_CLOEXEC;
return dev->driver->prime_handle_to_fd(dev, file_priv, return dev->driver->prime_handle_to_fd(dev, file_priv,
args->handle, flags, &args->fd); args->handle, args->flags, &args->fd);
} }
int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data, int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,

View File

@ -1155,13 +1155,6 @@ static int exynos_dp_create_connector(struct drm_encoder *encoder)
return 0; return 0;
} }
static bool exynos_dp_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void exynos_dp_mode_set(struct drm_encoder *encoder, static void exynos_dp_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
@ -1177,7 +1170,6 @@ static void exynos_dp_disable(struct drm_encoder *encoder)
} }
static const struct drm_encoder_helper_funcs exynos_dp_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs exynos_dp_encoder_helper_funcs = {
.mode_fixup = exynos_dp_mode_fixup,
.mode_set = exynos_dp_mode_set, .mode_set = exynos_dp_mode_set,
.enable = exynos_dp_enable, .enable = exynos_dp_enable,
.disable = exynos_dp_disable, .disable = exynos_dp_disable,

View File

@ -128,13 +128,6 @@ static int exynos_dpi_create_connector(struct drm_encoder *encoder)
return 0; return 0;
} }
static bool exynos_dpi_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void exynos_dpi_mode_set(struct drm_encoder *encoder, static void exynos_dpi_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
@ -162,7 +155,6 @@ static void exynos_dpi_disable(struct drm_encoder *encoder)
} }
static const struct drm_encoder_helper_funcs exynos_dpi_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs exynos_dpi_encoder_helper_funcs = {
.mode_fixup = exynos_dpi_mode_fixup,
.mode_set = exynos_dpi_mode_set, .mode_set = exynos_dpi_mode_set,
.enable = exynos_dpi_enable, .enable = exynos_dpi_enable,
.disable = exynos_dpi_disable, .disable = exynos_dpi_disable,

View File

@ -1597,13 +1597,6 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder)
return 0; return 0;
} }
static bool exynos_dsi_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void exynos_dsi_mode_set(struct drm_encoder *encoder, static void exynos_dsi_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
@ -1623,7 +1616,6 @@ static void exynos_dsi_mode_set(struct drm_encoder *encoder,
} }
static const struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = {
.mode_fixup = exynos_dsi_mode_fixup,
.mode_set = exynos_dsi_mode_set, .mode_set = exynos_dsi_mode_set,
.enable = exynos_dsi_enable, .enable = exynos_dsi_enable,
.disable = exynos_dsi_disable, .disable = exynos_dsi_disable,

View File

@ -410,13 +410,6 @@ static int vidi_create_connector(struct drm_encoder *encoder)
return 0; return 0;
} }
static bool exynos_vidi_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void exynos_vidi_mode_set(struct drm_encoder *encoder, static void exynos_vidi_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
@ -432,7 +425,6 @@ static void exynos_vidi_disable(struct drm_encoder *encoder)
} }
static const struct drm_encoder_helper_funcs exynos_vidi_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs exynos_vidi_encoder_helper_funcs = {
.mode_fixup = exynos_vidi_mode_fixup,
.mode_set = exynos_vidi_mode_set, .mode_set = exynos_vidi_mode_set,
.enable = exynos_vidi_enable, .enable = exynos_vidi_enable,
.disable = exynos_vidi_disable, .disable = exynos_vidi_disable,

View File

@ -217,7 +217,6 @@ static int cdv_intel_crt_set_property(struct drm_connector *connector,
static const struct drm_encoder_helper_funcs cdv_intel_crt_helper_funcs = { static const struct drm_encoder_helper_funcs cdv_intel_crt_helper_funcs = {
.dpms = cdv_intel_crt_dpms, .dpms = cdv_intel_crt_dpms,
.mode_fixup = gma_encoder_mode_fixup,
.prepare = gma_encoder_prepare, .prepare = gma_encoder_prepare,
.commit = gma_encoder_commit, .commit = gma_encoder_commit,
.mode_set = cdv_intel_crt_mode_set, .mode_set = cdv_intel_crt_mode_set,

View File

@ -255,7 +255,6 @@ static void cdv_hdmi_destroy(struct drm_connector *connector)
static const struct drm_encoder_helper_funcs cdv_hdmi_helper_funcs = { static const struct drm_encoder_helper_funcs cdv_hdmi_helper_funcs = {
.dpms = cdv_hdmi_dpms, .dpms = cdv_hdmi_dpms,
.mode_fixup = gma_encoder_mode_fixup,
.prepare = gma_encoder_prepare, .prepare = gma_encoder_prepare,
.mode_set = cdv_hdmi_mode_set, .mode_set = cdv_hdmi_mode_set,
.commit = gma_encoder_commit, .commit = gma_encoder_commit,

View File

@ -478,13 +478,6 @@ int gma_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
return 0; return 0;
} }
bool gma_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
bool gma_crtc_mode_fixup(struct drm_crtc *crtc, bool gma_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode, const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)

View File

@ -90,9 +90,6 @@ extern void gma_crtc_restore(struct drm_crtc *crtc);
extern void gma_encoder_prepare(struct drm_encoder *encoder); extern void gma_encoder_prepare(struct drm_encoder *encoder);
extern void gma_encoder_commit(struct drm_encoder *encoder); extern void gma_encoder_commit(struct drm_encoder *encoder);
extern void gma_encoder_destroy(struct drm_encoder *encoder); extern void gma_encoder_destroy(struct drm_encoder *encoder);
extern bool gma_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
/* Common clock related functions */ /* Common clock related functions */
extern const struct gma_limit_t *gma_limit(struct drm_crtc *crtc, int refclk); extern const struct gma_limit_t *gma_limit(struct drm_crtc *crtc, int refclk);

View File

@ -436,7 +436,7 @@ int gma_intel_setup_gmbus(struct drm_device *dev)
return 0; return 0;
err: err:
while (--i) { while (i--) {
struct intel_gmbus *bus = &dev_priv->gmbus[i]; struct intel_gmbus *bus = &dev_priv->gmbus[i];
i2c_del_adapter(&bus->adapter); i2c_del_adapter(&bus->adapter);
} }

View File

@ -601,7 +601,6 @@ static void oaktrail_hdmi_destroy(struct drm_connector *connector)
static const struct drm_encoder_helper_funcs oaktrail_hdmi_helper_funcs = { static const struct drm_encoder_helper_funcs oaktrail_hdmi_helper_funcs = {
.dpms = oaktrail_hdmi_dpms, .dpms = oaktrail_hdmi_dpms,
.mode_fixup = gma_encoder_mode_fixup,
.prepare = gma_encoder_prepare, .prepare = gma_encoder_prepare,
.mode_set = oaktrail_hdmi_mode_set, .mode_set = oaktrail_hdmi_mode_set,
.commit = gma_encoder_commit, .commit = gma_encoder_commit,

View File

@ -253,6 +253,8 @@ static int ch7006_encoder_create_resources(struct drm_encoder *encoder,
drm_mode_create_tv_properties(dev, NUM_TV_NORMS, ch7006_tv_norm_names); drm_mode_create_tv_properties(dev, NUM_TV_NORMS, ch7006_tv_norm_names);
priv->scale_property = drm_property_create_range(dev, 0, "scale", 0, 2); priv->scale_property = drm_property_create_range(dev, 0, "scale", 0, 2);
if (!priv->scale_property)
return -ENOMEM;
drm_object_attach_property(&connector->base, conf->tv_select_subconnector_property, drm_object_attach_property(&connector->base, conf->tv_select_subconnector_property,
priv->select_subconnector); priv->select_subconnector);

View File

@ -252,14 +252,6 @@ sil164_encoder_restore(struct drm_encoder *encoder)
priv->saved_slave_state); priv->saved_slave_state);
} }
static bool
sil164_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static int static int
sil164_encoder_mode_valid(struct drm_encoder *encoder, sil164_encoder_mode_valid(struct drm_encoder *encoder,
struct drm_display_mode *mode) struct drm_display_mode *mode)
@ -347,7 +339,6 @@ static const struct drm_encoder_slave_funcs sil164_encoder_funcs = {
.dpms = sil164_encoder_dpms, .dpms = sil164_encoder_dpms,
.save = sil164_encoder_save, .save = sil164_encoder_save,
.restore = sil164_encoder_restore, .restore = sil164_encoder_restore,
.mode_fixup = sil164_encoder_mode_fixup,
.mode_valid = sil164_encoder_mode_valid, .mode_valid = sil164_encoder_mode_valid,
.mode_set = sil164_encoder_mode_set, .mode_set = sil164_encoder_mode_set,
.detect = sil164_encoder_detect, .detect = sil164_encoder_detect,

View File

@ -856,14 +856,6 @@ static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
priv->dpms = mode; priv->dpms = mode;
} }
static bool
tda998x_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static int tda998x_connector_mode_valid(struct drm_connector *connector, static int tda998x_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode) struct drm_display_mode *mode)
{ {
@ -1343,7 +1335,6 @@ static void tda998x_encoder_commit(struct drm_encoder *encoder)
static const struct drm_encoder_helper_funcs tda998x_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs tda998x_encoder_helper_funcs = {
.dpms = tda998x_encoder_dpms, .dpms = tda998x_encoder_dpms,
.mode_fixup = tda998x_encoder_mode_fixup,
.prepare = tda998x_encoder_prepare, .prepare = tda998x_encoder_prepare,
.commit = tda998x_encoder_commit, .commit = tda998x_encoder_commit,
.mode_set = tda998x_encoder_mode_set, .mode_set = tda998x_encoder_mode_set,

View File

@ -35,9 +35,12 @@
#include "i915_trace.h" #include "i915_trace.h"
#include "intel_drv.h" #include "intel_drv.h"
#include <linux/apple-gmux.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h>
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
static struct drm_driver driver; static struct drm_driver driver;
@ -969,6 +972,15 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (PCI_FUNC(pdev->devfn)) if (PCI_FUNC(pdev->devfn))
return -ENODEV; return -ENODEV;
/*
* apple-gmux is needed on dual GPU MacBook Pro
* to probe the panel if we're the inactive GPU.
*/
if (IS_ENABLED(CONFIG_VGA_ARB) && IS_ENABLED(CONFIG_VGA_SWITCHEROO) &&
apple_gmux_present() && pdev != vga_default_device() &&
!vga_switcheroo_handler_flags())
return -EPROBE_DEFER;
return drm_get_pci_dev(pdev, ent, &driver); return drm_get_pci_dev(pdev, ent, &driver);
} }

View File

@ -193,10 +193,26 @@ static void i915_gem_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_n
static int i915_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma) static int i915_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma)
{ {
struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf);
int ret;
if (obj->base.size < vma->vm_end - vma->vm_start)
return -EINVAL; return -EINVAL;
if (!obj->base.filp)
return -ENODEV;
ret = obj->base.filp->f_op->mmap(obj->base.filp, vma);
if (ret)
return ret;
fput(vma->vm_file);
vma->vm_file = get_file(obj->base.filp);
return 0;
} }
static int i915_gem_begin_cpu_access(struct dma_buf *dma_buf, size_t start, size_t length, enum dma_data_direction direction) static int i915_gem_begin_cpu_access(struct dma_buf *dma_buf, enum dma_data_direction direction)
{ {
struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf); struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf);
struct drm_device *dev = obj->base.dev; struct drm_device *dev = obj->base.dev;
@ -212,6 +228,27 @@ static int i915_gem_begin_cpu_access(struct dma_buf *dma_buf, size_t start, size
return ret; return ret;
} }
static void i915_gem_end_cpu_access(struct dma_buf *dma_buf, enum dma_data_direction direction)
{
struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf);
struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
bool was_interruptible;
int ret;
mutex_lock(&dev->struct_mutex);
was_interruptible = dev_priv->mm.interruptible;
dev_priv->mm.interruptible = false;
ret = i915_gem_object_set_to_gtt_domain(obj, false);
dev_priv->mm.interruptible = was_interruptible;
mutex_unlock(&dev->struct_mutex);
if (unlikely(ret))
DRM_ERROR("unable to flush buffer following CPU access; rendering may be corrupt\n");
}
static const struct dma_buf_ops i915_dmabuf_ops = { static const struct dma_buf_ops i915_dmabuf_ops = {
.map_dma_buf = i915_gem_map_dma_buf, .map_dma_buf = i915_gem_map_dma_buf,
.unmap_dma_buf = i915_gem_unmap_dma_buf, .unmap_dma_buf = i915_gem_unmap_dma_buf,
@ -224,6 +261,7 @@ static const struct dma_buf_ops i915_dmabuf_ops = {
.vmap = i915_gem_dmabuf_vmap, .vmap = i915_gem_dmabuf_vmap,
.vunmap = i915_gem_dmabuf_vunmap, .vunmap = i915_gem_dmabuf_vunmap,
.begin_cpu_access = i915_gem_begin_cpu_access, .begin_cpu_access = i915_gem_begin_cpu_access,
.end_cpu_access = i915_gem_end_cpu_access,
}; };
struct dma_buf *i915_gem_prime_export(struct drm_device *dev, struct dma_buf *i915_gem_prime_export(struct drm_device *dev,

View File

@ -10521,7 +10521,6 @@ retry:
} }
connector_state->crtc = crtc; connector_state->crtc = crtc;
connector_state->best_encoder = &intel_encoder->base;
crtc_state = intel_atomic_get_crtc_state(state, intel_crtc); crtc_state = intel_atomic_get_crtc_state(state, intel_crtc);
if (IS_ERR(crtc_state)) { if (IS_ERR(crtc_state)) {
@ -10617,7 +10616,6 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
if (IS_ERR(crtc_state)) if (IS_ERR(crtc_state))
goto fail; goto fail;
connector_state->best_encoder = NULL;
connector_state->crtc = NULL; connector_state->crtc = NULL;
crtc_state->base.enable = crtc_state->base.active = false; crtc_state->base.enable = crtc_state->base.active = false;
@ -15593,6 +15591,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
crtc->base.state->active = crtc->active; crtc->base.state->active = crtc->active;
crtc->base.enabled = crtc->active; crtc->base.enabled = crtc->active;
crtc->base.state->connector_mask = 0; crtc->base.state->connector_mask = 0;
crtc->base.state->encoder_mask = 0;
/* Because we only establish the connector -> encoder -> /* Because we only establish the connector -> encoder ->
* crtc links if something is active, this means the * crtc links if something is active, this means the
@ -15832,6 +15831,8 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
*/ */
encoder->base.crtc->state->connector_mask |= encoder->base.crtc->state->connector_mask |=
1 << drm_connector_index(&connector->base); 1 << drm_connector_index(&connector->base);
encoder->base.crtc->state->encoder_mask |=
1 << drm_encoder_index(&encoder->base);
} }
} else { } else {

View File

@ -1188,7 +1188,6 @@ intel_dp_aux_fini(struct intel_dp *intel_dp)
static int static int
intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector) intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
{ {
struct drm_device *dev = intel_dp_to_dev(intel_dp);
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
enum port port = intel_dig_port->port; enum port port = intel_dig_port->port;
int ret; int ret;
@ -1199,7 +1198,7 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
if (!intel_dp->aux.name) if (!intel_dp->aux.name)
return -ENOMEM; return -ENOMEM;
intel_dp->aux.dev = dev->dev; intel_dp->aux.dev = connector->base.kdev;
intel_dp->aux.transfer = intel_dp_aux_transfer; intel_dp->aux.transfer = intel_dp_aux_transfer;
DRM_DEBUG_KMS("registering %s bus for %s\n", DRM_DEBUG_KMS("registering %s bus for %s\n",
@ -1214,16 +1213,6 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
return ret; return ret;
} }
ret = sysfs_create_link(&connector->base.kdev->kobj,
&intel_dp->aux.ddc.dev.kobj,
intel_dp->aux.ddc.dev.kobj.name);
if (ret < 0) {
DRM_ERROR("sysfs_create_link() for %s failed (%d)\n",
intel_dp->aux.name, ret);
intel_dp_aux_fini(intel_dp);
return ret;
}
return 0; return 0;
} }
@ -1232,9 +1221,7 @@ intel_dp_connector_unregister(struct intel_connector *intel_connector)
{ {
struct intel_dp *intel_dp = intel_attached_dp(&intel_connector->base); struct intel_dp *intel_dp = intel_attached_dp(&intel_connector->base);
if (!intel_connector->mst_port) intel_dp_aux_fini(intel_dp);
sysfs_remove_link(&intel_connector->base.kdev->kobj,
intel_dp->aux.ddc.dev.kobj.name);
intel_connector_unregister(intel_connector); intel_connector_unregister(intel_connector);
} }
@ -4868,7 +4855,6 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
struct intel_dp *intel_dp = &intel_dig_port->dp; struct intel_dp *intel_dp = &intel_dig_port->dp;
intel_dp_aux_fini(intel_dp);
intel_dp_mst_encoder_cleanup(intel_dig_port); intel_dp_mst_encoder_cleanup(intel_dig_port);
if (is_edp(intel_dp)) { if (is_edp(intel_dp)) {
cancel_delayed_work_sync(&intel_dp->panel_vdd_work); cancel_delayed_work_sync(&intel_dp->panel_vdd_work);

View File

@ -31,6 +31,7 @@
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/vga_switcheroo.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h> #include <drm/drm_crtc.h>
@ -1080,7 +1081,12 @@ void intel_lvds_init(struct drm_device *dev)
* preferred mode is the right one. * preferred mode is the right one.
*/ */
mutex_lock(&dev->mode_config.mutex); mutex_lock(&dev->mode_config.mutex);
edid = drm_get_edid(connector, intel_gmbus_get_adapter(dev_priv, pin)); if (vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC)
edid = drm_get_edid_switcheroo(connector,
intel_gmbus_get_adapter(dev_priv, pin));
else
edid = drm_get_edid(connector,
intel_gmbus_get_adapter(dev_priv, pin));
if (edid) { if (edid) {
if (drm_add_edid_modes(connector, edid)) { if (drm_add_edid_modes(connector, edid)) {
drm_mode_connector_update_edid_property(connector, drm_mode_connector_update_edid_property(connector,

View File

@ -109,13 +109,6 @@ static void dw_hdmi_imx_encoder_disable(struct drm_encoder *encoder)
{ {
} }
static bool dw_hdmi_imx_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adj_mode)
{
return true;
}
static void dw_hdmi_imx_encoder_mode_set(struct drm_encoder *encoder, static void dw_hdmi_imx_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adj_mode) struct drm_display_mode *adj_mode)
@ -138,7 +131,6 @@ static void dw_hdmi_imx_encoder_prepare(struct drm_encoder *encoder)
} }
static const struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = {
.mode_fixup = dw_hdmi_imx_encoder_mode_fixup,
.mode_set = dw_hdmi_imx_encoder_mode_set, .mode_set = dw_hdmi_imx_encoder_mode_set,
.prepare = dw_hdmi_imx_encoder_prepare, .prepare = dw_hdmi_imx_encoder_prepare,
.commit = dw_hdmi_imx_encoder_commit, .commit = dw_hdmi_imx_encoder_commit,

View File

@ -139,13 +139,6 @@ static void imx_ldb_encoder_dpms(struct drm_encoder *encoder, int mode)
{ {
} }
static bool imx_ldb_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno, static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno,
unsigned long serial_clk, unsigned long di_clk) unsigned long serial_clk, unsigned long di_clk)
{ {
@ -376,7 +369,6 @@ static const struct drm_encoder_funcs imx_ldb_encoder_funcs = {
static const struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = {
.dpms = imx_ldb_encoder_dpms, .dpms = imx_ldb_encoder_dpms,
.mode_fixup = imx_ldb_encoder_mode_fixup,
.prepare = imx_ldb_encoder_prepare, .prepare = imx_ldb_encoder_prepare,
.commit = imx_ldb_encoder_commit, .commit = imx_ldb_encoder_commit,
.mode_set = imx_ldb_encoder_mode_set, .mode_set = imx_ldb_encoder_mode_set,

View File

@ -286,13 +286,6 @@ static void imx_tve_encoder_dpms(struct drm_encoder *encoder, int mode)
dev_err(tve->dev, "failed to disable TVOUT: %d\n", ret); dev_err(tve->dev, "failed to disable TVOUT: %d\n", ret);
} }
static bool imx_tve_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void imx_tve_encoder_prepare(struct drm_encoder *encoder) static void imx_tve_encoder_prepare(struct drm_encoder *encoder)
{ {
struct imx_tve *tve = enc_to_tve(encoder); struct imx_tve *tve = enc_to_tve(encoder);
@ -379,7 +372,6 @@ static const struct drm_encoder_funcs imx_tve_encoder_funcs = {
static const struct drm_encoder_helper_funcs imx_tve_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs imx_tve_encoder_helper_funcs = {
.dpms = imx_tve_encoder_dpms, .dpms = imx_tve_encoder_dpms,
.mode_fixup = imx_tve_encoder_mode_fixup,
.prepare = imx_tve_encoder_prepare, .prepare = imx_tve_encoder_prepare,
.mode_set = imx_tve_encoder_mode_set, .mode_set = imx_tve_encoder_mode_set,
.commit = imx_tve_encoder_commit, .commit = imx_tve_encoder_commit,

View File

@ -112,13 +112,6 @@ static void imx_pd_encoder_dpms(struct drm_encoder *encoder, int mode)
drm_panel_enable(imxpd->panel); drm_panel_enable(imxpd->panel);
} }
static bool imx_pd_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void imx_pd_encoder_prepare(struct drm_encoder *encoder) static void imx_pd_encoder_prepare(struct drm_encoder *encoder)
{ {
struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
@ -166,7 +159,6 @@ static const struct drm_encoder_funcs imx_pd_encoder_funcs = {
static const struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
.dpms = imx_pd_encoder_dpms, .dpms = imx_pd_encoder_dpms,
.mode_fixup = imx_pd_encoder_mode_fixup,
.prepare = imx_pd_encoder_prepare, .prepare = imx_pd_encoder_prepare,
.commit = imx_pd_encoder_commit, .commit = imx_pd_encoder_commit,
.mode_set = imx_pd_encoder_mode_set, .mode_set = imx_pd_encoder_mode_set,

View File

@ -1479,13 +1479,6 @@ void mga_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
* These functions are analagous to those in the CRTC code, but are intended * These functions are analagous to those in the CRTC code, but are intended
* to handle any encoder-specific limitations * to handle any encoder-specific limitations
*/ */
static bool mga_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void mga_encoder_mode_set(struct drm_encoder *encoder, static void mga_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
@ -1515,7 +1508,6 @@ static void mga_encoder_destroy(struct drm_encoder *encoder)
static const struct drm_encoder_helper_funcs mga_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs mga_encoder_helper_funcs = {
.dpms = mga_encoder_dpms, .dpms = mga_encoder_dpms,
.mode_fixup = mga_encoder_mode_fixup,
.mode_set = mga_encoder_mode_set, .mode_set = mga_encoder_mode_set,
.prepare = mga_encoder_prepare, .prepare = mga_encoder_prepare,
.commit = mga_encoder_commit, .commit = mga_encoder_commit,

View File

@ -47,13 +47,6 @@ static const struct drm_encoder_funcs mdp4_dsi_encoder_funcs = {
.destroy = mdp4_dsi_encoder_destroy, .destroy = mdp4_dsi_encoder_destroy,
}; };
static bool mdp4_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void mdp4_dsi_encoder_mode_set(struct drm_encoder *encoder, static void mdp4_dsi_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
@ -163,7 +156,6 @@ static void mdp4_dsi_encoder_enable(struct drm_encoder *encoder)
} }
static const struct drm_encoder_helper_funcs mdp4_dsi_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs mdp4_dsi_encoder_helper_funcs = {
.mode_fixup = mdp4_dsi_encoder_mode_fixup,
.mode_set = mdp4_dsi_encoder_mode_set, .mode_set = mdp4_dsi_encoder_mode_set,
.disable = mdp4_dsi_encoder_disable, .disable = mdp4_dsi_encoder_disable,
.enable = mdp4_dsi_encoder_enable, .enable = mdp4_dsi_encoder_enable,

View File

@ -94,13 +94,6 @@ static const struct drm_encoder_funcs mdp4_dtv_encoder_funcs = {
.destroy = mdp4_dtv_encoder_destroy, .destroy = mdp4_dtv_encoder_destroy,
}; };
static bool mdp4_dtv_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder, static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
@ -234,7 +227,6 @@ static void mdp4_dtv_encoder_enable(struct drm_encoder *encoder)
} }
static const struct drm_encoder_helper_funcs mdp4_dtv_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs mdp4_dtv_encoder_helper_funcs = {
.mode_fixup = mdp4_dtv_encoder_mode_fixup,
.mode_set = mdp4_dtv_encoder_mode_set, .mode_set = mdp4_dtv_encoder_mode_set,
.enable = mdp4_dtv_encoder_enable, .enable = mdp4_dtv_encoder_enable,
.disable = mdp4_dtv_encoder_disable, .disable = mdp4_dtv_encoder_disable,

View File

@ -260,13 +260,6 @@ static void setup_phy(struct drm_encoder *encoder)
mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, lvds_phy_cfg0); mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, lvds_phy_cfg0);
} }
static bool mdp4_lcdc_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void mdp4_lcdc_encoder_mode_set(struct drm_encoder *encoder, static void mdp4_lcdc_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
@ -430,7 +423,6 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
} }
static const struct drm_encoder_helper_funcs mdp4_lcdc_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs mdp4_lcdc_encoder_helper_funcs = {
.mode_fixup = mdp4_lcdc_encoder_mode_fixup,
.mode_set = mdp4_lcdc_encoder_mode_set, .mode_set = mdp4_lcdc_encoder_mode_set,
.disable = mdp4_lcdc_encoder_disable, .disable = mdp4_lcdc_encoder_disable,
.enable = mdp4_lcdc_encoder_enable, .enable = mdp4_lcdc_encoder_enable,

View File

@ -188,13 +188,6 @@ static const struct drm_encoder_funcs mdp5_cmd_encoder_funcs = {
.destroy = mdp5_cmd_encoder_destroy, .destroy = mdp5_cmd_encoder_destroy,
}; };
static bool mdp5_cmd_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder, static void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
@ -256,7 +249,6 @@ static void mdp5_cmd_encoder_enable(struct drm_encoder *encoder)
} }
static const struct drm_encoder_helper_funcs mdp5_cmd_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs mdp5_cmd_encoder_helper_funcs = {
.mode_fixup = mdp5_cmd_encoder_mode_fixup,
.mode_set = mdp5_cmd_encoder_mode_set, .mode_set = mdp5_cmd_encoder_mode_set,
.disable = mdp5_cmd_encoder_disable, .disable = mdp5_cmd_encoder_disable,
.enable = mdp5_cmd_encoder_enable, .enable = mdp5_cmd_encoder_enable,
@ -340,4 +332,3 @@ fail:
return ERR_PTR(ret); return ERR_PTR(ret);
} }

View File

@ -112,13 +112,6 @@ static const struct drm_encoder_funcs mdp5_encoder_funcs = {
.destroy = mdp5_encoder_destroy, .destroy = mdp5_encoder_destroy,
}; };
static bool mdp5_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void mdp5_encoder_mode_set(struct drm_encoder *encoder, static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
@ -287,7 +280,6 @@ static void mdp5_encoder_enable(struct drm_encoder *encoder)
} }
static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
.mode_fixup = mdp5_encoder_mode_fixup,
.mode_set = mdp5_encoder_mode_set, .mode_set = mdp5_encoder_mode_set,
.disable = mdp5_encoder_disable, .disable = mdp5_encoder_disable,
.enable = mdp5_encoder_enable, .enable = mdp5_encoder_enable,

View File

@ -62,12 +62,8 @@ static int msm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma)
struct drm_fb_helper *helper = (struct drm_fb_helper *)info->par; struct drm_fb_helper *helper = (struct drm_fb_helper *)info->par;
struct msm_fbdev *fbdev = to_msm_fbdev(helper); struct msm_fbdev *fbdev = to_msm_fbdev(helper);
struct drm_gem_object *drm_obj = fbdev->bo; struct drm_gem_object *drm_obj = fbdev->bo;
struct drm_device *dev = helper->dev;
int ret = 0; int ret = 0;
if (drm_device_is_unplugged(dev))
return -ENODEV;
ret = drm_gem_mmap_obj(drm_obj, drm_obj->size, vma); ret = drm_gem_mmap_obj(drm_obj, drm_obj->size, vma);
if (ret) { if (ret) {
pr_err("%s:drm_gem_mmap_obj fail\n", __func__); pr_err("%s:drm_gem_mmap_obj fail\n", __func__);

View File

@ -314,7 +314,7 @@ void nouveau_register_dsm_handler(void)
if (!r) if (!r)
return; return;
vga_switcheroo_register_handler(&nouveau_dsm_handler); vga_switcheroo_register_handler(&nouveau_dsm_handler, 0);
} }
/* Must be called for Optimus models before the card can be turned off */ /* Must be called for Optimus models before the card can be turned off */

View File

@ -27,6 +27,7 @@
#include <acpi/button.h> #include <acpi/button.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/vga_switcheroo.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_edid.h> #include <drm/drm_edid.h>
@ -153,6 +154,17 @@ nouveau_connector_ddc_detect(struct drm_connector *connector)
if (ret == 0) if (ret == 0)
break; break;
} else } else
if ((vga_switcheroo_handler_flags() &
VGA_SWITCHEROO_CAN_SWITCH_DDC) &&
nv_encoder->dcb->type == DCB_OUTPUT_LVDS &&
nv_encoder->i2c) {
int ret;
vga_switcheroo_lock_ddc(dev->pdev);
ret = nvkm_probe_i2c(nv_encoder->i2c, 0x50);
vga_switcheroo_unlock_ddc(dev->pdev);
if (ret)
break;
} else
if (nv_encoder->i2c) { if (nv_encoder->i2c) {
if (nvkm_probe_i2c(nv_encoder->i2c, 0x50)) if (nvkm_probe_i2c(nv_encoder->i2c, 0x50))
break; break;
@ -265,7 +277,14 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
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) {
if ((vga_switcheroo_handler_flags() &
VGA_SWITCHEROO_CAN_SWITCH_DDC) &&
nv_connector->type == DCB_CONNECTOR_LVDS)
nv_connector->edid = drm_get_edid_switcheroo(connector,
i2c);
else
nv_connector->edid = drm_get_edid(connector, i2c); nv_connector->edid = drm_get_edid(connector, i2c);
drm_mode_connector_update_edid_property(connector, drm_mode_connector_update_edid_property(connector,
nv_connector->edid); nv_connector->edid);
if (!nv_connector->edid) { if (!nv_connector->edid) {

View File

@ -22,11 +22,13 @@
* Authors: Ben Skeggs * Authors: Ben Skeggs
*/ */
#include <linux/apple-gmux.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h> #include <linux/vga_switcheroo.h>
#include "drmP.h" #include "drmP.h"
@ -312,6 +314,15 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
bool boot = false; bool boot = false;
int ret; int ret;
/*
* apple-gmux is needed on dual GPU MacBook Pro
* to probe the panel if we're the inactive GPU.
*/
if (IS_ENABLED(CONFIG_VGA_ARB) && IS_ENABLED(CONFIG_VGA_SWITCHEROO) &&
apple_gmux_present() && pdev != vga_default_device() &&
!vga_switcheroo_handler_flags())
return -EPROBE_DEFER;
/* remove conflicting drivers (vesafb, efifb etc) */ /* remove conflicting drivers (vesafb, efifb etc) */
aper = alloc_apertures(3); aper = alloc_apertures(3);
if (!aper) if (!aper)

View File

@ -79,7 +79,7 @@ static void omap_gem_dmabuf_release(struct dma_buf *buffer)
static int omap_gem_dmabuf_begin_cpu_access(struct dma_buf *buffer, static int omap_gem_dmabuf_begin_cpu_access(struct dma_buf *buffer,
size_t start, size_t len, enum dma_data_direction dir) enum dma_data_direction dir)
{ {
struct drm_gem_object *obj = buffer->priv; struct drm_gem_object *obj = buffer->priv;
struct page **pages; struct page **pages;
@ -94,7 +94,7 @@ static int omap_gem_dmabuf_begin_cpu_access(struct dma_buf *buffer,
} }
static void omap_gem_dmabuf_end_cpu_access(struct dma_buf *buffer, static void omap_gem_dmabuf_end_cpu_access(struct dma_buf *buffer,
size_t start, size_t len, enum dma_data_direction dir) enum dma_data_direction dir)
{ {
struct drm_gem_object *obj = buffer->priv; struct drm_gem_object *obj = buffer->priv;
omap_gem_put_pages(obj); omap_gem_put_pages(obj);

View File

@ -734,14 +734,6 @@ static void qxl_enc_dpms(struct drm_encoder *encoder, int mode)
DRM_DEBUG("\n"); DRM_DEBUG("\n");
} }
static bool qxl_enc_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
DRM_DEBUG("\n");
return true;
}
static void qxl_enc_prepare(struct drm_encoder *encoder) static void qxl_enc_prepare(struct drm_encoder *encoder)
{ {
DRM_DEBUG("\n"); DRM_DEBUG("\n");
@ -864,7 +856,6 @@ static struct drm_encoder *qxl_best_encoder(struct drm_connector *connector)
static const struct drm_encoder_helper_funcs qxl_enc_helper_funcs = { static const struct drm_encoder_helper_funcs qxl_enc_helper_funcs = {
.dpms = qxl_enc_dpms, .dpms = qxl_enc_dpms,
.mode_fixup = qxl_enc_mode_fixup,
.prepare = qxl_enc_prepare, .prepare = qxl_enc_prepare,
.mode_set = qxl_enc_mode_set, .mode_set = qxl_enc_mode_set,
.commit = qxl_enc_commit, .commit = qxl_enc_commit,

View File

@ -2623,16 +2623,8 @@ radeon_atom_ext_dpms(struct drm_encoder *encoder, int mode)
} }
static bool radeon_atom_ext_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static const struct drm_encoder_helper_funcs radeon_atom_ext_helper_funcs = { static const struct drm_encoder_helper_funcs radeon_atom_ext_helper_funcs = {
.dpms = radeon_atom_ext_dpms, .dpms = radeon_atom_ext_dpms,
.mode_fixup = radeon_atom_ext_mode_fixup,
.prepare = radeon_atom_ext_prepare, .prepare = radeon_atom_ext_prepare,
.mode_set = radeon_atom_ext_mode_set, .mode_set = radeon_atom_ext_mode_set,
.commit = radeon_atom_ext_commit, .commit = radeon_atom_ext_commit,

View File

@ -551,13 +551,14 @@ static bool radeon_atpx_detect(void)
void radeon_register_atpx_handler(void) void radeon_register_atpx_handler(void)
{ {
bool r; bool r;
enum vga_switcheroo_handler_flags_t handler_flags = 0;
/* detect if we have any ATPX + 2 VGA in the system */ /* detect if we have any ATPX + 2 VGA in the system */
r = radeon_atpx_detect(); r = radeon_atpx_detect();
if (!r) if (!r)
return; return;
vga_switcheroo_register_handler(&radeon_atpx_handler); vga_switcheroo_register_handler(&radeon_atpx_handler, handler_flags);
} }
/** /**

View File

@ -34,6 +34,7 @@
#include "atom.h" #include "atom.h"
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/vga_switcheroo.h>
static int radeon_dp_handle_hpd(struct drm_connector *connector) static int radeon_dp_handle_hpd(struct drm_connector *connector)
{ {
@ -344,6 +345,11 @@ static void radeon_connector_get_edid(struct drm_connector *connector)
else if (radeon_connector->ddc_bus) else if (radeon_connector->ddc_bus)
radeon_connector->edid = drm_get_edid(&radeon_connector->base, radeon_connector->edid = drm_get_edid(&radeon_connector->base,
&radeon_connector->ddc_bus->adapter); &radeon_connector->ddc_bus->adapter);
} else if (vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC &&
connector->connector_type == DRM_MODE_CONNECTOR_LVDS &&
radeon_connector->ddc_bus) {
radeon_connector->edid = drm_get_edid_switcheroo(&radeon_connector->base,
&radeon_connector->ddc_bus->adapter);
} else if (radeon_connector->ddc_bus) { } else if (radeon_connector->ddc_bus) {
radeon_connector->edid = drm_get_edid(&radeon_connector->base, radeon_connector->edid = drm_get_edid(&radeon_connector->base,
&radeon_connector->ddc_bus->adapter); &radeon_connector->ddc_bus->adapter);

View File

@ -34,9 +34,11 @@
#include "radeon_drv.h" #include "radeon_drv.h"
#include <drm/drm_pciids.h> #include <drm/drm_pciids.h>
#include <linux/apple-gmux.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h> #include <linux/vga_switcheroo.h>
#include <drm/drm_gem.h> #include <drm/drm_gem.h>
@ -319,6 +321,15 @@ static int radeon_pci_probe(struct pci_dev *pdev,
{ {
int ret; int ret;
/*
* apple-gmux is needed on dual GPU MacBook Pro
* to probe the panel if we're the inactive GPU.
*/
if (IS_ENABLED(CONFIG_VGA_ARB) && IS_ENABLED(CONFIG_VGA_SWITCHEROO) &&
apple_gmux_present() && pdev != vga_default_device() &&
!vga_switcheroo_handler_flags())
return -EPROBE_DEFER;
/* Get rid of things like offb */ /* Get rid of things like offb */
ret = radeon_kick_out_firmware_fb(pdev); ret = radeon_kick_out_firmware_fb(pdev);
if (ret) if (ret)

View File

@ -875,13 +875,6 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
clk_disable_unprepare(dsi->pclk); clk_disable_unprepare(dsi->pclk);
} }
static bool dw_mipi_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder) static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
{ {
struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder); struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
@ -931,7 +924,6 @@ static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
static struct drm_encoder_helper_funcs static struct drm_encoder_helper_funcs
dw_mipi_dsi_encoder_helper_funcs = { dw_mipi_dsi_encoder_helper_funcs = {
.mode_fixup = dw_mipi_dsi_encoder_mode_fixup,
.commit = dw_mipi_dsi_encoder_commit, .commit = dw_mipi_dsi_encoder_commit,
.mode_set = dw_mipi_dsi_encoder_mode_set, .mode_set = dw_mipi_dsi_encoder_mode_set,
.disable = dw_mipi_dsi_encoder_disable, .disable = dw_mipi_dsi_encoder_disable,

View File

@ -440,13 +440,6 @@ static void sti_tvout_encoder_dpms(struct drm_encoder *encoder, int mode)
{ {
} }
static bool sti_tvout_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void sti_tvout_encoder_mode_set(struct drm_encoder *encoder, static void sti_tvout_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
@ -486,7 +479,6 @@ static void sti_dvo_encoder_disable(struct drm_encoder *encoder)
static const struct drm_encoder_helper_funcs sti_dvo_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs sti_dvo_encoder_helper_funcs = {
.dpms = sti_tvout_encoder_dpms, .dpms = sti_tvout_encoder_dpms,
.mode_fixup = sti_tvout_encoder_mode_fixup,
.mode_set = sti_tvout_encoder_mode_set, .mode_set = sti_tvout_encoder_mode_set,
.prepare = sti_tvout_encoder_prepare, .prepare = sti_tvout_encoder_prepare,
.commit = sti_dvo_encoder_commit, .commit = sti_dvo_encoder_commit,
@ -540,7 +532,6 @@ static void sti_hda_encoder_disable(struct drm_encoder *encoder)
static const struct drm_encoder_helper_funcs sti_hda_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs sti_hda_encoder_helper_funcs = {
.dpms = sti_tvout_encoder_dpms, .dpms = sti_tvout_encoder_dpms,
.mode_fixup = sti_tvout_encoder_mode_fixup,
.mode_set = sti_tvout_encoder_mode_set, .mode_set = sti_tvout_encoder_mode_set,
.prepare = sti_tvout_encoder_prepare, .prepare = sti_tvout_encoder_prepare,
.commit = sti_hda_encoder_commit, .commit = sti_hda_encoder_commit,
@ -589,7 +580,6 @@ static void sti_hdmi_encoder_disable(struct drm_encoder *encoder)
static const struct drm_encoder_helper_funcs sti_hdmi_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs sti_hdmi_encoder_helper_funcs = {
.dpms = sti_tvout_encoder_dpms, .dpms = sti_tvout_encoder_dpms,
.mode_fixup = sti_tvout_encoder_mode_fixup,
.mode_set = sti_tvout_encoder_mode_set, .mode_set = sti_tvout_encoder_mode_set,
.prepare = sti_tvout_encoder_prepare, .prepare = sti_tvout_encoder_prepare,
.commit = sti_hdmi_encoder_commit, .commit = sti_hdmi_encoder_commit,

View File

@ -70,14 +70,6 @@ static void panel_encoder_dpms(struct drm_encoder *encoder, int mode)
mode == DRM_MODE_DPMS_ON ? 1 : 0); mode == DRM_MODE_DPMS_ON ? 1 : 0);
} }
static bool panel_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
/* nothing needed */
return true;
}
static void panel_encoder_prepare(struct drm_encoder *encoder) static void panel_encoder_prepare(struct drm_encoder *encoder)
{ {
struct panel_encoder *panel_encoder = to_panel_encoder(encoder); struct panel_encoder *panel_encoder = to_panel_encoder(encoder);
@ -103,7 +95,6 @@ static const struct drm_encoder_funcs panel_encoder_funcs = {
static const struct drm_encoder_helper_funcs panel_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs panel_encoder_helper_funcs = {
.dpms = panel_encoder_dpms, .dpms = panel_encoder_dpms,
.mode_fixup = panel_encoder_mode_fixup,
.prepare = panel_encoder_prepare, .prepare = panel_encoder_prepare,
.commit = panel_encoder_commit, .commit = panel_encoder_commit,
.mode_set = panel_encoder_mode_set, .mode_set = panel_encoder_mode_set,

View File

@ -80,14 +80,6 @@ static void tfp410_encoder_dpms(struct drm_encoder *encoder, int mode)
tfp410_encoder->dpms = mode; tfp410_encoder->dpms = mode;
} }
static bool tfp410_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
/* nothing needed */
return true;
}
static void tfp410_encoder_prepare(struct drm_encoder *encoder) static void tfp410_encoder_prepare(struct drm_encoder *encoder)
{ {
tfp410_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); tfp410_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
@ -112,7 +104,6 @@ static const struct drm_encoder_funcs tfp410_encoder_funcs = {
static const struct drm_encoder_helper_funcs tfp410_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs tfp410_encoder_helper_funcs = {
.dpms = tfp410_encoder_dpms, .dpms = tfp410_encoder_dpms,
.mode_fixup = tfp410_encoder_mode_fixup,
.prepare = tfp410_encoder_prepare, .prepare = tfp410_encoder_prepare,
.commit = tfp410_encoder_commit, .commit = tfp410_encoder_commit,
.mode_set = tfp410_encoder_mode_set, .mode_set = tfp410_encoder_mode_set,

View File

@ -125,17 +125,5 @@ static struct usb_driver udl_driver = {
.disconnect = udl_usb_disconnect, .disconnect = udl_usb_disconnect,
.id_table = id_table, .id_table = id_table,
}; };
module_usb_driver(udl_driver);
static int __init udl_init(void)
{
return usb_register(&udl_driver);
}
static void __exit udl_exit(void)
{
usb_deregister(&udl_driver);
}
module_init(udl_init);
module_exit(udl_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View File

@ -26,13 +26,6 @@ static void udl_encoder_disable(struct drm_encoder *encoder)
{ {
} }
static bool udl_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void udl_encoder_prepare(struct drm_encoder *encoder) static void udl_encoder_prepare(struct drm_encoder *encoder)
{ {
} }
@ -54,7 +47,6 @@ udl_encoder_dpms(struct drm_encoder *encoder, int mode)
static const struct drm_encoder_helper_funcs udl_helper_funcs = { static const struct drm_encoder_helper_funcs udl_helper_funcs = {
.dpms = udl_encoder_dpms, .dpms = udl_encoder_dpms,
.mode_fixup = udl_mode_fixup,
.prepare = udl_encoder_prepare, .prepare = udl_encoder_prepare,
.mode_set = udl_encoder_mode_set, .mode_set = udl_encoder_mode_set,
.commit = udl_encoder_commit, .commit = udl_encoder_commit,

View File

@ -409,7 +409,6 @@ static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb,
if (ufb->obj->base.import_attach) { if (ufb->obj->base.import_attach) {
ret = dma_buf_begin_cpu_access(ufb->obj->base.import_attach->dmabuf, ret = dma_buf_begin_cpu_access(ufb->obj->base.import_attach->dmabuf,
0, ufb->obj->base.size,
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
if (ret) if (ret)
goto unlock; goto unlock;
@ -425,7 +424,6 @@ static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb,
if (ufb->obj->base.import_attach) { if (ufb->obj->base.import_attach) {
dma_buf_end_cpu_access(ufb->obj->base.import_attach->dmabuf, dma_buf_end_cpu_access(ufb->obj->base.import_attach->dmabuf,
0, ufb->obj->base.size,
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
} }

View File

@ -282,13 +282,6 @@ static const struct drm_crtc_helper_funcs virtio_gpu_crtc_helper_funcs = {
.atomic_check = virtio_gpu_crtc_atomic_check, .atomic_check = virtio_gpu_crtc_atomic_check,
}; };
static bool virtio_gpu_enc_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void virtio_gpu_enc_mode_set(struct drm_encoder *encoder, static void virtio_gpu_enc_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
@ -362,7 +355,6 @@ virtio_gpu_best_encoder(struct drm_connector *connector)
} }
static const struct drm_encoder_helper_funcs virtio_gpu_enc_helper_funcs = { static const struct drm_encoder_helper_funcs virtio_gpu_enc_helper_funcs = {
.mode_fixup = virtio_gpu_enc_mode_fixup,
.mode_set = virtio_gpu_enc_mode_set, .mode_set = virtio_gpu_enc_mode_set,
.enable = virtio_gpu_enc_enable, .enable = virtio_gpu_enc_enable,
.disable = virtio_gpu_enc_disable, .disable = virtio_gpu_enc_disable,

View File

@ -74,9 +74,17 @@
* there can thus be up to three clients: Two vga clients (GPUs) and one audio * there can thus be up to three clients: Two vga clients (GPUs) and one audio
* client (on the discrete GPU). The code is mostly prepared to support * client (on the discrete GPU). The code is mostly prepared to support
* machines with more than two GPUs should they become available. * machines with more than two GPUs should they become available.
*
* The GPU to which the outputs are currently switched is called the * The GPU to which the outputs are currently switched is called the
* active client in vga_switcheroo parlance. The GPU not in use is the * active client in vga_switcheroo parlance. The GPU not in use is the
* inactive client. * inactive client. When the inactive client's DRM driver is loaded,
* it will be unable to probe the panel's EDID and hence depends on
* VBIOS to provide its display modes. If the VBIOS modes are bogus or
* if there is no VBIOS at all (which is common on the MacBook Pro),
* a client may alternatively request that the DDC lines are temporarily
* switched to it, provided that the handler supports this. Switching
* only the DDC lines and not the entire output avoids unnecessary
* flickering.
*/ */
/** /**
@ -126,6 +134,10 @@ static DEFINE_MUTEX(vgasr_mutex);
* (counting only vga clients, not audio clients) * (counting only vga clients, not audio clients)
* @clients: list of registered clients * @clients: list of registered clients
* @handler: registered handler * @handler: registered handler
* @handler_flags: flags of registered handler
* @mux_hw_lock: protects mux state
* (in particular while DDC lines are temporarily switched)
* @old_ddc_owner: client to which DDC lines will be switched back on unlock
* *
* vga_switcheroo private data. Currently only one vga_switcheroo instance * vga_switcheroo private data. Currently only one vga_switcheroo instance
* per system is supported. * per system is supported.
@ -142,6 +154,9 @@ struct vgasr_priv {
struct list_head clients; struct list_head clients;
const struct vga_switcheroo_handler *handler; const struct vga_switcheroo_handler *handler;
enum vga_switcheroo_handler_flags_t handler_flags;
struct mutex mux_hw_lock;
int old_ddc_owner;
}; };
#define ID_BIT_AUDIO 0x100 #define ID_BIT_AUDIO 0x100
@ -156,6 +171,7 @@ static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv);
/* only one switcheroo per system */ /* only one switcheroo per system */
static struct vgasr_priv vgasr_priv = { static struct vgasr_priv vgasr_priv = {
.clients = LIST_HEAD_INIT(vgasr_priv.clients), .clients = LIST_HEAD_INIT(vgasr_priv.clients),
.mux_hw_lock = __MUTEX_INITIALIZER(vgasr_priv.mux_hw_lock),
}; };
static bool vga_switcheroo_ready(void) static bool vga_switcheroo_ready(void)
@ -190,13 +206,15 @@ static void vga_switcheroo_enable(void)
/** /**
* vga_switcheroo_register_handler() - register handler * vga_switcheroo_register_handler() - register handler
* @handler: handler callbacks * @handler: handler callbacks
* @handler_flags: handler flags
* *
* Register handler. Enable vga_switcheroo if two vga clients have already * Register handler. Enable vga_switcheroo if two vga clients have already
* registered. * registered.
* *
* Return: 0 on success, -EINVAL if a handler was already registered. * Return: 0 on success, -EINVAL if a handler was already registered.
*/ */
int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler) int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler,
enum vga_switcheroo_handler_flags_t handler_flags)
{ {
mutex_lock(&vgasr_mutex); mutex_lock(&vgasr_mutex);
if (vgasr_priv.handler) { if (vgasr_priv.handler) {
@ -205,6 +223,7 @@ int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler
} }
vgasr_priv.handler = handler; vgasr_priv.handler = handler;
vgasr_priv.handler_flags = handler_flags;
if (vga_switcheroo_ready()) { if (vga_switcheroo_ready()) {
pr_info("enabled\n"); pr_info("enabled\n");
vga_switcheroo_enable(); vga_switcheroo_enable();
@ -222,16 +241,33 @@ EXPORT_SYMBOL(vga_switcheroo_register_handler);
void vga_switcheroo_unregister_handler(void) void vga_switcheroo_unregister_handler(void)
{ {
mutex_lock(&vgasr_mutex); mutex_lock(&vgasr_mutex);
mutex_lock(&vgasr_priv.mux_hw_lock);
vgasr_priv.handler_flags = 0;
vgasr_priv.handler = NULL; vgasr_priv.handler = NULL;
if (vgasr_priv.active) { if (vgasr_priv.active) {
pr_info("disabled\n"); pr_info("disabled\n");
vga_switcheroo_debugfs_fini(&vgasr_priv); vga_switcheroo_debugfs_fini(&vgasr_priv);
vgasr_priv.active = false; vgasr_priv.active = false;
} }
mutex_unlock(&vgasr_priv.mux_hw_lock);
mutex_unlock(&vgasr_mutex); mutex_unlock(&vgasr_mutex);
} }
EXPORT_SYMBOL(vga_switcheroo_unregister_handler); EXPORT_SYMBOL(vga_switcheroo_unregister_handler);
/**
* vga_switcheroo_handler_flags() - obtain handler flags
*
* Helper for clients to obtain the handler flags bitmask.
*
* Return: Handler flags. A value of 0 means that no handler is registered
* or that the handler has no special capabilities.
*/
enum vga_switcheroo_handler_flags_t vga_switcheroo_handler_flags(void)
{
return vgasr_priv.handler_flags;
}
EXPORT_SYMBOL(vga_switcheroo_handler_flags);
static int register_client(struct pci_dev *pdev, static int register_client(struct pci_dev *pdev,
const struct vga_switcheroo_client_ops *ops, const struct vga_switcheroo_client_ops *ops,
enum vga_switcheroo_client_id id, bool active, enum vga_switcheroo_client_id id, bool active,
@ -412,6 +448,76 @@ void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
} }
EXPORT_SYMBOL(vga_switcheroo_client_fb_set); EXPORT_SYMBOL(vga_switcheroo_client_fb_set);
/**
* vga_switcheroo_lock_ddc() - temporarily switch DDC lines to a given client
* @pdev: client pci device
*
* Temporarily switch DDC lines to the client identified by @pdev
* (but leave the outputs otherwise switched to where they are).
* This allows the inactive client to probe EDID. The DDC lines must
* afterwards be switched back by calling vga_switcheroo_unlock_ddc(),
* even if this function returns an error.
*
* Return: Previous DDC owner on success or a negative int on error.
* Specifically, %-ENODEV if no handler has registered or if the handler
* does not support switching the DDC lines. Also, a negative value
* returned by the handler is propagated back to the caller.
* The return value has merely an informational purpose for any caller
* which might be interested in it. It is acceptable to ignore the return
* value and simply rely on the result of the subsequent EDID probe,
* which will be %NULL if DDC switching failed.
*/
int vga_switcheroo_lock_ddc(struct pci_dev *pdev)
{
enum vga_switcheroo_client_id id;
mutex_lock(&vgasr_priv.mux_hw_lock);
if (!vgasr_priv.handler || !vgasr_priv.handler->switch_ddc) {
vgasr_priv.old_ddc_owner = -ENODEV;
return -ENODEV;
}
id = vgasr_priv.handler->get_client_id(pdev);
vgasr_priv.old_ddc_owner = vgasr_priv.handler->switch_ddc(id);
return vgasr_priv.old_ddc_owner;
}
EXPORT_SYMBOL(vga_switcheroo_lock_ddc);
/**
* vga_switcheroo_unlock_ddc() - switch DDC lines back to previous owner
* @pdev: client pci device
*
* Switch DDC lines back to the previous owner after calling
* vga_switcheroo_lock_ddc(). This must be called even if
* vga_switcheroo_lock_ddc() returned an error.
*
* Return: Previous DDC owner on success (i.e. the client identifier of @pdev)
* or a negative int on error.
* Specifically, %-ENODEV if no handler has registered or if the handler
* does not support switching the DDC lines. Also, a negative value
* returned by the handler is propagated back to the caller.
* Finally, invoking this function without calling vga_switcheroo_lock_ddc()
* first is not allowed and will result in %-EINVAL.
*/
int vga_switcheroo_unlock_ddc(struct pci_dev *pdev)
{
enum vga_switcheroo_client_id id;
int ret = vgasr_priv.old_ddc_owner;
if (WARN_ON_ONCE(!mutex_is_locked(&vgasr_priv.mux_hw_lock)))
return -EINVAL;
if (vgasr_priv.old_ddc_owner >= 0) {
id = vgasr_priv.handler->get_client_id(pdev);
if (vgasr_priv.old_ddc_owner != id)
ret = vgasr_priv.handler->switch_ddc(
vgasr_priv.old_ddc_owner);
}
mutex_unlock(&vgasr_priv.mux_hw_lock);
return ret;
}
EXPORT_SYMBOL(vga_switcheroo_unlock_ddc);
/** /**
* DOC: Manual switching and manual power control * DOC: Manual switching and manual power control
* *
@ -549,7 +655,9 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
console_unlock(); console_unlock();
} }
mutex_lock(&vgasr_priv.mux_hw_lock);
ret = vgasr_priv.handler->switchto(new_client->id); ret = vgasr_priv.handler->switchto(new_client->id);
mutex_unlock(&vgasr_priv.mux_hw_lock);
if (ret) if (ret)
return ret; return ret;
@ -664,7 +772,9 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
vgasr_priv.delayed_switch_active = false; vgasr_priv.delayed_switch_active = false;
if (just_mux) { if (just_mux) {
mutex_lock(&vgasr_priv.mux_hw_lock);
ret = vgasr_priv.handler->switchto(client_id); ret = vgasr_priv.handler->switchto(client_id);
mutex_unlock(&vgasr_priv.mux_hw_lock);
goto out; goto out;
} }
@ -876,8 +986,11 @@ static int vga_switcheroo_runtime_suspend(struct device *dev)
if (ret) if (ret)
return ret; return ret;
mutex_lock(&vgasr_mutex); mutex_lock(&vgasr_mutex);
if (vgasr_priv.handler->switchto) if (vgasr_priv.handler->switchto) {
mutex_lock(&vgasr_priv.mux_hw_lock);
vgasr_priv.handler->switchto(VGA_SWITCHEROO_IGD); vgasr_priv.handler->switchto(VGA_SWITCHEROO_IGD);
mutex_unlock(&vgasr_priv.mux_hw_lock);
}
vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_OFF); vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_OFF);
mutex_unlock(&vgasr_mutex); mutex_unlock(&vgasr_mutex);
return 0; return 0;

View File

@ -19,6 +19,7 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/pnp.h> #include <linux/pnp.h>
#include <linux/apple_bl.h> #include <linux/apple_bl.h>
#include <linux/apple-gmux.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/pci.h> #include <linux/pci.h>
@ -57,7 +58,9 @@ struct apple_gmux_data {
/* switcheroo data */ /* switcheroo data */
acpi_handle dhandle; acpi_handle dhandle;
int gpe; int gpe;
enum vga_switcheroo_client_id resume_client_id; enum vga_switcheroo_client_id switch_state_display;
enum vga_switcheroo_client_id switch_state_ddc;
enum vga_switcheroo_client_id switch_state_external;
enum vga_switcheroo_state power_state; enum vga_switcheroo_state power_state;
struct completion powerchange_done; struct completion powerchange_done;
}; };
@ -368,21 +371,72 @@ static const struct backlight_ops gmux_bl_ops = {
* for the selected GPU. * for the selected GPU.
*/ */
static int gmux_switchto(enum vga_switcheroo_client_id id) static void gmux_read_switch_state(struct apple_gmux_data *gmux_data)
{ {
if (id == VGA_SWITCHEROO_IGD) { if (gmux_read8(gmux_data, GMUX_PORT_SWITCH_DDC) == 1)
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1); gmux_data->switch_state_ddc = VGA_SWITCHEROO_IGD;
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 2); else
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 2); gmux_data->switch_state_ddc = VGA_SWITCHEROO_DIS;
} else {
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2); if (gmux_read8(gmux_data, GMUX_PORT_SWITCH_DISPLAY) == 2)
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 3); gmux_data->switch_state_display = VGA_SWITCHEROO_IGD;
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3); else
gmux_data->switch_state_display = VGA_SWITCHEROO_DIS;
if (gmux_read8(gmux_data, GMUX_PORT_SWITCH_EXTERNAL) == 2)
gmux_data->switch_state_external = VGA_SWITCHEROO_IGD;
else
gmux_data->switch_state_external = VGA_SWITCHEROO_DIS;
} }
static void gmux_write_switch_state(struct apple_gmux_data *gmux_data)
{
if (gmux_data->switch_state_ddc == VGA_SWITCHEROO_IGD)
gmux_write8(gmux_data, GMUX_PORT_SWITCH_DDC, 1);
else
gmux_write8(gmux_data, GMUX_PORT_SWITCH_DDC, 2);
if (gmux_data->switch_state_display == VGA_SWITCHEROO_IGD)
gmux_write8(gmux_data, GMUX_PORT_SWITCH_DISPLAY, 2);
else
gmux_write8(gmux_data, GMUX_PORT_SWITCH_DISPLAY, 3);
if (gmux_data->switch_state_external == VGA_SWITCHEROO_IGD)
gmux_write8(gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 2);
else
gmux_write8(gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
}
static int gmux_switchto(enum vga_switcheroo_client_id id)
{
apple_gmux_data->switch_state_ddc = id;
apple_gmux_data->switch_state_display = id;
apple_gmux_data->switch_state_external = id;
gmux_write_switch_state(apple_gmux_data);
return 0; return 0;
} }
static int gmux_switch_ddc(enum vga_switcheroo_client_id id)
{
enum vga_switcheroo_client_id old_ddc_owner =
apple_gmux_data->switch_state_ddc;
if (id == old_ddc_owner)
return id;
pr_debug("Switching DDC from %d to %d\n", old_ddc_owner, id);
apple_gmux_data->switch_state_ddc = id;
if (id == VGA_SWITCHEROO_IGD)
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
else
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
return old_ddc_owner;
}
/** /**
* DOC: Power control * DOC: Power control
* *
@ -440,21 +494,19 @@ static int gmux_get_client_id(struct pci_dev *pdev)
return VGA_SWITCHEROO_DIS; return VGA_SWITCHEROO_DIS;
} }
static enum vga_switcheroo_client_id static const struct vga_switcheroo_handler gmux_handler_indexed = {
gmux_active_client(struct apple_gmux_data *gmux_data)
{
if (gmux_read8(gmux_data, GMUX_PORT_SWITCH_DISPLAY) == 2)
return VGA_SWITCHEROO_IGD;
return VGA_SWITCHEROO_DIS;
}
static const struct vga_switcheroo_handler gmux_handler = {
.switchto = gmux_switchto, .switchto = gmux_switchto,
.power_state = gmux_set_power_state, .power_state = gmux_set_power_state,
.get_client_id = gmux_get_client_id, .get_client_id = gmux_get_client_id,
}; };
static const struct vga_switcheroo_handler gmux_handler_classic = {
.switchto = gmux_switchto,
.switch_ddc = gmux_switch_ddc,
.power_state = gmux_set_power_state,
.get_client_id = gmux_get_client_id,
};
/** /**
* DOC: Interrupt * DOC: Interrupt
* *
@ -513,7 +565,6 @@ static int gmux_suspend(struct device *dev)
struct pnp_dev *pnp = to_pnp_dev(dev); struct pnp_dev *pnp = to_pnp_dev(dev);
struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp); struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
gmux_data->resume_client_id = gmux_active_client(gmux_data);
gmux_disable_interrupts(gmux_data); gmux_disable_interrupts(gmux_data);
return 0; return 0;
} }
@ -524,7 +575,7 @@ static int gmux_resume(struct device *dev)
struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp); struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
gmux_enable_interrupts(gmux_data); gmux_enable_interrupts(gmux_data);
gmux_switchto(gmux_data->resume_client_id); gmux_write_switch_state(gmux_data);
if (gmux_data->power_state == VGA_SWITCHEROO_OFF) if (gmux_data->power_state == VGA_SWITCHEROO_OFF)
gmux_set_discrete_state(gmux_data, gmux_data->power_state); gmux_set_discrete_state(gmux_data, gmux_data->power_state);
return 0; return 0;
@ -704,9 +755,23 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
apple_gmux_data = gmux_data; apple_gmux_data = gmux_data;
init_completion(&gmux_data->powerchange_done); init_completion(&gmux_data->powerchange_done);
gmux_enable_interrupts(gmux_data); gmux_enable_interrupts(gmux_data);
gmux_read_switch_state(gmux_data);
if (vga_switcheroo_register_handler(&gmux_handler)) { /*
ret = -ENODEV; * Retina MacBook Pros cannot switch the panel's AUX separately
* and need eDP pre-calibration. They are distinguishable from
* pre-retinas by having an "indexed" gmux.
*
* Pre-retina MacBook Pros can switch the panel's DDC separately.
*/
if (gmux_data->indexed)
ret = vga_switcheroo_register_handler(&gmux_handler_indexed,
VGA_SWITCHEROO_NEEDS_EDP_CONFIG);
else
ret = vga_switcheroo_register_handler(&gmux_handler_classic,
VGA_SWITCHEROO_CAN_SWITCH_DDC);
if (ret) {
pr_err("Failed to register vga_switcheroo handler\n");
goto err_register_handler; goto err_register_handler;
} }
@ -764,7 +829,7 @@ static void gmux_remove(struct pnp_dev *pnp)
} }
static const struct pnp_device_id gmux_device_ids[] = { static const struct pnp_device_id gmux_device_ids[] = {
{"APP000B", 0}, {GMUX_ACPI_HID, 0},
{"", 0} {"", 0}
}; };

View File

@ -1057,8 +1057,7 @@ static void ion_dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long offset,
{ {
} }
static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start, static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
size_t len,
enum dma_data_direction direction) enum dma_data_direction direction)
{ {
struct ion_buffer *buffer = dmabuf->priv; struct ion_buffer *buffer = dmabuf->priv;
@ -1076,8 +1075,7 @@ static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start,
return PTR_ERR_OR_ZERO(vaddr); return PTR_ERR_OR_ZERO(vaddr);
} }
static void ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf, size_t start, static void ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
size_t len,
enum dma_data_direction direction) enum dma_data_direction direction)
{ {
struct ion_buffer *buffer = dmabuf->priv; struct ion_buffer *buffer = dmabuf->priv;

View File

@ -109,7 +109,7 @@ static int ion_handle_test_kernel(struct dma_buf *dma_buf, void __user *ptr,
if (offset > dma_buf->size || size > dma_buf->size - offset) if (offset > dma_buf->size || size > dma_buf->size - offset)
return -EINVAL; return -EINVAL;
ret = dma_buf_begin_cpu_access(dma_buf, offset, size, dir); ret = dma_buf_begin_cpu_access(dma_buf, dir);
if (ret) if (ret)
return ret; return ret;
@ -139,7 +139,7 @@ static int ion_handle_test_kernel(struct dma_buf *dma_buf, void __user *ptr,
copy_offset = 0; copy_offset = 0;
} }
err: err:
dma_buf_end_cpu_access(dma_buf, offset, size, dir); dma_buf_end_cpu_access(dma_buf, dir);
return ret; return ret;
} }

View File

@ -307,6 +307,7 @@ struct drm_plane_helper_funcs;
* @connectors_changed: connectors to this crtc have been updated * @connectors_changed: connectors to this crtc have been updated
* @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
* @connector_mask: bitmask of (1 << drm_connector_index(connector)) of attached connectors * @connector_mask: bitmask of (1 << drm_connector_index(connector)) of attached connectors
* @encoder_mask: bitmask of (1 << drm_encoder_index(encoder)) of attached encoders
* @last_vblank_count: for helpers and drivers to capture the vblank of the * @last_vblank_count: for helpers and drivers to capture the vblank of the
* update to ensure framebuffer cleanup isn't done too early * update to ensure framebuffer cleanup isn't done too early
* @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings * @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings
@ -341,6 +342,7 @@ struct drm_crtc_state {
u32 plane_mask; u32 plane_mask;
u32 connector_mask; u32 connector_mask;
u32 encoder_mask;
/* last_vblank_count: for vblank waits before cleanup */ /* last_vblank_count: for vblank waits before cleanup */
u32 last_vblank_count; u32 last_vblank_count;
@ -2153,6 +2155,17 @@ struct drm_mode_config {
list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \ list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \
for_each_if ((plane_mask) & (1 << drm_plane_index(plane))) for_each_if ((plane_mask) & (1 << drm_plane_index(plane)))
/**
* drm_for_each_encoder_mask - iterate over encoders specified by bitmask
* @encoder: the loop cursor
* @dev: the DRM device
* @encoder_mask: bitmask of encoder indices
*
* Iterate over all encoders specified by bitmask.
*/
#define drm_for_each_encoder_mask(encoder, dev, encoder_mask) \
list_for_each_entry((encoder), &(dev)->mode_config.encoder_list, head) \
for_each_if ((encoder_mask) & (1 << drm_encoder_index(encoder)))
#define obj_to_crtc(x) container_of(x, struct drm_crtc, base) #define obj_to_crtc(x) container_of(x, struct drm_crtc, base)
#define obj_to_connector(x) container_of(x, struct drm_connector, base) #define obj_to_connector(x) container_of(x, struct drm_connector, base)
@ -2225,6 +2238,7 @@ int drm_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder, struct drm_encoder *encoder,
const struct drm_encoder_funcs *funcs, const struct drm_encoder_funcs *funcs,
int encoder_type, const char *name, ...); int encoder_type, const char *name, ...);
extern unsigned int drm_encoder_index(struct drm_encoder *encoder);
/** /**
* drm_encoder_crtc_ok - can a given crtc drive a given encoder? * drm_encoder_crtc_ok - can a given crtc drive a given encoder?
@ -2282,6 +2296,8 @@ extern void drm_property_destroy_user_blobs(struct drm_device *dev,
extern bool drm_probe_ddc(struct i2c_adapter *adapter); extern bool drm_probe_ddc(struct i2c_adapter *adapter);
extern struct edid *drm_get_edid(struct drm_connector *connector, extern struct edid *drm_get_edid(struct drm_connector *connector,
struct i2c_adapter *adapter); struct i2c_adapter *adapter);
extern struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
struct i2c_adapter *adapter);
extern struct edid *drm_edid_duplicate(const struct edid *edid); extern struct edid *drm_edid_duplicate(const struct edid *edid);
extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
extern void drm_mode_config_init(struct drm_device *dev); extern void drm_mode_config_init(struct drm_device *dev);
@ -2482,6 +2498,8 @@ extern int drm_format_num_planes(uint32_t format);
extern int drm_format_plane_cpp(uint32_t format, int plane); extern int drm_format_plane_cpp(uint32_t format, int plane);
extern int drm_format_horz_chroma_subsampling(uint32_t format); extern int drm_format_horz_chroma_subsampling(uint32_t format);
extern int drm_format_vert_chroma_subsampling(uint32_t format); extern int drm_format_vert_chroma_subsampling(uint32_t format);
extern int drm_format_plane_width(int width, uint32_t format, int plane);
extern int drm_format_plane_height(int height, uint32_t format, int plane);
extern const char *drm_get_format_name(uint32_t format); extern const char *drm_get_format_name(uint32_t format);
extern struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, extern struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
unsigned int supported_rotations); unsigned int supported_rotations);

View File

@ -0,0 +1,62 @@
/*
* Copyright © 2015 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Authors:
* Rafael Antognolli <rafael.antognolli@intel.com>
*
*/
#ifndef DRM_DP_AUX_DEV
#define DRM_DP_AUX_DEV
#include <drm/drm_dp_helper.h>
#ifdef CONFIG_DRM_DP_AUX_CHARDEV
int drm_dp_aux_dev_init(void);
void drm_dp_aux_dev_exit(void);
int drm_dp_aux_register_devnode(struct drm_dp_aux *aux);
void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux);
#else
static inline int drm_dp_aux_dev_init(void)
{
return 0;
}
static inline void drm_dp_aux_dev_exit(void)
{
}
static inline int drm_dp_aux_register_devnode(struct drm_dp_aux *aux)
{
return 0;
}
static inline void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux)
{
}
#endif
#endif

View File

@ -219,6 +219,7 @@ struct drm_fb_helper {
}; };
#ifdef CONFIG_DRM_FBDEV_EMULATION #ifdef CONFIG_DRM_FBDEV_EMULATION
int drm_fb_helper_modinit(void);
void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper, void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
const struct drm_fb_helper_funcs *funcs); const struct drm_fb_helper_funcs *funcs);
int drm_fb_helper_init(struct drm_device *dev, int drm_fb_helper_init(struct drm_device *dev,
@ -283,6 +284,11 @@ int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_
int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
struct drm_connector *connector); struct drm_connector *connector);
#else #else
static inline int drm_fb_helper_modinit(void)
{
return 0;
}
static inline void drm_fb_helper_prepare(struct drm_device *dev, static inline void drm_fb_helper_prepare(struct drm_device *dev,
struct drm_fb_helper *helper, struct drm_fb_helper *helper,
const struct drm_fb_helper_funcs *funcs) const struct drm_fb_helper_funcs *funcs)

View File

@ -439,7 +439,7 @@ struct drm_encoder_helper_funcs {
* can be modified by this callback and does not need to match mode. * can be modified by this callback and does not need to match mode.
* *
* This function is used by both legacy CRTC helpers and atomic helpers. * This function is used by both legacy CRTC helpers and atomic helpers.
* With atomic helpers it is optional. * This hook is optional.
* *
* NOTE: * NOTE:
* *

View File

@ -0,0 +1,50 @@
/*
* apple-gmux.h - microcontroller built into dual GPU MacBook Pro & Mac Pro
* Copyright (C) 2015 Lukas Wunner <lukas@wunner.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LINUX_APPLE_GMUX_H
#define LINUX_APPLE_GMUX_H
#include <linux/acpi.h>
#define GMUX_ACPI_HID "APP000B"
#if IS_ENABLED(CONFIG_APPLE_GMUX)
/**
* apple_gmux_present() - detect if gmux is built into the machine
*
* Drivers may use this to activate quirks specific to dual GPU MacBook Pros
* and Mac Pros, e.g. for deferred probing, runtime pm and backlight.
*
* Return: %true if gmux is present and the kernel was configured
* with CONFIG_APPLE_GMUX, %false otherwise.
*/
static inline bool apple_gmux_present(void)
{
return acpi_dev_present(GMUX_ACPI_HID);
}
#else /* !CONFIG_APPLE_GMUX */
static inline bool apple_gmux_present(void)
{
return false;
}
#endif /* !CONFIG_APPLE_GMUX */
#endif /* LINUX_APPLE_GMUX_H */

View File

@ -54,7 +54,7 @@ struct dma_buf_attachment;
* @release: release this buffer; to be called after the last dma_buf_put. * @release: release this buffer; to be called after the last dma_buf_put.
* @begin_cpu_access: [optional] called before cpu access to invalidate cpu * @begin_cpu_access: [optional] called before cpu access to invalidate cpu
* caches and allocate backing storage (if not yet done) * caches and allocate backing storage (if not yet done)
* respectively pin the objet into memory. * respectively pin the object into memory.
* @end_cpu_access: [optional] called after cpu access to flush caches. * @end_cpu_access: [optional] called after cpu access to flush caches.
* @kmap_atomic: maps a page from the buffer into kernel address * @kmap_atomic: maps a page from the buffer into kernel address
* space, users may not block until the subsequent unmap call. * space, users may not block until the subsequent unmap call.
@ -93,10 +93,8 @@ struct dma_buf_ops {
/* after final dma_buf_put() */ /* after final dma_buf_put() */
void (*release)(struct dma_buf *); void (*release)(struct dma_buf *);
int (*begin_cpu_access)(struct dma_buf *, size_t, size_t, int (*begin_cpu_access)(struct dma_buf *, enum dma_data_direction);
enum dma_data_direction); void (*end_cpu_access)(struct dma_buf *, enum dma_data_direction);
void (*end_cpu_access)(struct dma_buf *, size_t, size_t,
enum dma_data_direction);
void *(*kmap_atomic)(struct dma_buf *, unsigned long); void *(*kmap_atomic)(struct dma_buf *, unsigned long);
void (*kunmap_atomic)(struct dma_buf *, unsigned long, void *); void (*kunmap_atomic)(struct dma_buf *, unsigned long, void *);
void *(*kmap)(struct dma_buf *, unsigned long); void *(*kmap)(struct dma_buf *, unsigned long);
@ -224,9 +222,9 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *,
enum dma_data_direction); enum dma_data_direction);
void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct sg_table *, void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct sg_table *,
enum dma_data_direction); enum dma_data_direction);
int dma_buf_begin_cpu_access(struct dma_buf *dma_buf, size_t start, size_t len, int dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
enum dma_data_direction dir); enum dma_data_direction dir);
void dma_buf_end_cpu_access(struct dma_buf *dma_buf, size_t start, size_t len, void dma_buf_end_cpu_access(struct dma_buf *dma_buf,
enum dma_data_direction dir); enum dma_data_direction dir);
void *dma_buf_kmap_atomic(struct dma_buf *, unsigned long); void *dma_buf_kmap_atomic(struct dma_buf *, unsigned long);
void dma_buf_kunmap_atomic(struct dma_buf *, unsigned long, void *); void dma_buf_kunmap_atomic(struct dma_buf *, unsigned long, void *);

View File

@ -35,6 +35,26 @@
struct pci_dev; struct pci_dev;
/**
* enum vga_switcheroo_handler_flags_t - handler flags bitmask
* @VGA_SWITCHEROO_CAN_SWITCH_DDC: whether the handler is able to switch the
* DDC lines separately. This signals to clients that they should call
* drm_get_edid_switcheroo() to probe the EDID
* @VGA_SWITCHEROO_NEEDS_EDP_CONFIG: whether the handler is unable to switch
* the AUX channel separately. This signals to clients that the active
* GPU needs to train the link and communicate the link parameters to the
* inactive GPU (mediated by vga_switcheroo). The inactive GPU may then
* skip the AUX handshake and set up its output with these pre-calibrated
* values (DisplayPort specification v1.1a, section 2.5.3.3)
*
* Handler flags bitmask. Used by handlers to declare their capabilities upon
* registering with vga_switcheroo.
*/
enum vga_switcheroo_handler_flags_t {
VGA_SWITCHEROO_CAN_SWITCH_DDC = (1 << 0),
VGA_SWITCHEROO_NEEDS_EDP_CONFIG = (1 << 1),
};
/** /**
* enum vga_switcheroo_state - client power state * enum vga_switcheroo_state - client power state
* @VGA_SWITCHEROO_OFF: off * @VGA_SWITCHEROO_OFF: off
@ -82,6 +102,9 @@ enum vga_switcheroo_client_id {
* Mandatory. For muxless machines this should be a no-op. Returning 0 * Mandatory. For muxless machines this should be a no-op. Returning 0
* denotes success, anything else failure (in which case the switch is * denotes success, anything else failure (in which case the switch is
* aborted) * aborted)
* @switch_ddc: switch DDC lines to given client.
* Optional. Should return the previous DDC owner on success or a
* negative int on failure
* @power_state: cut or reinstate power of given client. * @power_state: cut or reinstate power of given client.
* Optional. The return value is ignored * Optional. The return value is ignored
* @get_client_id: determine if given pci device is integrated or discrete GPU. * @get_client_id: determine if given pci device is integrated or discrete GPU.
@ -93,6 +116,7 @@ enum vga_switcheroo_client_id {
struct vga_switcheroo_handler { struct vga_switcheroo_handler {
int (*init)(void); int (*init)(void);
int (*switchto)(enum vga_switcheroo_client_id id); int (*switchto)(enum vga_switcheroo_client_id id);
int (*switch_ddc)(enum vga_switcheroo_client_id id);
int (*power_state)(enum vga_switcheroo_client_id id, int (*power_state)(enum vga_switcheroo_client_id id,
enum vga_switcheroo_state state); enum vga_switcheroo_state state);
enum vga_switcheroo_client_id (*get_client_id)(struct pci_dev *pdev); enum vga_switcheroo_client_id (*get_client_id)(struct pci_dev *pdev);
@ -132,8 +156,12 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
void vga_switcheroo_client_fb_set(struct pci_dev *dev, void vga_switcheroo_client_fb_set(struct pci_dev *dev,
struct fb_info *info); struct fb_info *info);
int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler); int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler,
enum vga_switcheroo_handler_flags_t handler_flags);
void vga_switcheroo_unregister_handler(void); void vga_switcheroo_unregister_handler(void);
enum vga_switcheroo_handler_flags_t vga_switcheroo_handler_flags(void);
int vga_switcheroo_lock_ddc(struct pci_dev *pdev);
int vga_switcheroo_unlock_ddc(struct pci_dev *pdev);
int vga_switcheroo_process_delayed_switch(void); int vga_switcheroo_process_delayed_switch(void);
@ -150,11 +178,15 @@ static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {}
static inline int vga_switcheroo_register_client(struct pci_dev *dev, static inline int vga_switcheroo_register_client(struct pci_dev *dev,
const struct vga_switcheroo_client_ops *ops, bool driver_power_control) { return 0; } const struct vga_switcheroo_client_ops *ops, bool driver_power_control) { return 0; }
static inline void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct fb_info *info) {} static inline void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct fb_info *info) {}
static inline int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler) { return 0; } static inline int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler,
enum vga_switcheroo_handler_flags_t handler_flags) { return 0; }
static inline int vga_switcheroo_register_audio_client(struct pci_dev *pdev, static inline int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
const struct vga_switcheroo_client_ops *ops, const struct vga_switcheroo_client_ops *ops,
enum vga_switcheroo_client_id id) { return 0; } enum vga_switcheroo_client_id id) { return 0; }
static inline void vga_switcheroo_unregister_handler(void) {} static inline void vga_switcheroo_unregister_handler(void) {}
static inline enum vga_switcheroo_handler_flags_t vga_switcheroo_handler_flags(void) { return 0; }
static inline int vga_switcheroo_lock_ddc(struct pci_dev *pdev) { return -ENODEV; }
static inline int vga_switcheroo_unlock_ddc(struct pci_dev *pdev) { return -ENODEV; }
static inline int vga_switcheroo_process_delayed_switch(void) { return 0; } static inline int vga_switcheroo_process_delayed_switch(void) { return 0; }
static inline enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev) { return VGA_SWITCHEROO_ON; } static inline enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev) { return VGA_SWITCHEROO_ON; }

View File

@ -669,6 +669,7 @@ struct drm_set_client_cap {
__u64 value; __u64 value;
}; };
#define DRM_RDWR O_RDWR
#define DRM_CLOEXEC O_CLOEXEC #define DRM_CLOEXEC O_CLOEXEC
struct drm_prime_handle { struct drm_prime_handle {
__u32 handle; __u32 handle;

View File

@ -0,0 +1,40 @@
/*
* Framework for buffer objects that can be shared across devices/subsystems.
*
* Copyright(C) 2015 Intel Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DMA_BUF_UAPI_H_
#define _DMA_BUF_UAPI_H_
#include <linux/types.h>
/* begin/end dma-buf functions used for userspace mmap. */
struct dma_buf_sync {
__u64 flags;
};
#define DMA_BUF_SYNC_READ (1 << 0)
#define DMA_BUF_SYNC_WRITE (2 << 0)
#define DMA_BUF_SYNC_RW (DMA_BUF_SYNC_READ | DMA_BUF_SYNC_WRITE)
#define DMA_BUF_SYNC_START (0 << 2)
#define DMA_BUF_SYNC_END (1 << 2)
#define DMA_BUF_SYNC_VALID_FLAGS_MASK \
(DMA_BUF_SYNC_RW | DMA_BUF_SYNC_END)
#define DMA_BUF_BASE 'b'
#define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
#endif