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:
commit
08244c0085
|
@ -3422,6 +3422,7 @@ int num_ioctls;</synopsis>
|
|||
</sect1>
|
||||
<sect1>
|
||||
<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_state
|
||||
</sect1>
|
||||
|
@ -3450,6 +3451,10 @@ int num_ioctls;</synopsis>
|
|||
<title>Backlight control</title>
|
||||
!Pdrivers/platform/x86/apple-gmux.c Backlight control
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>Public functions</title>
|
||||
!Iinclude/linux/apple-gmux.h
|
||||
</sect2>
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
||||
|
|
|
@ -257,17 +257,15 @@ Access to a dma_buf from the kernel context involves three steps:
|
|||
|
||||
Interface:
|
||||
int dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
|
||||
size_t start, size_t len,
|
||||
enum dma_data_direction direction)
|
||||
|
||||
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
|
||||
backing storage. The exporter also needs to ensure that cpu access is
|
||||
coherent for the given range and access direction. The range and access
|
||||
direction can be used by the exporter to optimize the cache flushing, i.e.
|
||||
access outside of the range or with a different direction (read instead of
|
||||
write) might return stale or even bogus data (e.g. when the exporter needs to
|
||||
copy the data to temporary storage).
|
||||
coherent for the access direction. The direction can be used by the exporter
|
||||
to optimize the cache flushing, i.e. access with a different direction (read
|
||||
instead of write) might return stale or even bogus data (e.g. when the
|
||||
exporter needs to copy the data to temporary storage).
|
||||
|
||||
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
|
||||
|
||||
When the importer is done accessing the range specified in begin_cpu_access,
|
||||
it needs to announce this to the exporter (to facilitate cache flushing and
|
||||
unpinning of any pinned resources). The result of any dma_buf kmap calls
|
||||
after end_cpu_access is undefined.
|
||||
When the importer is done accessing the CPU, it needs to announce this to
|
||||
the exporter (to facilitate cache flushing and unpinning of any pinned
|
||||
resources). The result of any dma_buf kmap calls after end_cpu_access is
|
||||
undefined.
|
||||
|
||||
Interface:
|
||||
void dma_buf_end_cpu_access(struct dma_buf *dma_buf,
|
||||
size_t start, size_t len,
|
||||
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
|
||||
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
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include <linux/poll.h>
|
||||
#include <linux/reservation.h>
|
||||
|
||||
#include <uapi/linux/dma-buf.h>
|
||||
|
||||
static inline int is_dma_buf_file(struct file *);
|
||||
|
||||
struct dma_buf_list {
|
||||
|
@ -251,11 +253,54 @@ out:
|
|||
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 = {
|
||||
.release = dma_buf_release,
|
||||
.mmap = dma_buf_mmap_internal,
|
||||
.llseek = dma_buf_llseek,
|
||||
.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
|
||||
* specified access direction.
|
||||
* @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.
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
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;
|
||||
|
||||
if (dmabuf->ops->begin_cpu_access)
|
||||
ret = dmabuf->ops->begin_cpu_access(dmabuf, start,
|
||||
len, direction);
|
||||
ret = dmabuf->ops->begin_cpu_access(dmabuf, direction);
|
||||
|
||||
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
|
||||
* specified access direction.
|
||||
* @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.
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
WARN_ON(!dmabuf);
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -25,6 +25,14 @@ config DRM_MIPI_DSI
|
|||
bool
|
||||
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
|
||||
tristate
|
||||
depends on DRM
|
||||
|
|
|
@ -22,10 +22,13 @@ drm-$(CONFIG_OF) += drm_of.o
|
|||
drm-$(CONFIG_AGP) += drm_agpsupport.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_FBDEV_EMULATION) += drm_fb_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
|
||||
|
||||
|
|
|
@ -552,13 +552,14 @@ static bool amdgpu_atpx_detect(void)
|
|||
void amdgpu_register_atpx_handler(void)
|
||||
{
|
||||
bool r;
|
||||
enum vga_switcheroo_handler_flags_t handler_flags = 0;
|
||||
|
||||
/* detect if we have any ATPX + 2 VGA in the system */
|
||||
r = amdgpu_atpx_detect();
|
||||
if (!r)
|
||||
return;
|
||||
|
||||
vga_switcheroo_register_handler(&amdgpu_atpx_handler);
|
||||
vga_switcheroo_register_handler(&amdgpu_atpx_handler, handler_flags);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 = {
|
||||
.dpms = dce_v10_0_ext_dpms,
|
||||
.mode_fixup = dce_v10_0_ext_mode_fixup,
|
||||
.prepare = dce_v10_0_ext_prepare,
|
||||
.mode_set = dce_v10_0_ext_mode_set,
|
||||
.commit = dce_v10_0_ext_commit,
|
||||
|
|
|
@ -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 = {
|
||||
.dpms = dce_v11_0_ext_dpms,
|
||||
.mode_fixup = dce_v11_0_ext_mode_fixup,
|
||||
.prepare = dce_v11_0_ext_prepare,
|
||||
.mode_set = dce_v11_0_ext_mode_set,
|
||||
.commit = dce_v11_0_ext_commit,
|
||||
|
|
|
@ -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 = {
|
||||
.dpms = dce_v8_0_ext_dpms,
|
||||
.mode_fixup = dce_v8_0_ext_mode_fixup,
|
||||
.prepare = dce_v8_0_ext_prepare,
|
||||
.mode_set = dce_v8_0_ext_mode_set,
|
||||
.commit = dce_v8_0_ext_commit,
|
||||
|
|
|
@ -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,
|
||||
struct drm_display_mode *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 = {
|
||||
.dpms = ast_encoder_dpms,
|
||||
.mode_fixup = ast_mode_fixup,
|
||||
.prepare = ast_encoder_prepare,
|
||||
.commit = ast_encoder_commit,
|
||||
.mode_set = ast_encoder_mode_set,
|
||||
|
|
|
@ -152,13 +152,6 @@ static void bochs_crtc_init(struct drm_device *dev)
|
|||
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,
|
||||
struct drm_display_mode *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 = {
|
||||
.dpms = bochs_encoder_dpms,
|
||||
.mode_fixup = bochs_encoder_mode_fixup,
|
||||
.mode_set = bochs_encoder_mode_set,
|
||||
.prepare = bochs_encoder_prepare,
|
||||
.commit = bochs_encoder_commit,
|
||||
|
|
|
@ -1391,13 +1391,6 @@ static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
|
|||
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)
|
||||
{
|
||||
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,
|
||||
.post_disable = dw_hdmi_bridge_nop,
|
||||
.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)
|
||||
|
|
|
@ -430,14 +430,6 @@ void cirrus_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
|
|||
*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,
|
||||
struct drm_display_mode *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 = {
|
||||
.dpms = cirrus_encoder_dpms,
|
||||
.mode_fixup = cirrus_encoder_mode_fixup,
|
||||
.mode_set = cirrus_encoder_mode_set,
|
||||
.prepare = cirrus_encoder_prepare,
|
||||
.commit = cirrus_encoder_commit,
|
||||
|
|
|
@ -125,6 +125,47 @@ get_current_crtc_for_encoder(struct drm_device *dev,
|
|||
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
|
||||
steal_encoder(struct drm_atomic_state *state,
|
||||
struct drm_encoder *encoder,
|
||||
|
@ -134,7 +175,6 @@ steal_encoder(struct drm_atomic_state *state,
|
|||
struct drm_crtc_state *crtc_state;
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_state *connector_state;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* 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))
|
||||
return PTR_ERR(connector_state);
|
||||
|
||||
ret = drm_atomic_set_crtc_for_connector(connector_state, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
connector_state->best_encoder = NULL;
|
||||
if (connector_state->best_encoder != encoder)
|
||||
continue;
|
||||
|
||||
set_best_encoder(state, connector_state, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -216,7 +256,7 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
|
|||
connector->base.id,
|
||||
connector->name);
|
||||
|
||||
connector_state->best_encoder = NULL;
|
||||
set_best_encoder(state, connector_state, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -245,6 +285,8 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
|
|||
}
|
||||
|
||||
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",
|
||||
connector->base.id,
|
||||
connector->name,
|
||||
|
@ -279,7 +321,8 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
|
|||
if (WARN_ON(!connector_state->crtc))
|
||||
return -EINVAL;
|
||||
|
||||
connector_state->best_encoder = new_encoder;
|
||||
set_best_encoder(state, connector_state, new_encoder);
|
||||
|
||||
idx = drm_crtc_index(connector_state->crtc);
|
||||
|
||||
crtc_state = state->crtc_states[idx];
|
||||
|
|
|
@ -1160,6 +1160,29 @@ out_unlock:
|
|||
}
|
||||
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
|
||||
* @encoder: encoder to cleanup
|
||||
|
@ -5714,6 +5737,48 @@ int drm_format_vert_chroma_subsampling(uint32_t format)
|
|||
}
|
||||
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
|
||||
* @rotation: Rotation to be simplified
|
||||
|
|
|
@ -73,9 +73,6 @@
|
|||
* &drm_crtc_helper_funcs, struct &drm_encoder_helper_funcs and struct
|
||||
* &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
|
||||
|
@ -337,16 +334,21 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
|
|||
}
|
||||
|
||||
encoder_funcs = encoder->helper_private;
|
||||
if (!(ret = encoder_funcs->mode_fixup(encoder, mode,
|
||||
adjusted_mode))) {
|
||||
DRM_DEBUG_KMS("Encoder fixup failed\n");
|
||||
goto done;
|
||||
if (encoder_funcs->mode_fixup) {
|
||||
if (!(ret = encoder_funcs->mode_fixup(encoder, mode,
|
||||
adjusted_mode))) {
|
||||
DRM_DEBUG_KMS("Encoder fixup failed\n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) {
|
||||
DRM_DEBUG_KMS("CRTC fixup failed\n");
|
||||
goto done;
|
||||
if (crtc_funcs->mode_fixup) {
|
||||
if (!(ret = crtc_funcs->mode_fixup(crtc, mode,
|
||||
adjusted_mode))) {
|
||||
DRM_DEBUG_KMS("CRTC fixup failed\n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <drm/drm_dp_helper.h>
|
||||
#include <drm/drm_dp_aux_dev.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 ret;
|
||||
|
||||
mutex_init(&aux->hw_mutex);
|
||||
|
||||
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),
|
||||
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);
|
||||
|
||||
|
@ -778,6 +791,7 @@ EXPORT_SYMBOL(drm_dp_aux_register);
|
|||
*/
|
||||
void drm_dp_aux_unregister(struct drm_dp_aux *aux)
|
||||
{
|
||||
drm_dp_aux_unregister_devnode(aux);
|
||||
i2c_del_adapter(&aux->ddc);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_aux_unregister);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <linux/hdmi.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/vga_switcheroo.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_displayid.h>
|
||||
|
@ -1394,6 +1395,31 @@ struct edid *drm_get_edid(struct drm_connector *connector,
|
|||
}
|
||||
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
|
||||
* @edid: EDID to duplicate
|
||||
|
|
|
@ -140,6 +140,9 @@ bool drm_i2c_encoder_mode_fixup(struct drm_encoder *encoder,
|
|||
const struct drm_display_mode *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);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_i2c_encoder_mode_fixup);
|
||||
|
|
|
@ -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_connector *connector;
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
if (!drm_fbdev_emulation)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
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 (!fb_helper_connector)
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
fb_helper_connector->connector = connector;
|
||||
fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector;
|
||||
}
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
return 0;
|
||||
|
@ -130,7 +126,7 @@ fail:
|
|||
fb_helper->connector_count = 0;
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
||||
return -ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
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;
|
||||
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);
|
||||
modes = kcalloc(dev->mode_config.num_connector,
|
||||
modes = kcalloc(fb_helper->connector_count,
|
||||
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);
|
||||
enabled = kcalloc(dev->mode_config.num_connector,
|
||||
enabled = kcalloc(fb_helper->connector_count,
|
||||
sizeof(bool), GFP_KERNEL);
|
||||
if (!crtcs || !modes || !enabled || !offsets) {
|
||||
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,
|
||||
offsets,
|
||||
enabled, width, height))) {
|
||||
memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0]));
|
||||
memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0]));
|
||||
memset(offsets, 0, dev->mode_config.num_connector*sizeof(offsets[0]));
|
||||
memset(modes, 0, fb_helper->connector_count*sizeof(modes[0]));
|
||||
memset(crtcs, 0, fb_helper->connector_count*sizeof(crtcs[0]));
|
||||
memset(offsets, 0, fb_helper->connector_count*sizeof(offsets[0]));
|
||||
|
||||
if (!drm_target_cloned(fb_helper, modes, offsets,
|
||||
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
|
||||
* attempt to load fbcon to avoid leaving the system without a usable console.
|
||||
*/
|
||||
#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
|
||||
static int __init drm_fb_helper_modinit(void)
|
||||
int __init drm_fb_helper_modinit(void)
|
||||
{
|
||||
#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
|
||||
const char *name = "fbcon";
|
||||
struct module *fbcon;
|
||||
|
||||
|
@ -2208,8 +2204,7 @@ static int __init drm_fb_helper_modinit(void)
|
|||
|
||||
if (!fbcon)
|
||||
request_module_nowait(name);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(drm_fb_helper_modinit);
|
||||
#endif
|
||||
EXPORT_SYMBOL(drm_fb_helper_modinit);
|
||||
|
|
|
@ -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);
|
|
@ -1371,8 +1371,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
|
|||
}
|
||||
done:
|
||||
if (i >= 0) {
|
||||
printk(KERN_WARNING
|
||||
"parse error at position %i in video mode '%s'\n",
|
||||
pr_warn("[drm] parse error at position %i in video mode '%s'\n",
|
||||
i, name);
|
||||
mode->specified = false;
|
||||
return false;
|
||||
|
|
|
@ -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
|
||||
* @dev: drm_device to export from
|
||||
* @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
|
||||
* 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_prime_handle *args = data;
|
||||
uint32_t flags;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_PRIME))
|
||||
return -EINVAL;
|
||||
|
@ -637,14 +636,11 @@ int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
|
|||
return -ENOSYS;
|
||||
|
||||
/* check flags are valid */
|
||||
if (args->flags & ~DRM_CLOEXEC)
|
||||
if (args->flags & ~(DRM_CLOEXEC | DRM_RDWR))
|
||||
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,
|
||||
args->handle, flags, &args->fd);
|
||||
args->handle, args->flags, &args->fd);
|
||||
}
|
||||
|
||||
int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
|
||||
|
|
|
@ -1155,13 +1155,6 @@ static int exynos_dp_create_connector(struct drm_encoder *encoder)
|
|||
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,
|
||||
struct drm_display_mode *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 = {
|
||||
.mode_fixup = exynos_dp_mode_fixup,
|
||||
.mode_set = exynos_dp_mode_set,
|
||||
.enable = exynos_dp_enable,
|
||||
.disable = exynos_dp_disable,
|
||||
|
|
|
@ -128,13 +128,6 @@ static int exynos_dpi_create_connector(struct drm_encoder *encoder)
|
|||
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,
|
||||
struct drm_display_mode *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 = {
|
||||
.mode_fixup = exynos_dpi_mode_fixup,
|
||||
.mode_set = exynos_dpi_mode_set,
|
||||
.enable = exynos_dpi_enable,
|
||||
.disable = exynos_dpi_disable,
|
||||
|
|
|
@ -1597,13 +1597,6 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder)
|
|||
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,
|
||||
struct drm_display_mode *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 = {
|
||||
.mode_fixup = exynos_dsi_mode_fixup,
|
||||
.mode_set = exynos_dsi_mode_set,
|
||||
.enable = exynos_dsi_enable,
|
||||
.disable = exynos_dsi_disable,
|
||||
|
|
|
@ -410,13 +410,6 @@ static int vidi_create_connector(struct drm_encoder *encoder)
|
|||
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,
|
||||
struct drm_display_mode *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 = {
|
||||
.mode_fixup = exynos_vidi_mode_fixup,
|
||||
.mode_set = exynos_vidi_mode_set,
|
||||
.enable = exynos_vidi_enable,
|
||||
.disable = exynos_vidi_disable,
|
||||
|
|
|
@ -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 = {
|
||||
.dpms = cdv_intel_crt_dpms,
|
||||
.mode_fixup = gma_encoder_mode_fixup,
|
||||
.prepare = gma_encoder_prepare,
|
||||
.commit = gma_encoder_commit,
|
||||
.mode_set = cdv_intel_crt_mode_set,
|
||||
|
|
|
@ -255,7 +255,6 @@ static void cdv_hdmi_destroy(struct drm_connector *connector)
|
|||
|
||||
static const struct drm_encoder_helper_funcs cdv_hdmi_helper_funcs = {
|
||||
.dpms = cdv_hdmi_dpms,
|
||||
.mode_fixup = gma_encoder_mode_fixup,
|
||||
.prepare = gma_encoder_prepare,
|
||||
.mode_set = cdv_hdmi_mode_set,
|
||||
.commit = gma_encoder_commit,
|
||||
|
|
|
@ -478,13 +478,6 @@ int gma_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
|
|||
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,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
|
|
|
@ -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_commit(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 */
|
||||
extern const struct gma_limit_t *gma_limit(struct drm_crtc *crtc, int refclk);
|
||||
|
|
|
@ -436,7 +436,7 @@ int gma_intel_setup_gmbus(struct drm_device *dev)
|
|||
return 0;
|
||||
|
||||
err:
|
||||
while (--i) {
|
||||
while (i--) {
|
||||
struct intel_gmbus *bus = &dev_priv->gmbus[i];
|
||||
i2c_del_adapter(&bus->adapter);
|
||||
}
|
||||
|
|
|
@ -601,7 +601,6 @@ static void oaktrail_hdmi_destroy(struct drm_connector *connector)
|
|||
|
||||
static const struct drm_encoder_helper_funcs oaktrail_hdmi_helper_funcs = {
|
||||
.dpms = oaktrail_hdmi_dpms,
|
||||
.mode_fixup = gma_encoder_mode_fixup,
|
||||
.prepare = gma_encoder_prepare,
|
||||
.mode_set = oaktrail_hdmi_mode_set,
|
||||
.commit = gma_encoder_commit,
|
||||
|
|
|
@ -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);
|
||||
|
||||
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,
|
||||
priv->select_subconnector);
|
||||
|
|
|
@ -252,14 +252,6 @@ sil164_encoder_restore(struct drm_encoder *encoder)
|
|||
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
|
||||
sil164_encoder_mode_valid(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode)
|
||||
|
@ -347,7 +339,6 @@ static const struct drm_encoder_slave_funcs sil164_encoder_funcs = {
|
|||
.dpms = sil164_encoder_dpms,
|
||||
.save = sil164_encoder_save,
|
||||
.restore = sil164_encoder_restore,
|
||||
.mode_fixup = sil164_encoder_mode_fixup,
|
||||
.mode_valid = sil164_encoder_mode_valid,
|
||||
.mode_set = sil164_encoder_mode_set,
|
||||
.detect = sil164_encoder_detect,
|
||||
|
|
|
@ -856,14 +856,6 @@ static void tda998x_encoder_dpms(struct drm_encoder *encoder, int 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,
|
||||
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 = {
|
||||
.dpms = tda998x_encoder_dpms,
|
||||
.mode_fixup = tda998x_encoder_mode_fixup,
|
||||
.prepare = tda998x_encoder_prepare,
|
||||
.commit = tda998x_encoder_commit,
|
||||
.mode_set = tda998x_encoder_mode_set,
|
||||
|
|
|
@ -35,9 +35,12 @@
|
|||
#include "i915_trace.h"
|
||||
#include "intel_drv.h"
|
||||
|
||||
#include <linux/apple-gmux.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/vgaarb.h>
|
||||
#include <linux/vga_switcheroo.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
|
||||
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))
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
return -EINVAL;
|
||||
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;
|
||||
|
||||
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_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;
|
||||
}
|
||||
|
||||
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 = {
|
||||
.map_dma_buf = i915_gem_map_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,
|
||||
.vunmap = i915_gem_dmabuf_vunmap,
|
||||
.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,
|
||||
|
|
|
@ -10521,7 +10521,6 @@ retry:
|
|||
}
|
||||
|
||||
connector_state->crtc = crtc;
|
||||
connector_state->best_encoder = &intel_encoder->base;
|
||||
|
||||
crtc_state = intel_atomic_get_crtc_state(state, intel_crtc);
|
||||
if (IS_ERR(crtc_state)) {
|
||||
|
@ -10617,7 +10616,6 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
|
|||
if (IS_ERR(crtc_state))
|
||||
goto fail;
|
||||
|
||||
connector_state->best_encoder = NULL;
|
||||
connector_state->crtc = NULL;
|
||||
|
||||
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.enabled = crtc->active;
|
||||
crtc->base.state->connector_mask = 0;
|
||||
crtc->base.state->encoder_mask = 0;
|
||||
|
||||
/* Because we only establish the connector -> encoder ->
|
||||
* 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 |=
|
||||
1 << drm_connector_index(&connector->base);
|
||||
encoder->base.crtc->state->encoder_mask |=
|
||||
1 << drm_encoder_index(&encoder->base);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
|
@ -1188,7 +1188,6 @@ intel_dp_aux_fini(struct intel_dp *intel_dp)
|
|||
static int
|
||||
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);
|
||||
enum port port = intel_dig_port->port;
|
||||
int ret;
|
||||
|
@ -1199,7 +1198,7 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
|
|||
if (!intel_dp->aux.name)
|
||||
return -ENOMEM;
|
||||
|
||||
intel_dp->aux.dev = dev->dev;
|
||||
intel_dp->aux.dev = connector->base.kdev;
|
||||
intel_dp->aux.transfer = intel_dp_aux_transfer;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1232,9 +1221,7 @@ intel_dp_connector_unregister(struct intel_connector *intel_connector)
|
|||
{
|
||||
struct intel_dp *intel_dp = intel_attached_dp(&intel_connector->base);
|
||||
|
||||
if (!intel_connector->mst_port)
|
||||
sysfs_remove_link(&intel_connector->base.kdev->kobj,
|
||||
intel_dp->aux.ddc.dev.kobj.name);
|
||||
intel_dp_aux_fini(intel_dp);
|
||||
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_dp *intel_dp = &intel_dig_port->dp;
|
||||
|
||||
intel_dp_aux_fini(intel_dp);
|
||||
intel_dp_mst_encoder_cleanup(intel_dig_port);
|
||||
if (is_edp(intel_dp)) {
|
||||
cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <linux/dmi.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vga_switcheroo.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
|
@ -1080,7 +1081,12 @@ void intel_lvds_init(struct drm_device *dev)
|
|||
* preferred mode is the right one.
|
||||
*/
|
||||
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 (drm_add_edid_modes(connector, edid)) {
|
||||
drm_mode_connector_update_edid_property(connector,
|
||||
|
|
|
@ -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,
|
||||
struct drm_display_mode *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 = {
|
||||
.mode_fixup = dw_hdmi_imx_encoder_mode_fixup,
|
||||
.mode_set = dw_hdmi_imx_encoder_mode_set,
|
||||
.prepare = dw_hdmi_imx_encoder_prepare,
|
||||
.commit = dw_hdmi_imx_encoder_commit,
|
||||
|
|
|
@ -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,
|
||||
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 = {
|
||||
.dpms = imx_ldb_encoder_dpms,
|
||||
.mode_fixup = imx_ldb_encoder_mode_fixup,
|
||||
.prepare = imx_ldb_encoder_prepare,
|
||||
.commit = imx_ldb_encoder_commit,
|
||||
.mode_set = imx_ldb_encoder_mode_set,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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 = {
|
||||
.dpms = imx_tve_encoder_dpms,
|
||||
.mode_fixup = imx_tve_encoder_mode_fixup,
|
||||
.prepare = imx_tve_encoder_prepare,
|
||||
.mode_set = imx_tve_encoder_mode_set,
|
||||
.commit = imx_tve_encoder_commit,
|
||||
|
|
|
@ -112,13 +112,6 @@ static void imx_pd_encoder_dpms(struct drm_encoder *encoder, int mode)
|
|||
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)
|
||||
{
|
||||
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 = {
|
||||
.dpms = imx_pd_encoder_dpms,
|
||||
.mode_fixup = imx_pd_encoder_mode_fixup,
|
||||
.prepare = imx_pd_encoder_prepare,
|
||||
.commit = imx_pd_encoder_commit,
|
||||
.mode_set = imx_pd_encoder_mode_set,
|
||||
|
|
|
@ -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
|
||||
* 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,
|
||||
struct drm_display_mode *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 = {
|
||||
.dpms = mga_encoder_dpms,
|
||||
.mode_fixup = mga_encoder_mode_fixup,
|
||||
.mode_set = mga_encoder_mode_set,
|
||||
.prepare = mga_encoder_prepare,
|
||||
.commit = mga_encoder_commit,
|
||||
|
|
|
@ -47,13 +47,6 @@ static const struct drm_encoder_funcs mdp4_dsi_encoder_funcs = {
|
|||
.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,
|
||||
struct drm_display_mode *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 = {
|
||||
.mode_fixup = mdp4_dsi_encoder_mode_fixup,
|
||||
.mode_set = mdp4_dsi_encoder_mode_set,
|
||||
.disable = mdp4_dsi_encoder_disable,
|
||||
.enable = mdp4_dsi_encoder_enable,
|
||||
|
|
|
@ -94,13 +94,6 @@ static const struct drm_encoder_funcs mdp4_dtv_encoder_funcs = {
|
|||
.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,
|
||||
struct drm_display_mode *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 = {
|
||||
.mode_fixup = mdp4_dtv_encoder_mode_fixup,
|
||||
.mode_set = mdp4_dtv_encoder_mode_set,
|
||||
.enable = mdp4_dtv_encoder_enable,
|
||||
.disable = mdp4_dtv_encoder_disable,
|
||||
|
|
|
@ -260,13 +260,6 @@ static void setup_phy(struct drm_encoder *encoder)
|
|||
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,
|
||||
struct drm_display_mode *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 = {
|
||||
.mode_fixup = mdp4_lcdc_encoder_mode_fixup,
|
||||
.mode_set = mdp4_lcdc_encoder_mode_set,
|
||||
.disable = mdp4_lcdc_encoder_disable,
|
||||
.enable = mdp4_lcdc_encoder_enable,
|
||||
|
|
|
@ -188,13 +188,6 @@ static const struct drm_encoder_funcs mdp5_cmd_encoder_funcs = {
|
|||
.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,
|
||||
struct drm_display_mode *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 = {
|
||||
.mode_fixup = mdp5_cmd_encoder_mode_fixup,
|
||||
.mode_set = mdp5_cmd_encoder_mode_set,
|
||||
.disable = mdp5_cmd_encoder_disable,
|
||||
.enable = mdp5_cmd_encoder_enable,
|
||||
|
@ -340,4 +332,3 @@ fail:
|
|||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
|
|
|
@ -112,13 +112,6 @@ static const struct drm_encoder_funcs mdp5_encoder_funcs = {
|
|||
.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,
|
||||
struct drm_display_mode *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 = {
|
||||
.mode_fixup = mdp5_encoder_mode_fixup,
|
||||
.mode_set = mdp5_encoder_mode_set,
|
||||
.disable = mdp5_encoder_disable,
|
||||
.enable = mdp5_encoder_enable,
|
||||
|
|
|
@ -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 msm_fbdev *fbdev = to_msm_fbdev(helper);
|
||||
struct drm_gem_object *drm_obj = fbdev->bo;
|
||||
struct drm_device *dev = helper->dev;
|
||||
int ret = 0;
|
||||
|
||||
if (drm_device_is_unplugged(dev))
|
||||
return -ENODEV;
|
||||
|
||||
ret = drm_gem_mmap_obj(drm_obj, drm_obj->size, vma);
|
||||
if (ret) {
|
||||
pr_err("%s:drm_gem_mmap_obj fail\n", __func__);
|
||||
|
|
|
@ -314,7 +314,7 @@ void nouveau_register_dsm_handler(void)
|
|||
if (!r)
|
||||
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 */
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <acpi/button.h>
|
||||
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/vga_switcheroo.h>
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_edid.h>
|
||||
|
@ -153,6 +154,17 @@ nouveau_connector_ddc_detect(struct drm_connector *connector)
|
|||
if (ret == 0)
|
||||
break;
|
||||
} 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 (nvkm_probe_i2c(nv_encoder->i2c, 0x50))
|
||||
break;
|
||||
|
@ -265,7 +277,14 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
|
|||
|
||||
nv_encoder = nouveau_connector_ddc_detect(connector);
|
||||
if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) {
|
||||
nv_connector->edid = drm_get_edid(connector, i2c);
|
||||
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);
|
||||
|
||||
drm_mode_connector_update_edid_property(connector,
|
||||
nv_connector->edid);
|
||||
if (!nv_connector->edid) {
|
||||
|
|
|
@ -22,11 +22,13 @@
|
|||
* Authors: Ben Skeggs
|
||||
*/
|
||||
|
||||
#include <linux/apple-gmux.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/vgaarb.h>
|
||||
#include <linux/vga_switcheroo.h>
|
||||
|
||||
#include "drmP.h"
|
||||
|
@ -312,6 +314,15 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
|
|||
bool boot = false;
|
||||
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) */
|
||||
aper = alloc_apertures(3);
|
||||
if (!aper)
|
||||
|
|
|
@ -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,
|
||||
size_t start, size_t len, enum dma_data_direction dir)
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
struct drm_gem_object *obj = buffer->priv;
|
||||
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,
|
||||
size_t start, size_t len, enum dma_data_direction dir)
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
struct drm_gem_object *obj = buffer->priv;
|
||||
omap_gem_put_pages(obj);
|
||||
|
|
|
@ -734,14 +734,6 @@ static void qxl_enc_dpms(struct drm_encoder *encoder, int mode)
|
|||
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)
|
||||
{
|
||||
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 = {
|
||||
.dpms = qxl_enc_dpms,
|
||||
.mode_fixup = qxl_enc_mode_fixup,
|
||||
.prepare = qxl_enc_prepare,
|
||||
.mode_set = qxl_enc_mode_set,
|
||||
.commit = qxl_enc_commit,
|
||||
|
|
|
@ -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 = {
|
||||
.dpms = radeon_atom_ext_dpms,
|
||||
.mode_fixup = radeon_atom_ext_mode_fixup,
|
||||
.prepare = radeon_atom_ext_prepare,
|
||||
.mode_set = radeon_atom_ext_mode_set,
|
||||
.commit = radeon_atom_ext_commit,
|
||||
|
|
|
@ -551,13 +551,14 @@ static bool radeon_atpx_detect(void)
|
|||
void radeon_register_atpx_handler(void)
|
||||
{
|
||||
bool r;
|
||||
enum vga_switcheroo_handler_flags_t handler_flags = 0;
|
||||
|
||||
/* detect if we have any ATPX + 2 VGA in the system */
|
||||
r = radeon_atpx_detect();
|
||||
if (!r)
|
||||
return;
|
||||
|
||||
vga_switcheroo_register_handler(&radeon_atpx_handler);
|
||||
vga_switcheroo_register_handler(&radeon_atpx_handler, handler_flags);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "atom.h"
|
||||
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/vga_switcheroo.h>
|
||||
|
||||
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)
|
||||
radeon_connector->edid = drm_get_edid(&radeon_connector->base,
|
||||
&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) {
|
||||
radeon_connector->edid = drm_get_edid(&radeon_connector->base,
|
||||
&radeon_connector->ddc_bus->adapter);
|
||||
|
|
|
@ -34,9 +34,11 @@
|
|||
#include "radeon_drv.h"
|
||||
|
||||
#include <drm/drm_pciids.h>
|
||||
#include <linux/apple-gmux.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/vgaarb.h>
|
||||
#include <linux/vga_switcheroo.h>
|
||||
#include <drm/drm_gem.h>
|
||||
|
||||
|
@ -319,6 +321,15 @@ static int radeon_pci_probe(struct pci_dev *pdev,
|
|||
{
|
||||
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 */
|
||||
ret = radeon_kick_out_firmware_fb(pdev);
|
||||
if (ret)
|
||||
|
|
|
@ -875,13 +875,6 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
|
|||
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)
|
||||
{
|
||||
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
|
||||
dw_mipi_dsi_encoder_helper_funcs = {
|
||||
.mode_fixup = dw_mipi_dsi_encoder_mode_fixup,
|
||||
.commit = dw_mipi_dsi_encoder_commit,
|
||||
.mode_set = dw_mipi_dsi_encoder_mode_set,
|
||||
.disable = dw_mipi_dsi_encoder_disable,
|
||||
|
|
|
@ -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,
|
||||
struct drm_display_mode *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 = {
|
||||
.dpms = sti_tvout_encoder_dpms,
|
||||
.mode_fixup = sti_tvout_encoder_mode_fixup,
|
||||
.mode_set = sti_tvout_encoder_mode_set,
|
||||
.prepare = sti_tvout_encoder_prepare,
|
||||
.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 = {
|
||||
.dpms = sti_tvout_encoder_dpms,
|
||||
.mode_fixup = sti_tvout_encoder_mode_fixup,
|
||||
.mode_set = sti_tvout_encoder_mode_set,
|
||||
.prepare = sti_tvout_encoder_prepare,
|
||||
.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 = {
|
||||
.dpms = sti_tvout_encoder_dpms,
|
||||
.mode_fixup = sti_tvout_encoder_mode_fixup,
|
||||
.mode_set = sti_tvout_encoder_mode_set,
|
||||
.prepare = sti_tvout_encoder_prepare,
|
||||
.commit = sti_hdmi_encoder_commit,
|
||||
|
|
|
@ -70,14 +70,6 @@ static void panel_encoder_dpms(struct drm_encoder *encoder, int mode)
|
|||
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)
|
||||
{
|
||||
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 = {
|
||||
.dpms = panel_encoder_dpms,
|
||||
.mode_fixup = panel_encoder_mode_fixup,
|
||||
.prepare = panel_encoder_prepare,
|
||||
.commit = panel_encoder_commit,
|
||||
.mode_set = panel_encoder_mode_set,
|
||||
|
|
|
@ -80,14 +80,6 @@ static void tfp410_encoder_dpms(struct drm_encoder *encoder, int 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)
|
||||
{
|
||||
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 = {
|
||||
.dpms = tfp410_encoder_dpms,
|
||||
.mode_fixup = tfp410_encoder_mode_fixup,
|
||||
.prepare = tfp410_encoder_prepare,
|
||||
.commit = tfp410_encoder_commit,
|
||||
.mode_set = tfp410_encoder_mode_set,
|
||||
|
|
|
@ -125,17 +125,5 @@ static struct usb_driver udl_driver = {
|
|||
.disconnect = udl_usb_disconnect,
|
||||
.id_table = id_table,
|
||||
};
|
||||
|
||||
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_usb_driver(udl_driver);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
@ -54,7 +47,6 @@ udl_encoder_dpms(struct drm_encoder *encoder, int mode)
|
|||
|
||||
static const struct drm_encoder_helper_funcs udl_helper_funcs = {
|
||||
.dpms = udl_encoder_dpms,
|
||||
.mode_fixup = udl_mode_fixup,
|
||||
.prepare = udl_encoder_prepare,
|
||||
.mode_set = udl_encoder_mode_set,
|
||||
.commit = udl_encoder_commit,
|
||||
|
|
|
@ -409,7 +409,6 @@ static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb,
|
|||
|
||||
if (ufb->obj->base.import_attach) {
|
||||
ret = dma_buf_begin_cpu_access(ufb->obj->base.import_attach->dmabuf,
|
||||
0, ufb->obj->base.size,
|
||||
DMA_FROM_DEVICE);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
|
@ -425,7 +424,6 @@ static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb,
|
|||
|
||||
if (ufb->obj->base.import_attach) {
|
||||
dma_buf_end_cpu_access(ufb->obj->base.import_attach->dmabuf,
|
||||
0, ufb->obj->base.size,
|
||||
DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
|
|
|
@ -282,13 +282,6 @@ static const struct drm_crtc_helper_funcs virtio_gpu_crtc_helper_funcs = {
|
|||
.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,
|
||||
struct drm_display_mode *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 = {
|
||||
.mode_fixup = virtio_gpu_enc_mode_fixup,
|
||||
.mode_set = virtio_gpu_enc_mode_set,
|
||||
.enable = virtio_gpu_enc_enable,
|
||||
.disable = virtio_gpu_enc_disable,
|
||||
|
|
|
@ -74,9 +74,17 @@
|
|||
* 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
|
||||
* machines with more than two GPUs should they become available.
|
||||
*
|
||||
* 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
|
||||
* 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)
|
||||
* @clients: list of registered clients
|
||||
* @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
|
||||
* per system is supported.
|
||||
|
@ -142,6 +154,9 @@ struct vgasr_priv {
|
|||
struct list_head clients;
|
||||
|
||||
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
|
||||
|
@ -156,6 +171,7 @@ static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv);
|
|||
/* only one switcheroo per system */
|
||||
static struct vgasr_priv vgasr_priv = {
|
||||
.clients = LIST_HEAD_INIT(vgasr_priv.clients),
|
||||
.mux_hw_lock = __MUTEX_INITIALIZER(vgasr_priv.mux_hw_lock),
|
||||
};
|
||||
|
||||
static bool vga_switcheroo_ready(void)
|
||||
|
@ -190,13 +206,15 @@ static void vga_switcheroo_enable(void)
|
|||
/**
|
||||
* vga_switcheroo_register_handler() - register handler
|
||||
* @handler: handler callbacks
|
||||
* @handler_flags: handler flags
|
||||
*
|
||||
* Register handler. Enable vga_switcheroo if two vga clients have 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);
|
||||
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_flags = handler_flags;
|
||||
if (vga_switcheroo_ready()) {
|
||||
pr_info("enabled\n");
|
||||
vga_switcheroo_enable();
|
||||
|
@ -222,16 +241,33 @@ EXPORT_SYMBOL(vga_switcheroo_register_handler);
|
|||
void vga_switcheroo_unregister_handler(void)
|
||||
{
|
||||
mutex_lock(&vgasr_mutex);
|
||||
mutex_lock(&vgasr_priv.mux_hw_lock);
|
||||
vgasr_priv.handler_flags = 0;
|
||||
vgasr_priv.handler = NULL;
|
||||
if (vgasr_priv.active) {
|
||||
pr_info("disabled\n");
|
||||
vga_switcheroo_debugfs_fini(&vgasr_priv);
|
||||
vgasr_priv.active = false;
|
||||
}
|
||||
mutex_unlock(&vgasr_priv.mux_hw_lock);
|
||||
mutex_unlock(&vgasr_mutex);
|
||||
}
|
||||
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,
|
||||
const struct vga_switcheroo_client_ops *ops,
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
|
@ -549,7 +655,9 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
|
|||
console_unlock();
|
||||
}
|
||||
|
||||
mutex_lock(&vgasr_priv.mux_hw_lock);
|
||||
ret = vgasr_priv.handler->switchto(new_client->id);
|
||||
mutex_unlock(&vgasr_priv.mux_hw_lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -664,7 +772,9 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
|
|||
vgasr_priv.delayed_switch_active = false;
|
||||
|
||||
if (just_mux) {
|
||||
mutex_lock(&vgasr_priv.mux_hw_lock);
|
||||
ret = vgasr_priv.handler->switchto(client_id);
|
||||
mutex_unlock(&vgasr_priv.mux_hw_lock);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -876,8 +986,11 @@ static int vga_switcheroo_runtime_suspend(struct device *dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
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);
|
||||
mutex_unlock(&vgasr_priv.mux_hw_lock);
|
||||
}
|
||||
vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_OFF);
|
||||
mutex_unlock(&vgasr_mutex);
|
||||
return 0;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/acpi.h>
|
||||
#include <linux/pnp.h>
|
||||
#include <linux/apple_bl.h>
|
||||
#include <linux/apple-gmux.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pci.h>
|
||||
|
@ -57,7 +58,9 @@ struct apple_gmux_data {
|
|||
/* switcheroo data */
|
||||
acpi_handle dhandle;
|
||||
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;
|
||||
struct completion powerchange_done;
|
||||
};
|
||||
|
@ -368,21 +371,72 @@ static const struct backlight_ops gmux_bl_ops = {
|
|||
* for the selected GPU.
|
||||
*/
|
||||
|
||||
static void gmux_read_switch_state(struct apple_gmux_data *gmux_data)
|
||||
{
|
||||
if (gmux_read8(gmux_data, GMUX_PORT_SWITCH_DDC) == 1)
|
||||
gmux_data->switch_state_ddc = VGA_SWITCHEROO_IGD;
|
||||
else
|
||||
gmux_data->switch_state_ddc = VGA_SWITCHEROO_DIS;
|
||||
|
||||
if (gmux_read8(gmux_data, GMUX_PORT_SWITCH_DISPLAY) == 2)
|
||||
gmux_data->switch_state_display = VGA_SWITCHEROO_IGD;
|
||||
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)
|
||||
{
|
||||
if (id == VGA_SWITCHEROO_IGD) {
|
||||
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
|
||||
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 2);
|
||||
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 2);
|
||||
} else {
|
||||
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
|
||||
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 3);
|
||||
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
*
|
||||
|
@ -440,21 +494,19 @@ static int gmux_get_client_id(struct pci_dev *pdev)
|
|||
return VGA_SWITCHEROO_DIS;
|
||||
}
|
||||
|
||||
static enum vga_switcheroo_client_id
|
||||
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 = {
|
||||
static const struct vga_switcheroo_handler gmux_handler_indexed = {
|
||||
.switchto = gmux_switchto,
|
||||
.power_state = gmux_set_power_state,
|
||||
.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
|
||||
*
|
||||
|
@ -513,7 +565,6 @@ static int gmux_suspend(struct device *dev)
|
|||
struct pnp_dev *pnp = to_pnp_dev(dev);
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
@ -524,7 +575,7 @@ static int gmux_resume(struct device *dev)
|
|||
struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
|
||||
|
||||
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)
|
||||
gmux_set_discrete_state(gmux_data, gmux_data->power_state);
|
||||
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;
|
||||
init_completion(&gmux_data->powerchange_done);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -764,7 +829,7 @@ static void gmux_remove(struct pnp_dev *pnp)
|
|||
}
|
||||
|
||||
static const struct pnp_device_id gmux_device_ids[] = {
|
||||
{"APP000B", 0},
|
||||
{GMUX_ACPI_HID, 0},
|
||||
{"", 0}
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
size_t len,
|
||||
static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
static void ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf, size_t start,
|
||||
size_t len,
|
||||
static void ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
struct ion_buffer *buffer = dmabuf->priv;
|
||||
|
|
|
@ -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)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dma_buf_begin_cpu_access(dma_buf, offset, size, dir);
|
||||
ret = dma_buf_begin_cpu_access(dma_buf, dir);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -139,7 +139,7 @@ static int ion_handle_test_kernel(struct dma_buf *dma_buf, void __user *ptr,
|
|||
copy_offset = 0;
|
||||
}
|
||||
err:
|
||||
dma_buf_end_cpu_access(dma_buf, offset, size, dir);
|
||||
dma_buf_end_cpu_access(dma_buf, dir);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -307,6 +307,7 @@ struct drm_plane_helper_funcs;
|
|||
* @connectors_changed: connectors to this crtc have been updated
|
||||
* @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
|
||||
* @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
|
||||
* update to ensure framebuffer cleanup isn't done too early
|
||||
* @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 connector_mask;
|
||||
u32 encoder_mask;
|
||||
|
||||
/* last_vblank_count: for vblank waits before cleanup */
|
||||
u32 last_vblank_count;
|
||||
|
@ -2153,6 +2155,17 @@ struct drm_mode_config {
|
|||
list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \
|
||||
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_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,
|
||||
const struct drm_encoder_funcs *funcs,
|
||||
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?
|
||||
|
@ -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 struct edid *drm_get_edid(struct drm_connector *connector,
|
||||
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 int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
|
||||
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_horz_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 struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
|
||||
unsigned int supported_rotations);
|
||||
|
|
|
@ -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
|
|
@ -219,6 +219,7 @@ struct drm_fb_helper {
|
|||
};
|
||||
|
||||
#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,
|
||||
const struct drm_fb_helper_funcs *funcs);
|
||||
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,
|
||||
struct drm_connector *connector);
|
||||
#else
|
||||
static inline int drm_fb_helper_modinit(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void drm_fb_helper_prepare(struct drm_device *dev,
|
||||
struct drm_fb_helper *helper,
|
||||
const struct drm_fb_helper_funcs *funcs)
|
||||
|
|
|
@ -439,7 +439,7 @@ struct drm_encoder_helper_funcs {
|
|||
* 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.
|
||||
* With atomic helpers it is optional.
|
||||
* This hook is optional.
|
||||
*
|
||||
* NOTE:
|
||||
*
|
||||
|
|
|
@ -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 */
|
|
@ -54,7 +54,7 @@ struct dma_buf_attachment;
|
|||
* @release: release this buffer; to be called after the last dma_buf_put.
|
||||
* @begin_cpu_access: [optional] called before cpu access to invalidate cpu
|
||||
* 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.
|
||||
* @kmap_atomic: maps a page from the buffer into kernel address
|
||||
* space, users may not block until the subsequent unmap call.
|
||||
|
@ -93,10 +93,8 @@ struct dma_buf_ops {
|
|||
/* after final dma_buf_put() */
|
||||
void (*release)(struct dma_buf *);
|
||||
|
||||
int (*begin_cpu_access)(struct dma_buf *, size_t, size_t,
|
||||
enum dma_data_direction);
|
||||
void (*end_cpu_access)(struct dma_buf *, size_t, size_t,
|
||||
enum dma_data_direction);
|
||||
int (*begin_cpu_access)(struct dma_buf *, enum dma_data_direction);
|
||||
void (*end_cpu_access)(struct dma_buf *, enum dma_data_direction);
|
||||
void *(*kmap_atomic)(struct dma_buf *, unsigned long);
|
||||
void (*kunmap_atomic)(struct dma_buf *, unsigned long, void *);
|
||||
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);
|
||||
void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct sg_table *,
|
||||
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);
|
||||
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);
|
||||
void *dma_buf_kmap_atomic(struct dma_buf *, unsigned long);
|
||||
void dma_buf_kunmap_atomic(struct dma_buf *, unsigned long, void *);
|
||||
|
|
|
@ -35,6 +35,26 @@
|
|||
|
||||
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
|
||||
* @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
|
||||
* denotes success, anything else failure (in which case the switch is
|
||||
* 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.
|
||||
* Optional. The return value is ignored
|
||||
* @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 {
|
||||
int (*init)(void);
|
||||
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,
|
||||
enum vga_switcheroo_state state);
|
||||
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,
|
||||
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);
|
||||
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);
|
||||
|
||||
|
@ -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,
|
||||
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 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,
|
||||
const struct vga_switcheroo_client_ops *ops,
|
||||
enum vga_switcheroo_client_id id) { return 0; }
|
||||
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 enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev) { return VGA_SWITCHEROO_ON; }
|
||||
|
||||
|
|
|
@ -669,6 +669,7 @@ struct drm_set_client_cap {
|
|||
__u64 value;
|
||||
};
|
||||
|
||||
#define DRM_RDWR O_RDWR
|
||||
#define DRM_CLOEXEC O_CLOEXEC
|
||||
struct drm_prime_handle {
|
||||
__u32 handle;
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue