Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f8467618 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge remote branch 'origin/drm-core-next' into test

Conflicts:
	drivers/gpu/drm/drm_fb_helper.c
parents 22dd5013 447aeb90
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -15,7 +15,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \


drm-$(CONFIG_COMPAT) += drm_ioc32.o
drm-$(CONFIG_COMPAT) += drm_ioc32.o


drm_kms_helper-y := drm_fb_helper.o drm_crtc_helper.o
drm_kms_helper-y := drm_fb_helper.o drm_crtc_helper.o drm_dp_i2c_helper.o


obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o


+173 −0
Original line number Original line Diff line number Diff line
@@ -125,6 +125,15 @@ static struct drm_prop_enum_list drm_tv_subconnector_enum_list[] =
DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
		 drm_tv_subconnector_enum_list)
		 drm_tv_subconnector_enum_list)


static struct drm_prop_enum_list drm_dirty_info_enum_list[] = {
	{ DRM_MODE_DIRTY_OFF,      "Off"      },
	{ DRM_MODE_DIRTY_ON,       "On"       },
	{ DRM_MODE_DIRTY_ANNOTATE, "Annotate" },
};

DRM_ENUM_NAME_FN(drm_get_dirty_info_name,
		 drm_dirty_info_enum_list)

struct drm_conn_prop_enum_list {
struct drm_conn_prop_enum_list {
	int type;
	int type;
	char *name;
	char *name;
@@ -801,6 +810,36 @@ int drm_mode_create_dithering_property(struct drm_device *dev)
}
}
EXPORT_SYMBOL(drm_mode_create_dithering_property);
EXPORT_SYMBOL(drm_mode_create_dithering_property);


/**
 * drm_mode_create_dirty_property - create dirty property
 * @dev: DRM device
 *
 * Called by a driver the first time it's needed, must be attached to desired
 * connectors.
 */
int drm_mode_create_dirty_info_property(struct drm_device *dev)
{
	struct drm_property *dirty_info;
	int i;

	if (dev->mode_config.dirty_info_property)
		return 0;

	dirty_info =
		drm_property_create(dev, DRM_MODE_PROP_ENUM |
				    DRM_MODE_PROP_IMMUTABLE,
				    "dirty",
				    ARRAY_SIZE(drm_dirty_info_enum_list));
	for (i = 0; i < ARRAY_SIZE(drm_dirty_info_enum_list); i++)
		drm_property_add_enum(dirty_info, i,
				      drm_dirty_info_enum_list[i].type,
				      drm_dirty_info_enum_list[i].name);
	dev->mode_config.dirty_info_property = dirty_info;

	return 0;
}
EXPORT_SYMBOL(drm_mode_create_dirty_info_property);

/**
/**
 * drm_mode_config_init - initialize DRM mode_configuration structure
 * drm_mode_config_init - initialize DRM mode_configuration structure
 * @dev: DRM device
 * @dev: DRM device
@@ -1753,6 +1792,71 @@ out:
	return ret;
	return ret;
}
}


int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
			   void *data, struct drm_file *file_priv)
{
	struct drm_clip_rect __user *clips_ptr;
	struct drm_clip_rect *clips = NULL;
	struct drm_mode_fb_dirty_cmd *r = data;
	struct drm_mode_object *obj;
	struct drm_framebuffer *fb;
	unsigned flags;
	int num_clips;
	int ret = 0;

	mutex_lock(&dev->mode_config.mutex);
	obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
	if (!obj) {
		DRM_ERROR("invalid framebuffer id\n");
		ret = -EINVAL;
		goto out_err1;
	}
	fb = obj_to_fb(obj);

	num_clips = r->num_clips;
	clips_ptr = (struct drm_clip_rect *)(unsigned long)r->clips_ptr;

	if (!num_clips != !clips_ptr) {
		ret = -EINVAL;
		goto out_err1;
	}

	flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags;

	/* If userspace annotates copy, clips must come in pairs */
	if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) {
		ret = -EINVAL;
		goto out_err1;
	}

	if (num_clips && clips_ptr) {
		clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL);
		if (!clips) {
			ret = -ENOMEM;
			goto out_err1;
		}

		ret = copy_from_user(clips, clips_ptr,
				     num_clips * sizeof(*clips));
		if (ret)
			goto out_err2;
	}

	if (fb->funcs->dirty) {
		ret = fb->funcs->dirty(fb, flags, r->color, clips, num_clips);
	} else {
		ret = -ENOSYS;
		goto out_err2;
	}

out_err2:
	kfree(clips);
out_err1:
	mutex_unlock(&dev->mode_config.mutex);
	return ret;
}


/**
/**
 * drm_fb_release - remove and free the FBs on this file
 * drm_fb_release - remove and free the FBs on this file
 * @filp: file * from the ioctl
 * @filp: file * from the ioctl
@@ -2478,3 +2582,72 @@ out:
	mutex_unlock(&dev->mode_config.mutex);
	mutex_unlock(&dev->mode_config.mutex);
	return ret;
	return ret;
}
}

int drm_mode_page_flip_ioctl(struct drm_device *dev,
			     void *data, struct drm_file *file_priv)
{
	struct drm_mode_crtc_page_flip *page_flip = data;
	struct drm_mode_object *obj;
	struct drm_crtc *crtc;
	struct drm_framebuffer *fb;
	struct drm_pending_vblank_event *e = NULL;
	unsigned long flags;
	int ret = -EINVAL;

	if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
	    page_flip->reserved != 0)
		return -EINVAL;

	mutex_lock(&dev->mode_config.mutex);
	obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC);
	if (!obj)
		goto out;
	crtc = obj_to_crtc(obj);

	if (crtc->funcs->page_flip == NULL)
		goto out;

	obj = drm_mode_object_find(dev, page_flip->fb_id, DRM_MODE_OBJECT_FB);
	if (!obj)
		goto out;
	fb = obj_to_fb(obj);

	if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
		ret = -ENOMEM;
		spin_lock_irqsave(&dev->event_lock, flags);
		if (file_priv->event_space < sizeof e->event) {
			spin_unlock_irqrestore(&dev->event_lock, flags);
			goto out;
		}
		file_priv->event_space -= sizeof e->event;
		spin_unlock_irqrestore(&dev->event_lock, flags);

		e = kzalloc(sizeof *e, GFP_KERNEL);
		if (e == NULL) {
			spin_lock_irqsave(&dev->event_lock, flags);
			file_priv->event_space += sizeof e->event;
			spin_unlock_irqrestore(&dev->event_lock, flags);
			goto out;
		}

		e->event.base.type = DRM_EVENT_VBLANK;
		e->event.base.length = sizeof e->event;
		e->event.user_data = page_flip->user_data;
		e->base.event = &e->event.base;
		e->base.file_priv = file_priv;
		e->base.destroy =
			(void (*) (struct drm_pending_event *)) kfree;
	}

	ret = crtc->funcs->page_flip(crtc, fb, e);
	if (ret) {
		spin_lock_irqsave(&dev->event_lock, flags);
		file_priv->event_space += sizeof e->event;
		spin_unlock_irqrestore(&dev->event_lock, flags);
		kfree(e);
	}

out:
	mutex_unlock(&dev->mode_config.mutex);
	return ret;
}
+1 −1
Original line number Original line Diff line number Diff line
@@ -109,7 +109,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,


	count = (*connector_funcs->get_modes)(connector);
	count = (*connector_funcs->get_modes)(connector);
	if (!count) {
	if (!count) {
		count = drm_add_modes_noedid(connector, 800, 600);
		count = drm_add_modes_noedid(connector, 1024, 768);
		if (!count)
		if (!count)
			return 0;
			return 0;
	}
	}
+5 −69
Original line number Original line Diff line number Diff line
@@ -28,85 +28,21 @@
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/i2c.h>
#include <linux/i2c.h>
#include "intel_dp.h"
#include "drm_dp_helper.h"
#include "drmP.h"
#include "drmP.h"


/* Run a single AUX_CH I2C transaction, writing/reading data as necessary */
/* Run a single AUX_CH I2C transaction, writing/reading data as necessary */

#define MODE_I2C_START	1
#define MODE_I2C_WRITE	2
#define MODE_I2C_READ	4
#define MODE_I2C_STOP	8

static int
static int
i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
			    uint8_t write_byte, uint8_t *read_byte)
			    uint8_t write_byte, uint8_t *read_byte)
{
{
	struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
	struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
	uint16_t address = algo_data->address;
	uint8_t msg[5];
	uint8_t reply[2];
	int msg_bytes;
	int reply_bytes;
	int ret;
	int ret;
	
	
	/* Set up the command byte */
	ret = (*algo_data->aux_ch)(adapter, mode,
	if (mode & MODE_I2C_READ)
				   write_byte, read_byte);
		msg[0] = AUX_I2C_READ << 4;
	else
		msg[0] = AUX_I2C_WRITE << 4;

	if (!(mode & MODE_I2C_STOP))
		msg[0] |= AUX_I2C_MOT << 4;

	msg[1] = address >> 8;
	msg[2] = address;

	switch (mode) {
	case MODE_I2C_WRITE:
		msg[3] = 0;
		msg[4] = write_byte;
		msg_bytes = 5;
		reply_bytes = 1;
		break;
	case MODE_I2C_READ:
		msg[3] = 0;
		msg_bytes = 4;
		reply_bytes = 2;
		break;
	default:
		msg_bytes = 3;
		reply_bytes = 1;
		break;
	}

	for (;;) {
		ret = (*algo_data->aux_ch)(adapter,
					   msg, msg_bytes,
					   reply, reply_bytes);
		if (ret < 0) {
			DRM_DEBUG("aux_ch failed %d\n", ret);
	return ret;
	return ret;
}
}
		switch (reply[0] & AUX_I2C_REPLY_MASK) {
		case AUX_I2C_REPLY_ACK:
			if (mode == MODE_I2C_READ) {
				*read_byte = reply[1];
			}
			return reply_bytes - 1;
		case AUX_I2C_REPLY_NACK:
			DRM_DEBUG("aux_ch nack\n");
			return -EREMOTEIO;
		case AUX_I2C_REPLY_DEFER:
			DRM_DEBUG("aux_ch defer\n");
			udelay(100);
			break;
		default:
			DRM_ERROR("aux_ch invalid reply 0x%02x\n", reply[0]);
			return -EREMOTEIO;
		}
	}
}


/*
/*
 * I2C over AUX CH
 * I2C over AUX CH
+36 −6
Original line number Original line Diff line number Diff line
@@ -145,6 +145,8 @@ static struct drm_ioctl_desc drm_ioctls[] = {
	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW),
	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW),
	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW),
	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW),
	DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW),
	DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW),
	DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
	DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW)
};
};


#define DRM_CORE_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls )
#define DRM_CORE_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls )
@@ -365,6 +367,29 @@ static void __exit drm_core_exit(void)
module_init(drm_core_init);
module_init(drm_core_init);
module_exit(drm_core_exit);
module_exit(drm_core_exit);


/**
 * Copy and IOCTL return string to user space
 */
static int drm_copy_field(char *buf, size_t *buf_len, const char *value)
{
	int len;

	/* don't overflow userbuf */
	len = strlen(value);
	if (len > *buf_len)
		len = *buf_len;

	/* let userspace know exact length of driver value (which could be
	 * larger than the userspace-supplied buffer) */
	*buf_len = strlen(value);

	/* finally, try filling in the userbuf */
	if (len && buf)
		if (copy_to_user(buf, value, len))
			return -EFAULT;
	return 0;
}

/**
/**
 * Get version information
 * Get version information
 *
 *
@@ -380,16 +405,21 @@ static int drm_version(struct drm_device *dev, void *data,
		       struct drm_file *file_priv)
		       struct drm_file *file_priv)
{
{
	struct drm_version *version = data;
	struct drm_version *version = data;
	int len;
	int err;


	version->version_major = dev->driver->major;
	version->version_major = dev->driver->major;
	version->version_minor = dev->driver->minor;
	version->version_minor = dev->driver->minor;
	version->version_patchlevel = dev->driver->patchlevel;
	version->version_patchlevel = dev->driver->patchlevel;
	DRM_COPY(version->name, dev->driver->name);
	err = drm_copy_field(version->name, &version->name_len,
	DRM_COPY(version->date, dev->driver->date);
			dev->driver->name);
	DRM_COPY(version->desc, dev->driver->desc);
	if (!err)

		err = drm_copy_field(version->date, &version->date_len,
	return 0;
				dev->driver->date);
	if (!err)
		err = drm_copy_field(version->desc, &version->desc_len,
				dev->driver->desc);

	return err;
}
}


/**
/**
Loading