diff options
133 files changed, 26209 insertions, 727 deletions
diff --git a/libdrm/Makefile.am b/libdrm/Makefile.am index e7e07e47..24c32038 100644 --- a/libdrm/Makefile.am +++ b/libdrm/Makefile.am @@ -23,9 +23,9 @@ libdrm_ladir = $(libdir)  libdrm_la_LDFLAGS = -version-number 2:3:0 -no-undefined  AM_CFLAGS = -I$(top_srcdir)/shared-core -libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c +libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c xf86drmMode.c  libdrmincludedir = ${includedir} -libdrminclude_HEADERS = xf86drm.h xf86mm.h +libdrminclude_HEADERS = xf86drm.h xf86mm.h xf86drmMode.h  EXTRA_DIST = ChangeLog TODO diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index e3550de7..39a849c6 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -87,6 +87,9 @@  #define DRM_MSG_VERBOSITY 3 +#define DRM_NODE_CONTROL 0 +#define DRM_NODE_RENDER 1 +  static drmServerInfoPtr drm_server_info;  void drmSetServerInfo(drmServerInfoPtr info) @@ -264,7 +267,7 @@ static int drmMatchBusID(const char *id1, const char *id2)   * special file node with the major and minor numbers specified by \p dev and   * parent directory if necessary and was called by root.   */ -static int drmOpenDevice(long dev, int minor) +static int drmOpenDevice(long dev, int minor, int type)  {      stat_t          st;      char            buf[64]; @@ -274,7 +277,7 @@ static int drmOpenDevice(long dev, int minor)      uid_t           user    = DRM_DEV_UID;      gid_t           group   = DRM_DEV_GID, serv_group; -    sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor); +    sprintf(buf, type ? DRM_DEV_NAME : DRM_CONTROL_DEV_NAME, DRM_DIR_NAME, minor);      drmMsg("drmOpenDevice: node name is %s\n", buf);      if (drm_server_info) { @@ -348,15 +351,15 @@ static int drmOpenDevice(long dev, int minor)   * Calls drmOpenDevice() if \p create is set, otherwise assembles the device   * name from \p minor and opens it.   */ -static int drmOpenMinor(int minor, int create) +static int drmOpenMinor(int minor, int create, int type)  {      int  fd;      char buf[64];      if (create) -	return drmOpenDevice(makedev(DRM_MAJOR, minor), minor); +      return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type); -    sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor); +    sprintf(buf, type ? DRM_DEV_NAME : DRM_CONTROL_DEV_NAME, DRM_DIR_NAME, minor);      if ((fd = open(buf, O_RDWR, 0)) >= 0)  	return fd;      return -errno; @@ -379,7 +382,7 @@ int drmAvailable(void)      int           retval = 0;      int           fd; -    if ((fd = drmOpenMinor(0, 1)) < 0) { +    if ((fd = drmOpenMinor(0, 1, DRM_NODE_RENDER)) < 0) {  #ifdef __linux__  	/* Try proc for backward Linux compatibility */  	if (!access("/proc/dri/0", R_OK)) @@ -420,7 +423,7 @@ static int drmOpenByBusid(const char *busid)      drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid);      for (i = 0; i < DRM_MAX_MINOR; i++) { -	fd = drmOpenMinor(i, 1); +	fd = drmOpenMinor(i, 1, DRM_NODE_RENDER);  	drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);  	if (fd >= 0) {  	    sv.drm_di_major = 1; @@ -482,7 +485,7 @@ static int drmOpenByName(const char *name)       * already in use.  If it's in use it will have a busid assigned already.       */      for (i = 0; i < DRM_MAX_MINOR; i++) { -	if ((fd = drmOpenMinor(i, 1)) >= 0) { +	if ((fd = drmOpenMinor(i, 1, DRM_NODE_RENDER)) >= 0) {  	    if ((version = drmGetVersion(fd))) {  		if (!strcmp(version->name, name)) {  		    drmFreeVersion(version); @@ -526,7 +529,7 @@ static int drmOpenByName(const char *name)  			if (*pt) { /* Found busid */  			    return drmOpenByBusid(++pt);  			} else { /* No busid */ -			    return drmOpenDevice(strtol(devstring, NULL, 0),i); +			    return drmOpenDevice(strtol(devstring, NULL, 0),i, DRM_NODE_RENDER);  			}  		    }  		} @@ -576,6 +579,10 @@ int drmOpen(const char *name, const char *busid)      return -1;  } +int drmOpenControl(int minor) +{ +    return drmOpenMinor(minor, 0, DRM_NODE_CONTROL); +}  /**   * Free the version information returned by drmGetVersion(). diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 230f54ce..7b418604 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -49,6 +49,7 @@  #define DRM_DIR_NAME  "/dev/dri"  #define DRM_DEV_NAME  "%s/card%d" +#define DRM_CONTROL_DEV_NAME  "%s/controlD%d"  #define DRM_PROC_NAME "/proc/dri/" /* For backward Linux compatibility */  #define DRM_ERR_NO_DEVICE  (-1001) @@ -508,6 +509,7 @@ do {	register unsigned int __old __asm("o0");		\  /* General user-level programmer's API: unprivileged */  extern int           drmAvailable(void);  extern int           drmOpen(const char *name, const char *busid); +extern int drmOpenControl(int minor);  extern int           drmClose(int fd);  extern drmVersionPtr drmGetVersion(int fd);  extern drmVersionPtr drmGetLibVersion(int fd); diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c new file mode 100644 index 00000000..52fef81b --- /dev/null +++ b/libdrm/xf86drmMode.c @@ -0,0 +1,573 @@ +/* + * \file xf86drmMode.c + * Header for DRM modesetting interface. + * + * \author Jakob Bornecrantz <wallbraker@gmail.com> + * + * \par Acknowledgements: + * Feb 2007, Dave Airlie <airlied@linux.ie> + */ + +/* + * Copyright (c) <year> <copyright holders> + * + * 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 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. + * + */ + +/* + * TODO the types we are after are defined in diffrent headers on diffrent + * platforms find which headers to include to get uint32_t + */ +#include <stdint.h> + +#include "xf86drmMode.h" +#include "xf86drm.h" +#include <drm.h> +#include <string.h> + +#define U642VOID(x) ((void *)(unsigned long)(x)) +#define VOID2U64(x) ((uint64_t)(unsigned long)(x)) + +/* + * Util functions + */ + +void* drmAllocCpy(void *array, int count, int entry_size) +{ +	char *r; +	int i; + +	if (!count || !array || !entry_size) +		return 0; + +	if (!(r = drmMalloc(count*entry_size))) +		return 0; + +	for (i = 0; i < count; i++) +		memcpy(r+(entry_size*i), array+(entry_size*i), entry_size); + +	return r; +} + +/** + * Generate crtc and output ids. + * + * Will generate ids starting from 1 up to count if count is greater then 0. + */ +static uint32_t* drmAllocGenerate(int count) +{ +	uint32_t *r; +	int i; + +	if(0 <= count) +		return 0; + +	if (!(r = drmMalloc(count*sizeof(*r)))) +		return 0; + +	for (i = 0; i < count; r[i] = ++i); + +	return 0; +} + +/* + * A couple of free functions. + */ + +void drmModeFreeModeInfo(struct drm_mode_modeinfo *ptr) +{ +	if (!ptr) +		return; + +	drmFree(ptr); +} + +void drmModeFreeResources(drmModeResPtr ptr) +{ +	if (!ptr) +		return; + +	drmFree(ptr); + +} + +void drmModeFreeFB(drmModeFBPtr ptr) +{ +	if (!ptr) +		return; + +	/* we might add more frees later. */ +	drmFree(ptr); +} + +void drmModeFreeCrtc(drmModeCrtcPtr ptr) +{ +	if (!ptr) +		return; + +	drmFree(ptr); + +} + +void drmModeFreeOutput(drmModeOutputPtr ptr) +{ +	if (!ptr) +		return; + +	drmFree(ptr->modes); +	drmFree(ptr); + +} + +/* + * ModeSetting functions. + */ + +drmModeResPtr drmModeGetResources(int fd) +{ +	struct drm_mode_card_res res; +	int i; +	drmModeResPtr r = 0; + +	memset(&res, 0, sizeof(struct drm_mode_card_res)); + +	if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) +		return 0; + +	if (res.count_fbs) +		res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t))); +	if (res.count_crtcs) +		res.crtc_id_ptr = VOID2U64(drmMalloc(res.count_crtcs*sizeof(uint32_t))); +	if (res.count_outputs) +		res.output_id_ptr = VOID2U64(drmMalloc(res.count_outputs*sizeof(uint32_t))); + +	if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) { +		r = NULL; +		goto err_allocs; +	} + +	/* +	 * return +	 */ + + +	if (!(r = drmMalloc(sizeof(*r)))) +		return 0; + +	r->min_width     = res.min_width; +	r->max_width     = res.max_width; +	r->min_height    = res.min_height; +	r->max_height    = res.max_height; +	r->count_fbs     = res.count_fbs; +	r->count_crtcs   = res.count_crtcs; +	r->count_outputs = res.count_outputs; +	/* TODO we realy should test if these allocs fails. */ +	r->fbs           = drmAllocCpy(U642VOID(res.fb_id_ptr), res.count_fbs, sizeof(uint32_t)); +	r->crtcs         = drmAllocCpy(U642VOID(res.crtc_id_ptr), res.count_crtcs, sizeof(uint32_t)); +	r->outputs       = drmAllocCpy(U642VOID(res.output_id_ptr), res.count_outputs, sizeof(uint32_t)); + +err_allocs: +	drmFree(U642VOID(res.fb_id_ptr)); +	drmFree(U642VOID(res.crtc_id_ptr)); +	drmFree(U642VOID(res.output_id_ptr)); + +	return r; +} + +uint32_t drmModeGetHotplug(int fd) +{ +	struct drm_mode_hotplug arg; +	arg.counter = 0; + +	ioctl(fd, DRM_IOCTL_MODE_HOTPLUG, &arg); +	return arg.counter; +} + +int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, +                 uint8_t bpp, uint32_t pitch, drmBO *bo, uint32_t *buf_id) +{ +	struct drm_mode_fb_cmd f; +	int ret; + +	f.width  = width; +	f.height = height; +	f.pitch  = pitch; +	f.bpp    = bpp; +	f.depth  = depth; +	f.handle = bo->handle; + +	if (ret = ioctl(fd, DRM_IOCTL_MODE_ADDFB, &f)) +		return ret; + +	*buf_id = f.buffer_id; +	return 0; +} + +int drmModeRmFB(int fd, uint32_t bufferId) +{ +	return ioctl(fd, DRM_IOCTL_MODE_RMFB, &bufferId); + + +} + +drmModeFBPtr drmModeGetFB(int fd, uint32_t buf) +{ +	struct drm_mode_fb_cmd info; +	drmModeFBPtr r; + +	info.buffer_id = buf; + +	if (ioctl(fd, DRM_IOCTL_MODE_GETFB, &info)) +		return NULL; + +	if (!(r = drmMalloc(sizeof(*r)))) +		return NULL; + +	r->buffer_id = info.buffer_id; +	r->width = info.width; +	r->height = info.height; +	r->pitch = info.pitch; +	r->bpp = info.bpp; +	r->handle = info.handle; +	r->depth = info.depth; + +	return r; +} + + +/* + * Crtc functions + */ + +drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) +{ +	struct drm_mode_crtc crtc; +	drmModeCrtcPtr r; +	int i = 0; + +	crtc.count_outputs   = 0; +	crtc.outputs         = 0; +	crtc.count_possibles = 0; +	crtc.possibles       = 0; +	crtc.crtc_id = crtcId; + +	if (ioctl(fd, DRM_IOCTL_MODE_GETCRTC, &crtc)) +		return 0; + +	/* +	 * return +	 */ + +	if (!(r = drmMalloc(sizeof(*r)))) +		return 0; +	 +	r->crtc_id         = crtc.crtc_id; +	r->x               = crtc.x; +	r->y               = crtc.y; +	r->mode_valid      = crtc.mode_valid; +	if (r->mode_valid) +		memcpy(&r->mode, &crtc.mode, sizeof(struct drm_mode_modeinfo)); +	r->buffer_id       = crtc.fb_id; +	r->gamma_size      = crtc.gamma_size; +	r->count_outputs   = crtc.count_outputs; +	r->count_possibles = crtc.count_possibles; +	/* TODO we realy should test if these alloc & cpy fails. */ +	r->outputs         = crtc.outputs; +	r->possibles       = crtc.possibles; + +	return r; + +err_allocs: + +	return 0; +} + + +int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, +                   uint32_t x, uint32_t y, uint32_t *outputs, int count, +		   struct drm_mode_modeinfo *mode) +{ +	struct drm_mode_crtc crtc; + +	crtc.count_outputs   = 0; +	crtc.outputs         = 0; +	crtc.count_possibles = 0; +	crtc.possibles       = 0; + +	crtc.x             = x; +	crtc.y             = y; +	crtc.crtc_id       = crtcId; +	crtc.fb_id         = bufferId; +	crtc.set_outputs_ptr = VOID2U64(outputs); +	crtc.count_outputs = count; +	if (mode) { +	  memcpy(&crtc.mode, mode, sizeof(struct drm_mode_modeinfo)); +	  crtc.mode_valid = 1; +	} else +	  crtc.mode_valid = 0; + +	return ioctl(fd, DRM_IOCTL_MODE_SETCRTC, &crtc); +} + +/* + * Cursor manipulation + */ + +int drmModeSetCursor(int fd, uint32_t crtcId, drmBO *bo, uint32_t width, uint32_t height) +{ +	struct drm_mode_cursor arg; + +	arg.flags = DRM_MODE_CURSOR_BO; +	arg.crtc = crtcId; +	arg.width = width; +	arg.height = height; +	if (bo) +		arg.handle = bo->handle; +	else +		arg.handle = 0; + +	return ioctl(fd, DRM_IOCTL_MODE_CURSOR, &arg); +} + +int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y) +{ +	struct drm_mode_cursor arg; + +	arg.flags = DRM_MODE_CURSOR_MOVE; +	arg.crtc = crtcId; +	arg.x = x; +	arg.y = y; + +	return ioctl(fd, DRM_IOCTL_MODE_CURSOR, &arg); +} + +/* + * Output manipulation + */ + +drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) +{ +	struct drm_mode_get_output out; +	drmModeOutputPtr r = NULL; + +	out.output = output_id; +	out.output_type_id = 0; +	out.output_type  = 0; +	out.count_crtcs  = 0; +	out.crtcs        = 0; +	out.count_clones = 0; +	out.clones       = 0; +	out.count_modes  = 0; +	out.modes_ptr    = 0; +	out.count_props  = 0; +	out.props_ptr    = 0; +	out.prop_values_ptr = 0; + +	if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out)) +		return 0; + +	if (out.count_props) { +		out.props_ptr = VOID2U64(drmMalloc(out.count_props*sizeof(uint32_t))); +		out.prop_values_ptr = VOID2U64(drmMalloc(out.count_props*sizeof(uint64_t))); +	} + +	if (out.count_modes) +		out.modes_ptr = VOID2U64(drmMalloc(out.count_modes*sizeof(struct drm_mode_modeinfo))); + +	if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out)) +		goto err_allocs; + +	if(!(r = drmMalloc(sizeof(*r)))) { +		goto err_allocs; +	} + +	r->output_id = out.output; +	r->crtc = out.crtc; +	r->connection   = out.connection; +	r->mmWidth      = out.mm_width; +	r->mmHeight     = out.mm_height; +	r->subpixel     = out.subpixel; +	r->count_crtcs  = out.count_crtcs; +	r->count_clones = out.count_clones; +	r->count_modes  = out.count_modes; +	/* TODO we should test if these alloc & cpy fails. */ +	r->crtcs        = out.crtcs; +	r->clones       = out.clones; +	r->count_props  = out.count_props; +	r->props        = drmAllocCpy(U642VOID(out.props_ptr), out.count_props, sizeof(uint32_t)); +	r->prop_values  = drmAllocCpy(U642VOID(out.prop_values_ptr), out.count_props, sizeof(uint64_t)); +	r->modes        = drmAllocCpy(U642VOID(out.modes_ptr), out.count_modes, sizeof(struct drm_mode_modeinfo)); +	r->output_type  = out.output_type; +	r->output_type_id = out.output_type_id; + +err_allocs: +	drmFree(U642VOID(out.prop_values_ptr)); +	drmFree(U642VOID(out.props_ptr)); +	drmFree(U642VOID(out.modes_ptr)); + +	return r; +} + +int drmModeAttachMode(int fd, uint32_t output_id, struct drm_mode_modeinfo *mode_info) +{ +	struct drm_mode_mode_cmd res; + +	memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo)); +	res.output_id = output_id; + +	return ioctl(fd, DRM_IOCTL_MODE_ATTACHMODE, &res); +} + +int drmModeDetachMode(int fd, uint32_t output_id, struct drm_mode_modeinfo *mode_info) +{ +	struct drm_mode_mode_cmd res; + +	memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo)); +	res.output_id = output_id; + +	return ioctl(fd, DRM_IOCTL_MODE_DETACHMODE, &res); +} + + +drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id) +{ +	struct drm_mode_get_property prop; +	drmModePropertyPtr r; +	struct drm_mode_property_blob *blob_tmp; +	int i; +	prop.prop_id = property_id; +	prop.count_enum_blobs = 0; +	prop.count_values = 0; +	prop.flags = 0; +	prop.enum_blob_ptr = 0; +	prop.values_ptr = 0; + +	if (ioctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) +		return 0; + +	if (prop.count_values) +		prop.values_ptr = VOID2U64(drmMalloc(prop.count_values * sizeof(uint64_t))); + +	if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_ENUM)) +		prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(struct drm_mode_property_enum))); + +	if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_BLOB)) { +		prop.values_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t))); +		prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t))); +	} + +	if (ioctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) { +		r = NULL; +		goto err_allocs; +	} + +	if (!(r = drmMalloc(sizeof(*r)))) +		return NULL; +	 +	r->prop_id = prop.prop_id; +	r->count_values = prop.count_values; +	 +	r->flags = prop.flags; +	if (prop.count_values) +		r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_values, sizeof(uint64_t)); +	if (prop.flags & DRM_MODE_PROP_ENUM) { +		r->count_enums = prop.count_enum_blobs; +		r->enums = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(struct drm_mode_property_enum)); +	} else	if (prop.flags & DRM_MODE_PROP_ENUM) { +		r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_enum_blobs, sizeof(uint32_t)); +		r->blob_ids = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(uint32_t)); +		r->count_blobs = prop.count_enum_blobs; +	} +	strncpy(r->name, prop.name, DRM_PROP_NAME_LEN); +	r->name[DRM_PROP_NAME_LEN-1] = 0; + +err_allocs: +	drmFree(U642VOID(prop.values_ptr)); +	drmFree(U642VOID(prop.enum_blob_ptr)); + +	return r; +} + +void drmModeFreeProperty(drmModePropertyPtr ptr) +{ +	if (!ptr) +		return; + +	drmFree(ptr->values); +	drmFree(ptr->enums); +	drmFree(ptr); +} + +drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id) +{ +	struct drm_mode_get_blob blob; +	drmModePropertyBlobPtr r; + +	blob.length = 0; +	blob.data = 0; +	blob.blob_id = blob_id; + +	if (ioctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) +		return NULL; + +	if (blob.length) +		blob.data = VOID2U64(drmMalloc(blob.length)); + +	if (ioctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) { +		r = NULL; +		goto err_allocs; +	} + +	if (!(r = drmMalloc(sizeof(*r)))) +		return NULL; + +	r->id = blob.blob_id; +	r->length = blob.length; +	r->data = drmAllocCpy(U642VOID(blob.data), 1, blob.length); + +err_allocs: +	drmFree(U642VOID(blob.data)); +	return r; +} + +void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr) +{ +	if (!ptr) +		return; + +	drmFree(ptr->data); +	drmFree(ptr); +} + +int drmModeOutputSetProperty(int fd, uint32_t output_id, uint32_t property_id, +			     uint64_t value) +{ +	struct drm_mode_output_set_property osp; +	int ret; + +	osp.output_id = output_id; +	osp.prop_id = property_id; +	osp.value = value; + +	if (ret = ioctl(fd, DRM_IOCTL_MODE_SETPROPERTY, &osp)) +		return ret; + +	return 0; +} diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h new file mode 100644 index 00000000..7cc3ceca --- /dev/null +++ b/libdrm/xf86drmMode.h @@ -0,0 +1,245 @@ +/* + * \file xf86drmMode.h + * Header for DRM modesetting interface. + * + * \author Jakob Bornecrantz <wallbraker@gmail.com> + * + * \par Acknowledgements: + * Feb 2007, Dave Airlie <airlied@linux.ie> + */ + +/* + * Copyright (c) <year> <copyright holders> + * + * 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 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. + * + */ + +#include <drm.h> +#include "xf86mm.h" + +/* + * This is the interface for modesetting for drm. + * + * In order to use this interface you must include either <stdint.h> or another + * header defining uint32_t, int32_t and uint16_t. + * + * It aims to provide a randr1.2 compatible interface for modesettings in the + * kernel, the interface is also ment to be used by libraries like EGL. + * + * More information can be found in randrproto.txt which can be found here: + * http://gitweb.freedesktop.org/?p=xorg/proto/randrproto.git + * + * There are some major diffrences to be noted. Unlike the randr1.2 proto you + * need to create the memory object of the framebuffer yourself with the ttm + * buffer object interface. This object needs to be pinned. + */ + + +typedef struct _drmModeRes { + +	int count_fbs; +	uint32_t *fbs; + +	int count_crtcs; +	uint32_t *crtcs; + +	int count_outputs; +	uint32_t *outputs; + +	uint32_t min_width, max_width; +	uint32_t min_height, max_height; +} drmModeRes, *drmModeResPtr; + +typedef struct drm_mode_fb_cmd drmModeFB, *drmModeFBPtr; + +typedef struct _drmModePropertyBlob { +	uint32_t id; +	uint32_t length; +	void *data; +} drmModePropertyBlobRes, *drmModePropertyBlobPtr; + +typedef struct _drmModeProperty { +	unsigned int prop_id; +	unsigned int flags; +	char name[DRM_PROP_NAME_LEN]; +	int count_values; +	uint64_t *values; // store the blob lengths +	int count_enums; +	struct drm_mode_property_enum *enums; +	int count_blobs; +	uint32_t *blob_ids; // store the blob IDs +} drmModePropertyRes, *drmModePropertyPtr; + +typedef struct _drmModeCrtc { +	unsigned int crtc_id; +	unsigned int buffer_id; /**< FB id to connect to 0 = disconnect*/ + +	uint32_t x, y; /**< Position on the frameuffer */ +	uint32_t width, height; +	int mode_valid; +	struct drm_mode_modeinfo mode; + +	int count_outputs; +	uint32_t outputs; /**< Outputs that are connected */ + +	int count_possibles; +	uint32_t possibles; /**< Outputs that can be connected */ + +	int gamma_size; /**< Number of gamma stops */ + +} drmModeCrtc, *drmModeCrtcPtr; + +typedef enum { +	DRM_MODE_CONNECTED         = 1, +	DRM_MODE_DISCONNECTED      = 2, +	DRM_MODE_UNKNOWNCONNECTION = 3 +} drmModeConnection; + +typedef enum { +	DRM_MODE_SUBPIXEL_UNKNOWN        = 1, +	DRM_MODE_SUBPIXEL_HORIZONTAL_RGB = 2, +	DRM_MODE_SUBPIXEL_HORIZONTAL_BGR = 3, +	DRM_MODE_SUBPIXEL_VERTICAL_RGB   = 4, +	DRM_MODE_SUBPIXEL_VERTICAL_BGR   = 5, +	DRM_MODE_SUBPIXEL_NONE           = 6 +} drmModeSubPixel; + +typedef struct _drmModeOutput { +	unsigned int output_id; + +	unsigned int crtc; /**< Crtc currently connected to */ +	unsigned int output_type; +	unsigned int output_type_id; +	drmModeConnection connection; +	uint32_t mmWidth, mmHeight; /**< HxW in millimeters */ +	drmModeSubPixel subpixel; + +	int count_crtcs; +	uint32_t crtcs; /**< Possible crtc to connect to */ + +	int count_clones; +	uint32_t clones; /**< Mask of clones */ + +	int count_modes; +	struct drm_mode_modeinfo *modes; + +	int count_props; +	uint32_t *props; /**< List of property ids */ +	uint64_t *prop_values; /**< List of property values */ + +} drmModeOutput, *drmModeOutputPtr; + + + +extern void drmModeFreeModeInfo( struct drm_mode_modeinfo *ptr ); +extern void drmModeFreeResources( drmModeResPtr ptr ); +extern void drmModeFreeFB( drmModeFBPtr ptr ); +extern void drmModeFreeCrtc( drmModeCrtcPtr ptr ); +extern void drmModeFreeOutput( drmModeOutputPtr ptr ); + +/** + * Retrives all of the resources associated with a card. + */ +extern drmModeResPtr drmModeGetResources(int fd); + +/** + * Retrives the hotplug counter + */ +extern uint32_t drmModeGetHotplug(int fd); + +/* + * FrameBuffer manipulation. + */ + +/** + * Retrive information about framebuffer bufferId + */ +extern drmModeFBPtr drmModeGetFB(int fd, uint32_t bufferId); + +/** + * Creates a new framebuffer with an buffer object as its scanout buffer. + */ +extern int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, +			uint8_t bpp, uint32_t pitch, drmBO *bo, +			uint32_t *buf_id); +/** + * Destroies the given framebuffer. + */ +extern int drmModeRmFB(int fd, uint32_t bufferId); + + +/* + * Crtc functions + */ + +/** + * Retrive information about the ctrt crtcId + */ +extern drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId); + +/** + * Set the mode on a crtc crtcId with the given mode modeId. + */ +int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, +                   uint32_t x, uint32_t y, uint32_t *outputs, int count, +		   struct drm_mode_modeinfo *mode); + +/* + * Cursor functions + */ + +/** + * Set the cursor on crtc + */ +int drmModeSetCursor(int fd, uint32_t crtcId, drmBO *bo, uint32_t width, uint32_t height); + +/** + * Move the cursor on crtc + */ +int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y); + +/* + * Output manipulation + */ + +/** + * Retrive information about the output outputId. + */ +extern drmModeOutputPtr drmModeGetOutput(int fd, +		uint32_t outputId); + +/** + * Attaches the given mode to an output. + */ +extern int drmModeAttachMode(int fd, uint32_t outputId, struct drm_mode_modeinfo *mode_info); + +/** + * Detaches a mode from the output + * must be unused, by the given mode. + */ +extern int drmModeDetachMode(int fd, uint32_t outputId, struct drm_mode_modeinfo *mode_info); + +extern drmModePropertyPtr drmModeGetProperty(int fd, uint32_t propertyId); +extern void drmModeFreeProperty(drmModePropertyPtr ptr); + +extern drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id); +extern void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr); +extern int drmModeOutputSetProperty(int fd, uint32_t output_id, uint32_t property_id, +				    uint64_t value); diff --git a/linux-core/Makefile b/linux-core/Makefile index 7f6b123e..2f33e5df 100644 --- a/linux-core/Makefile +++ b/linux-core/Makefile @@ -58,7 +58,7 @@ endif  # Modules for all architectures  MODULE_LIST := drm.o tdfx.o r128.o radeon.o mga.o sis.o savage.o via.o \ -               mach64.o nv.o nouveau.o xgi.o +               mach64.o nv.o nouveau.o xgi.o radeon_ms.o  # Modules only for ix86 architectures  ifneq (,$(findstring 86,$(MACHINE))) @@ -92,6 +92,7 @@ NVHEADERS =     nv_drv.h $(DRMHEADERS)  FFBHEADERS = 	ffb_drv.h $(DRMHEADERS)  NOUVEAUHEADERS = nouveau_drv.h nouveau_drm.h nouveau_reg.h $(DRMHEADERS)  XGIHEADERS = xgi_cmdlist.h xgi_drv.h xgi_misc.h xgi_regs.h $(DRMHEADERS) +RADEONMSHEADERS = radeon_ms_driver.h $(DRMHEADERS)   PROGS = dristat drmstat @@ -286,6 +287,7 @@ CONFIG_DRM_MACH64 := n  CONFIG_DRM_NV := n  CONFIG_DRM_NOUVEAU := n  CONFIG_DRM_XGI := n +CONFIG_DRM_RADEON_MS := n  # Enable module builds for the modules requested/supported. @@ -325,6 +327,9 @@ endif  ifneq (,$(findstring xgi,$(DRM_MODULES)))  CONFIG_DRM_XGI := m  endif +ifneq (,$(findstring radeon_ms,$(DRM_MODULES))) +CONFIG_DRM_RADEON_MS := m +endif  # These require AGP support diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index e7c280d0..8f6f01ac 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -13,14 +13,16 @@ drm-objs    := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \  		drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \  		drm_memory_debug.o ati_pcigart.o drm_sman.o \  		drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \ -	        drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_bo_lock.o \ -		drm_regman.o +	        drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_crtc.o \ +		drm_edid.o drm_modes.o drm_bo_lock.o drm_regman.o  tdfx-objs   := tdfx_drv.o  r128-objs   := r128_drv.o r128_cce.o r128_state.o r128_irq.o  mga-objs    := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o  i810-objs   := i810_drv.o i810_dma.o  i915-objs   := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \ -		i915_buffer.o i915_compat.o +		i915_buffer.o intel_display.o intel_crt.o intel_lvds.o \ +		intel_sdvo.o intel_modes.o intel_i2c.o i915_init.o intel_fb.o \ +		intel_tv.o i915_compat.o  nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \  		nouveau_object.o nouveau_irq.o nouveau_notifier.o nouveau_swmthd.o \  		nouveau_sgdma.o nouveau_dma.o nouveau_buffer.o nouveau_fence.o \ @@ -31,7 +33,14 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \  		nv04_graph.o nv10_graph.o nv20_graph.o \  		nv40_graph.o nv50_graph.o \  		nv04_instmem.o nv50_instmem.o -radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o +radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o radeon_fence.o radeon_buffer.o +radeon_ms-objs := radeon_ms_drv.o radeon_ms_drm.o radeon_ms_family.o \ +		radeon_ms_state.o radeon_ms_bo.o radeon_ms_irq.o \ +		radeon_ms_bus.o radeon_ms_fence.o \ +		radeon_ms_cp.o radeon_ms_cp_mc.o radeon_ms_i2c.o \ +		radeon_ms_output.o radeon_ms_crtc.o radeon_ms_fb.o \ +		radeon_ms_exec.o radeon_ms_gpu.o radeon_ms_dac.o \ +		radeon_ms_properties.o radeon_ms_rom.o radeon_ms_combios.o  sis-objs    := sis_drv.o sis_mm.o  ffb-objs    := ffb_drv.o ffb_context.o  savage-objs := savage_drv.o savage_bci.o savage_state.o @@ -45,6 +54,7 @@ xgi-objs    := xgi_cmdlist.o xgi_drv.o xgi_fb.o xgi_misc.o xgi_pcie.o \  ifeq ($(CONFIG_COMPAT),y)  drm-objs    += drm_ioc32.o  radeon-objs += radeon_ioc32.o +radeon_ms-objs += radeon_ms_compat.o  mga-objs    += mga_ioc32.o  r128-objs   += r128_ioc32.o  i915-objs   += i915_ioc32.o @@ -67,3 +77,4 @@ obj-$(CONFIG_DRM_MACH64)+= mach64.o  obj-$(CONFIG_DRM_NV)    += nv.o  obj-$(CONFIG_DRM_NOUVEAU) += nouveau.o  obj-$(CONFIG_DRM_XGI)   += xgi.o +obj-$(CONFIG_DRM_RADEON_MS) += radeon_ms.o diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index 68029635..97a5dfb2 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -35,6 +35,45 @@  # define ATI_PCIGART_PAGE_SIZE		4096	/**< PCI GART page size */ +static __inline__ void insert_page_into_table(struct drm_ati_pcigart_info *info, u32 page_base, u32 *pci_gart) +{ +	switch(info->gart_reg_if) { +	case DRM_ATI_GART_IGP: +		*pci_gart = cpu_to_le32((page_base) | 0xc); +		break; +	case DRM_ATI_GART_PCIE: +		*pci_gart = cpu_to_le32((page_base >> 8) | 0xc); +		break; +	default: +	case DRM_ATI_GART_PCI: +		*pci_gart = cpu_to_le32(page_base); +		break; +	} +} + +static __inline__ u32 get_page_base_from_table(struct drm_ati_pcigart_info *info, u32 *pci_gart) +{ +	u32 retval; +	switch(info->gart_reg_if) { +	case DRM_ATI_GART_IGP: +		retval = *pci_gart; +		retval &= ~0xc; +		break; +	case DRM_ATI_GART_PCIE: +		retval = *pci_gart; +		retval &= ~0xc; +		retval <<= 8; +		break; +	default: +	case DRM_ATI_GART_PCI: +		retval = *pci_gart; +		break; +	} +	return retval; +} + + +  static void *drm_ati_alloc_pcigart_table(int order)  {  	unsigned long address; @@ -207,18 +246,7 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga  		page_base = (u32) entry->busaddr[i];  		for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { -			switch(gart_info->gart_reg_if) { -			case DRM_ATI_GART_IGP: -				*pci_gart = cpu_to_le32((page_base) | 0xc); -				break; -			case DRM_ATI_GART_PCIE: -				*pci_gart = cpu_to_le32((page_base >> 8) | 0xc); -				break; -			default: -			case DRM_ATI_GART_PCI: -				*pci_gart = cpu_to_le32(page_base); -				break; -			} +			insert_page_into_table(gart_info, page_base, pci_gart);  			pci_gart++;  			page_base += ATI_PCIGART_PAGE_SIZE;  		} @@ -238,3 +266,147 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga  	return ret;  }  EXPORT_SYMBOL(drm_ati_pcigart_init); + +static int ati_pcigart_needs_unbind_cache_adjust(struct drm_ttm_backend *backend) +{ +	return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 0 : 1); +} + +static int ati_pcigart_populate(struct drm_ttm_backend *backend, +				unsigned long num_pages, +				struct page **pages, +				struct page *dummy_page) +{ +	ati_pcigart_ttm_backend_t *atipci_be = +		container_of(backend, ati_pcigart_ttm_backend_t, backend); + +	DRM_ERROR("%ld\n", num_pages); +	atipci_be->pages = pages; +	atipci_be->num_pages = num_pages; +	atipci_be->populated = 1; +	return 0; +} + +static int ati_pcigart_bind_ttm(struct drm_ttm_backend *backend, +				struct drm_bo_mem_reg *bo_mem) +{ +	ati_pcigart_ttm_backend_t *atipci_be = +		container_of(backend, ati_pcigart_ttm_backend_t, backend); +        off_t j; +	int i; +	struct drm_ati_pcigart_info *info = atipci_be->gart_info; +	u32 *pci_gart; +	u32 page_base; +	unsigned long offset = bo_mem->mm_node->start; +	pci_gart = info->addr; + +	DRM_ERROR("Offset is %08lX\n", bo_mem->mm_node->start); +        j = offset; +        while (j < (offset + atipci_be->num_pages)) { +		if (get_page_base_from_table(info, pci_gart+j)) +			return -EBUSY; +                j++; +        } + +        for (i = 0, j = offset; i < atipci_be->num_pages; i++, j++) { +		struct page *cur_page = atipci_be->pages[i]; +                /* write value */ +		page_base = page_to_phys(cur_page); +		insert_page_into_table(info, page_base, pci_gart + j); +        } + +#if defined(__i386__) || defined(__x86_64__) +	wbinvd(); +#else +	mb(); +#endif + +	atipci_be->gart_flush_fn(atipci_be->dev); + +	atipci_be->bound = 1; +	atipci_be->offset = offset; +        /* need to traverse table and add entries */ +	DRM_DEBUG("\n"); +	return 0; +} + +static int ati_pcigart_unbind_ttm(struct drm_ttm_backend *backend) +{ +	ati_pcigart_ttm_backend_t *atipci_be = +		container_of(backend, ati_pcigart_ttm_backend_t, backend); +	struct drm_ati_pcigart_info *info = atipci_be->gart_info;	 +	unsigned long offset = atipci_be->offset; +	int i; +	off_t j; +	u32 *pci_gart = info->addr; + +	DRM_DEBUG("\n"); + +	if (atipci_be->bound != 1) +		return -EINVAL; + +	for (i = 0, j = offset; i < atipci_be->num_pages; i++, j++) { +		*(pci_gart + j) = 0; +	} +	atipci_be->gart_flush_fn(atipci_be->dev); +	atipci_be->bound = 0; +	atipci_be->offset = 0; +	return 0; +} + +static void ati_pcigart_clear_ttm(struct drm_ttm_backend *backend) +{ +	ati_pcigart_ttm_backend_t *atipci_be = +		container_of(backend, ati_pcigart_ttm_backend_t, backend); + +	DRM_DEBUG("\n");	 +	if (atipci_be->pages) { +		backend->func->unbind(backend); +		atipci_be->pages = NULL; + +	} +	atipci_be->num_pages = 0; +} + +static void ati_pcigart_destroy_ttm(struct drm_ttm_backend *backend) +{ +	ati_pcigart_ttm_backend_t *atipci_be; +	if (backend) { +		DRM_DEBUG("\n"); +		atipci_be = container_of(backend, ati_pcigart_ttm_backend_t, backend); +		if (atipci_be) { +			if (atipci_be->pages) { +				backend->func->clear(backend); +			} +			drm_ctl_free(atipci_be, sizeof(*atipci_be), DRM_MEM_TTM); +		} +	} +} + +static struct drm_ttm_backend_func ati_pcigart_ttm_backend =  +{ +	.needs_ub_cache_adjust = ati_pcigart_needs_unbind_cache_adjust, +	.populate = ati_pcigart_populate, +	.clear = ati_pcigart_clear_ttm, +	.bind = ati_pcigart_bind_ttm, +	.unbind = ati_pcigart_unbind_ttm, +	.destroy =  ati_pcigart_destroy_ttm, +}; + +struct drm_ttm_backend *ati_pcigart_init_ttm(struct drm_device *dev, struct drm_ati_pcigart_info *info, void (*gart_flush_fn)(struct drm_device *dev)) +{ +	ati_pcigart_ttm_backend_t *atipci_be; + +	atipci_be = drm_ctl_calloc(1, sizeof (*atipci_be), DRM_MEM_TTM); +	if (!atipci_be) +		return NULL; +	 +	atipci_be->populated = 0; +	atipci_be->backend.func = &ati_pcigart_ttm_backend; +	atipci_be->gart_info = info; +	atipci_be->gart_flush_fn = gart_flush_fn; +	atipci_be->dev = dev; + +	return &atipci_be->backend; +} +EXPORT_SYMBOL(ati_pcigart_init_ttm); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 33f3649e..297d8d60 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -173,6 +173,8 @@ struct drm_file;  #include "drm_compat.h" +#include "drm_crtc.h" +  /***********************************************************************/  /** \name Macros to make printk easier */  /*@{*/ @@ -260,11 +262,11 @@ struct drm_file;   */  #define LOCK_TEST_WITH_RETURN( dev, file_priv )				\  do {									\ -	if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) ||		\ -	     dev->lock.file_priv != file_priv )	{			\ +	if ( !_DRM_LOCK_IS_HELD( file_priv->master->lock.hw_lock->lock ) ||		\ +	     file_priv->master->lock.file_priv != file_priv )	{			\  		DRM_ERROR( "%s called without lock held, held  %d owner %p %p\n",\ -			   __FUNCTION__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\ -			   dev->lock.file_priv, file_priv );		\ +			   __FUNCTION__, _DRM_LOCK_IS_HELD( file_priv->master->lock.hw_lock->lock ),\ +			   file_priv->master->lock.file_priv, file_priv );		\  		return -EINVAL;						\  	}								\  } while (0) @@ -298,6 +300,7 @@ typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd,  #define DRM_AUTH        0x1  #define DRM_MASTER      0x2  #define DRM_ROOT_ONLY   0x4 +#define DRM_CONTROL_ALLOW 0x8 // allow ioctl to operate on control node   struct drm_ioctl_desc {  	unsigned int cmd; @@ -407,14 +410,12 @@ enum drm_ref_type {  /** File private data */  struct drm_file {  	int authenticated; -	int master; -	int minor;  	pid_t pid;  	uid_t uid;  	drm_magic_t magic;  	unsigned long ioctl_count;  	struct list_head lhead; -	struct drm_head *head; +	struct drm_minor *minor;  	int remove_auth_on_close;  	unsigned long lock_count; @@ -430,6 +431,11 @@ struct drm_file {  	struct drm_open_hash refd_object_hash[_DRM_NO_REF_TYPES];  	struct file *filp;  	void *driver_priv; + +	int is_master; /* this file private is a master for a minor */ +	struct drm_master *master; /* master this node is currently associated with +				      N.B. not always minor->master */ +	struct list_head fbs;  };  /** Wait queue */ @@ -564,6 +570,8 @@ struct drm_map_list {  	struct drm_map *map;			/**< mapping */  	uint64_t user_token;  	struct drm_mm_node *file_offset_node; +	struct drm_master *master; /** if this map is associated with a specific +				       master */  };  typedef struct drm_map drm_local_map_t; @@ -603,6 +611,28 @@ struct drm_ati_pcigart_info {  #include "drm_objects.h" +/* per-master structure */ +struct drm_master { +	 +	struct list_head head; /**< each minor contains a list of masters */ +	struct drm_minor *minor; /**< link back to minor we are a master for */ + +	char *unique;			/**< Unique identifier: e.g., busid */ +	int unique_len;			/**< Length of unique field */ + +	int blocked;			/**< Blocked due to VC switch? */ + +	/** \name Authentication */ +	/*@{ */ +	struct drm_open_hash magiclist; +	struct list_head magicfree; +	/*@} */ + +	struct drm_lock_data lock;		/**< Information on hardware lock */ + +	void *driver_priv; /**< Private structure for driver to use */ +}; +  /**   * DRM driver structure. This structure represent the common code for   * a family of cards. There will one drm_device for each card present @@ -702,6 +732,15 @@ struct drm_driver {  	void (*set_version) (struct drm_device *dev,  			     struct drm_set_version *sv); +	/* FB routines, if present */ +	int (*fb_probe)(struct drm_device *dev, struct drm_crtc *crtc); +	int (*fb_remove)(struct drm_device *dev, struct drm_crtc *crtc); +	int (*fb_resize)(struct drm_device *dev, struct drm_crtc *crtc); + +	/* Master routines */ +	int (*master_create)(struct drm_device *dev, struct drm_master *master); +	void (*master_destroy)(struct drm_device *dev, struct drm_master *master); +  	struct drm_fence_driver *fence_driver;  	struct drm_bo_driver *bo_driver; @@ -721,17 +760,28 @@ struct drm_driver {  	struct pci_driver pci_driver;  }; +#define DRM_MINOR_UNASSIGNED 0 +#define DRM_MINOR_CONTROL 1 +#define DRM_MINOR_LEGACY 2 +#define DRM_MINOR_RENDER 3  /** - * DRM head structure. This structure represent a video head on a card - * that may contain multiple heads. Embed one per head of these in the - * private drm_device structure. + * DRM minor structure. This structure represents a drm minor number.   */ -struct drm_head { -	int minor;			/**< Minor device number */ +struct drm_minor { +	int index;			/**< Minor device number */ +	int type;                       /**< Control or render */ +	dev_t device;			/**< Device number for mknod */ +	struct device kdev;		/**< Linux device */  	struct drm_device *dev; +	/* for render nodes */  	struct proc_dir_entry *dev_root;  /**< proc directory entry */ -	dev_t device;			/**< Device number for mknod */  	struct class_device *dev_class; + +	/* for control nodes - a pointer to the current master for this control node */ +	struct drm_master *master; /* currently active master for this node */ +	struct list_head master_list; + +	/* possibly needs a list of configured modesetting pieces */  }; @@ -740,14 +790,9 @@ struct drm_head {   * may contain multiple heads.   */  struct drm_device { -	struct device dev;		/**< Linux device */ -	char *unique;			/**< Unique identifier: e.g., busid */ -	int unique_len;			/**< Length of unique field */  	char *devname;			/**< For /proc/interrupts */  	int if_version;			/**< Highest interface version set */ -	int blocked;			/**< Blocked due to VC switch? */ -  	/** \name Locks */  	/*@{ */  	spinlock_t count_lock;		/**< For inuse, drm_device::open_count, drm_device::buf_use */ @@ -770,12 +815,6 @@ struct drm_device {  	atomic_t counts[15];  	/*@} */ -	/** \name Authentication */ -	/*@{ */ -	struct list_head filelist; -	struct drm_open_hash magiclist; -	struct list_head magicfree; -	/*@} */  	/** \name Memory management */  	/*@{ */ @@ -796,7 +835,9 @@ struct drm_device {  	struct idr ctx_idr;  	struct list_head vmalist;	/**< List of vmas (for debugging) */ -	struct drm_lock_data lock;		/**< Information on hardware lock */ + +	struct list_head filelist; +  	/*@} */  	/** \name DMA queues (contexts) */ @@ -808,6 +849,7 @@ struct drm_device {  	struct drm_device_dma *dma;		/**< Optional pointer for DMA support */  	/*@} */ +  	/** \name Context support */  	/*@{ */  	int irq;			/**< Interrupt used by board */ @@ -870,7 +912,10 @@ struct drm_device {  	struct drm_driver *driver;  	drm_local_map_t *agp_buffer_map;  	unsigned int agp_buffer_token; -	struct drm_head primary;		/**< primary screen head */ + +	/* minor number for control node */ +	struct drm_minor *control; +	struct drm_minor *primary;		/**< render type primary screen head */  	struct drm_fence_manager fm;  	struct drm_buffer_manager bm; @@ -880,6 +925,9 @@ struct drm_device {  	spinlock_t drw_lock;  	struct idr drw_idr;  	/*@} */ + +	/* DRM mode setting */ +	struct drm_mode_config mode_config;  };  #if __OS_HAS_AGP @@ -891,6 +939,17 @@ struct drm_agp_ttm_backend {  };  #endif +typedef struct ati_pcigart_ttm_backend { +	struct drm_ttm_backend backend; +	int populated; +	void (*gart_flush_fn)(struct drm_device *dev); +	struct drm_ati_pcigart_info *gart_info; +	unsigned long offset; +	struct page **pages; +	int num_pages; +	int bound; +	struct drm_device *dev; +} ati_pcigart_ttm_backend_t;  static __inline__ int drm_core_check_feature(struct drm_device *dev,  					     int feature) @@ -1184,26 +1243,25 @@ extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle);  extern struct drm_ttm_backend *drm_agp_init_ttm(struct drm_device *dev);  extern void drm_agp_chipset_flush(struct drm_device *dev);  				/* Stub support (drm_stub.h) */ +extern struct drm_master *drm_get_master(struct drm_minor *minor); +extern void drm_put_master(struct drm_master *master);  extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,  		     struct drm_driver *driver);  extern int drm_put_dev(struct drm_device *dev); -extern int drm_put_head(struct drm_head * head); +extern int drm_put_minor(struct drm_minor **minor);  extern unsigned int drm_debug; /* 1 to enable debug output */ -extern unsigned int drm_cards_limit; -extern struct drm_head **drm_heads; +  extern struct class *drm_class;  extern struct proc_dir_entry *drm_proc_root; +extern struct idr drm_minors_idr; +  extern drm_local_map_t *drm_getsarea(struct drm_device *dev);  				/* Proc support (drm_proc.h) */ -extern int drm_proc_init(struct drm_device *dev, -			 int minor, -			 struct proc_dir_entry *root, -			 struct proc_dir_entry **dev_root); -extern int drm_proc_cleanup(int minor, -			    struct proc_dir_entry *root, -			    struct proc_dir_entry *dev_root); +int drm_proc_init(struct drm_minor *minor, int minor_id, +		  struct proc_dir_entry *root); +int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root);  				/* Scatter Gather Support (drm_scatter.h) */  extern void drm_sg_cleanup(struct drm_sg_mem * entry); @@ -1216,6 +1274,7 @@ extern int drm_sg_free(struct drm_device *dev, void *data,  			       /* ATI PCIGART support (ati_pcigart.h) */  extern int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info);  extern int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info); +extern struct drm_ttm_backend *ati_pcigart_init_ttm(struct drm_device *dev, struct drm_ati_pcigart_info *info, void (*gart_flush_fn)(struct drm_device *dev));  extern drm_dma_handle_t *drm_pci_alloc(struct drm_device *dev, size_t size,  			   size_t align, dma_addr_t maxaddr); @@ -1226,8 +1285,8 @@ extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t *dmah);  struct drm_sysfs_class;  extern struct class *drm_sysfs_create(struct module *owner, char *name);  extern void drm_sysfs_destroy(void); -extern int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head); -extern void drm_sysfs_device_remove(struct drm_device *dev); +extern int drm_sysfs_device_add(struct drm_minor *minor); +extern void drm_sysfs_device_remove(struct drm_minor *minor);  /*   * Basic memory manager support (drm_mm.c) @@ -1244,6 +1303,7 @@ extern int drm_mm_clean(struct drm_mm *mm);  extern unsigned long drm_mm_tail_space(struct drm_mm *mm);  extern int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size);  extern int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size); +extern void drm_mm_print(struct drm_mm *mm, const char *name);  static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block)  { diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index 02187017..adcb93a5 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -130,7 +130,7 @@ EXPORT_SYMBOL(drm_agp_acquire);  int drm_agp_acquire_ioctl(struct drm_device *dev, void *data,  			  struct drm_file *file_priv)  { -	return drm_agp_acquire((struct drm_device *) file_priv->head->dev); +	return drm_agp_acquire((struct drm_device *) file_priv->minor->dev);  }  /** diff --git a/linux-core/drm_auth.c b/linux-core/drm_auth.c index c904a91d..20c8a634 100644 --- a/linux-core/drm_auth.c +++ b/linux-core/drm_auth.c @@ -45,14 +45,15 @@   * the one with matching magic number, while holding the drm_device::struct_mutex   * lock.   */ -static struct drm_file *drm_find_file(struct drm_device * dev, drm_magic_t magic) +static struct drm_file *drm_find_file(struct drm_master *master , drm_magic_t magic)  {  	struct drm_file *retval = NULL;  	struct drm_magic_entry *pt;  	struct drm_hash_item *hash; +	struct drm_device *dev = master->minor->dev;  	mutex_lock(&dev->struct_mutex); -	if (!drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) { +	if (!drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) {  		pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item);  		retval = pt->priv;  	} @@ -71,11 +72,11 @@ static struct drm_file *drm_find_file(struct drm_device * dev, drm_magic_t magic   * associated the magic number hash key in drm_device::magiclist, while holding   * the drm_device::struct_mutex lock.   */ -static int drm_add_magic(struct drm_device * dev, struct drm_file * priv, +static int drm_add_magic(struct drm_master *master, struct drm_file * priv,  			 drm_magic_t magic)  {  	struct drm_magic_entry *entry; - +	struct drm_device *dev = master->minor->dev;  	DRM_DEBUG("%d\n", magic);  	entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC); @@ -85,8 +86,8 @@ static int drm_add_magic(struct drm_device * dev, struct drm_file * priv,  	entry->priv = priv;  	entry->hash_item.key = (unsigned long)magic;  	mutex_lock(&dev->struct_mutex); -	drm_ht_insert_item(&dev->magiclist, &entry->hash_item); -	list_add_tail(&entry->head, &dev->magicfree); +	drm_ht_insert_item(&master->magiclist, &entry->hash_item); +	list_add_tail(&entry->head, &master->magicfree);  	mutex_unlock(&dev->struct_mutex);  	return 0; @@ -101,20 +102,21 @@ static int drm_add_magic(struct drm_device * dev, struct drm_file * priv,   * Searches and unlinks the entry in drm_device::magiclist with the magic   * number hash key, while holding the drm_device::struct_mutex lock.   */ -static int drm_remove_magic(struct drm_device * dev, drm_magic_t magic) +static int drm_remove_magic(struct drm_master *master, drm_magic_t magic)  {  	struct drm_magic_entry *pt;  	struct drm_hash_item *hash; +	struct drm_device *dev = master->minor->dev;  	DRM_DEBUG("%d\n", magic);  	mutex_lock(&dev->struct_mutex); -	if (drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) { +	if (drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) {  		mutex_unlock(&dev->struct_mutex);  		return -EINVAL;  	}  	pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item); -	drm_ht_remove_item(&dev->magiclist, hash); +	drm_ht_remove_item(&master->magiclist, hash);  	list_del(&pt->head);  	mutex_unlock(&dev->struct_mutex); @@ -152,9 +154,9 @@ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)  				++sequence;	/* reserve 0 */  			auth->magic = sequence++;  			spin_unlock(&lock); -		} while (drm_find_file(dev, auth->magic)); +		} while (drm_find_file(file_priv->master, auth->magic));  		file_priv->magic = auth->magic; -		drm_add_magic(dev, file_priv, auth->magic); +		drm_add_magic(file_priv->master, file_priv, auth->magic);  	}  	DRM_DEBUG("%u\n", auth->magic); @@ -180,9 +182,9 @@ int drm_authmagic(struct drm_device *dev, void *data,  	struct drm_file *file;  	DRM_DEBUG("%u\n", auth->magic); -	if ((file = drm_find_file(dev, auth->magic))) { +	if ((file = drm_find_file(file_priv->master, auth->magic))) {  		file->authenticated = 1; -		drm_remove_magic(dev, auth->magic); +		drm_remove_magic(file_priv->master, auth->magic);  		return 0;  	}  	return -EINVAL; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 3b180d15..1f3c2d2c 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -574,7 +574,6 @@ void drm_putback_buffer_objects(struct drm_device *dev)  }  EXPORT_SYMBOL(drm_putback_buffer_objects); -  /*   * Note. The caller has to register (if applicable)   * and deregister fence object usage. @@ -1189,7 +1188,7 @@ static int drm_buffer_object_map(struct drm_file *file_priv, uint32_t handle,  				 struct drm_bo_info_rep *rep)  {  	struct drm_buffer_object *bo; -	struct drm_device *dev = file_priv->head->dev; +	struct drm_device *dev = file_priv->minor->dev;  	int ret = 0;  	int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; @@ -1261,7 +1260,7 @@ out:  static int drm_buffer_object_unmap(struct drm_file *file_priv, uint32_t handle)  { -	struct drm_device *dev = file_priv->head->dev; +	struct drm_device *dev = file_priv->minor->dev;  	struct drm_buffer_object *bo;  	struct drm_ref_object *ro;  	int ret = 0; @@ -1653,7 +1652,7 @@ int drm_bo_handle_validate(struct drm_file *file_priv, uint32_t handle,  			   struct drm_bo_info_rep *rep,  			   struct drm_buffer_object **bo_rep)  { -	struct drm_device *dev = file_priv->head->dev; +	struct drm_device *dev = file_priv->minor->dev;  	struct drm_buffer_object *bo;  	int ret; @@ -1689,7 +1688,7 @@ EXPORT_SYMBOL(drm_bo_handle_validate);  static int drm_bo_handle_info(struct drm_file *file_priv, uint32_t handle,  			      struct drm_bo_info_rep *rep)  { -	struct drm_device *dev = file_priv->head->dev; +	struct drm_device *dev = file_priv->minor->dev;  	struct drm_buffer_object *bo;  	mutex_lock(&dev->struct_mutex); @@ -1712,7 +1711,7 @@ static int drm_bo_handle_wait(struct drm_file *file_priv, uint32_t handle,  			      uint32_t hint,  			      struct drm_bo_info_rep *rep)  { -	struct drm_device *dev = file_priv->head->dev; +	struct drm_device *dev = file_priv->minor->dev;  	struct drm_buffer_object *bo;  	int no_wait = hint & DRM_BO_HINT_DONT_BLOCK;  	int ret; @@ -1757,7 +1756,7 @@ int drm_buffer_object_create(struct drm_device *dev,  	size += buffer_start & ~PAGE_MASK;  	num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;  	if (num_pages == 0) { -		DRM_ERROR("Illegal buffer object size.\n"); +		DRM_ERROR("Illegal buffer object size %ld.\n", size);  		return -EINVAL;  	} @@ -1832,7 +1831,7 @@ EXPORT_SYMBOL(drm_buffer_object_create);  static int drm_bo_add_user_object(struct drm_file *file_priv,  				  struct drm_buffer_object *bo, int shareable)  { -	struct drm_device *dev = file_priv->head->dev; +	struct drm_device *dev = file_priv->minor->dev;  	int ret;  	mutex_lock(&dev->struct_mutex); @@ -1880,7 +1879,7 @@ int drm_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fil  	if (bo_type == drm_bo_type_user)  		req->flags &= ~DRM_BO_FLAG_SHAREABLE; -	ret = drm_buffer_object_create(file_priv->head->dev, +	ret = drm_buffer_object_create(file_priv->minor->dev,  				       req->size, bo_type, req->flags,  				       req->hint, req->page_alignment,  				       req->buffer_start, &entry); @@ -2350,6 +2349,7 @@ out:  	mutex_unlock(&dev->struct_mutex);  	return ret;  } +EXPORT_SYMBOL(drm_bo_driver_finish);  /*   * This function is intended to be called on drm driver load. diff --git a/linux-core/drm_bo_lock.c b/linux-core/drm_bo_lock.c index f967fb7c..2795384e 100644 --- a/linux-core/drm_bo_lock.c +++ b/linux-core/drm_bo_lock.c @@ -141,7 +141,7 @@ int drm_bo_write_lock(struct drm_bo_lock *lock, struct drm_file *file_priv)  	 * while holding it.  	 */ -	dev = file_priv->head->dev; +	dev = file_priv->minor->dev;  	mutex_lock(&dev->struct_mutex);  	ret = drm_add_user_object(file_priv, &lock->base, 0);  	lock->base.remove = &drm_bo_write_lock_remove; @@ -156,7 +156,7 @@ int drm_bo_write_lock(struct drm_bo_lock *lock, struct drm_file *file_priv)  int drm_bo_write_unlock(struct drm_bo_lock *lock, struct drm_file *file_priv)  { -	struct drm_device *dev = file_priv->head->dev; +	struct drm_device *dev = file_priv->minor->dev;  	struct drm_ref_object *ro;  	mutex_lock(&dev->struct_mutex); diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c index b06a09f0..db433d63 100644 --- a/linux-core/drm_bo_move.c +++ b/linux-core/drm_bo_move.c @@ -147,6 +147,7 @@ void drm_mem_reg_iounmap(struct drm_device *dev, struct drm_bo_mem_reg *mem,  	if (virtual && (man->flags & _DRM_FLAG_NEEDS_IOREMAP))  		iounmap(virtual);  } +EXPORT_SYMBOL(drm_mem_reg_iounmap);  static int drm_copy_io_page(void *dst, void *src, unsigned long page)  { diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index 75c75c2f..031f8ba0 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -52,9 +52,9 @@ struct drm_map_list *drm_find_matching_map(struct drm_device *dev, drm_local_map  {  	struct drm_map_list *entry;  	list_for_each_entry(entry, &dev->maplist, head) { -		if (entry->map && map->type == entry->map->type && -		    ((entry->map->offset == map->offset) || -		     (map->type == _DRM_SHM && map->flags==_DRM_CONTAINS_LOCK))) { +		if (entry->map && (entry->master == dev->primary->master) && (map->type == entry->map->type) && +		    ((entry->map->offset == map->offset) ||  +		     ((map->type == _DRM_SHM) && (map->flags&_DRM_CONTAINS_LOCK)))) {  			return entry;  		}  	} @@ -209,12 +209,12 @@ static int drm_addmap_core(struct drm_device *dev, unsigned int offset,  		map->offset = (unsigned long)map->handle;  		if (map->flags & _DRM_CONTAINS_LOCK) {  			/* Prevent a 2nd X Server from creating a 2nd lock */ -			if (dev->lock.hw_lock != NULL) { +			if (dev->primary->master->lock.hw_lock != NULL) {  				vfree(map->handle);  				drm_free(map, sizeof(*map), DRM_MEM_MAPS);  				return -EBUSY;  			} -			dev->sigdata.lock = dev->lock.hw_lock = map->handle;	/* Pointer to lock */ +			dev->sigdata.lock = dev->primary->master->lock.hw_lock = map->handle;	/* Pointer to lock */  		}  		break;  	case _DRM_AGP: { @@ -318,6 +318,7 @@ static int drm_addmap_core(struct drm_device *dev, unsigned int offset,  	list->user_token = list->hash.key << PAGE_SHIFT;  	mutex_unlock(&dev->struct_mutex); +	list->master = dev->primary->master;  	*maplist = list;  	return 0;  } @@ -412,6 +413,9 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map)  		break;  	case _DRM_SHM:  		vfree(map->handle); +		dev->sigdata.lock = dev->primary->master->lock.hw_lock = NULL;   /* SHM removed */ +		dev->primary->master->lock.file_priv = NULL; +		wake_up_interruptible(&dev->primary->master->lock.lock_queue);  		break;  	case _DRM_AGP:  	case _DRM_SCATTER_GATHER: diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index a745a7d9..cd4ff7df 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -729,3 +729,38 @@ void *idr_replace(struct idr *idp, void *ptr, int id)  }  EXPORT_SYMBOL(idr_replace);  #endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) +static __inline__ unsigned long __round_jiffies(unsigned long j, int cpu) +{ +	int rem; +	unsigned long original = j; + +	j += cpu * 3; + +	rem = j % HZ; + +	if (rem < HZ/4) /* round down */ +		j = j - rem; +	else /* round up */ +		j = j - rem + HZ; + +	/* now that we have rounded, subtract the extra skew again */ +	j -= cpu * 3; + +	if (j <= jiffies) /* rounding ate our timeout entirely; */ +		return original; +	return j; +} + +static __inline__ unsigned long __round_jiffies_relative(unsigned long j, int cpu) +{ +	return  __round_jiffies(j + jiffies, cpu) - jiffies; +} + +unsigned long round_jiffies_relative(unsigned long j) +{ +	return __round_jiffies_relative(j, raw_smp_processor_id()); +} +EXPORT_SYMBOL(round_jiffies_relative); +#endif diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index f8933e0c..92dcbc21 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -60,6 +60,13 @@  #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))  #undef DRM_IRQ_ARGS  #define DRM_IRQ_ARGS		int irq, void *arg, struct pt_regs *regs + +typedef _Bool bool; +enum { +        false   = 0, +        true    = 1 +}; +  #endif  #ifndef list_for_each_safe @@ -152,7 +159,7 @@ static __inline__ void *kcalloc(size_t nmemb, size_t size, int flags)  #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)  #define vmalloc_user(_size) ({void * tmp = vmalloc(_size);   \ -      if (tmp) memset(tmp, 0, size);			     \ +      if (tmp) memset(tmp, 0, _size);			     \        (tmp);})  #endif @@ -325,7 +332,7 @@ void *idr_replace(struct idr *idp, void *ptr, int id);  #endif  #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) -typedef _Bool                   bool; +extern unsigned long round_jiffies_relative(unsigned long j);  #endif  #endif diff --git a/linux-core/drm_context.c b/linux-core/drm_context.c index 83ad291e..febee9f7 100644 --- a/linux-core/drm_context.c +++ b/linux-core/drm_context.c @@ -257,12 +257,13 @@ static int drm_context_switch(struct drm_device *dev, int old, int new)   * hardware lock is held, clears the drm_device::context_flag and wakes up   * drm_device::context_wait.   */ -static int drm_context_switch_complete(struct drm_device *dev, int new) +static int drm_context_switch_complete(struct drm_device *dev,  +				       struct drm_file *file_priv, int new)  {  	dev->last_context = new;	/* PRE/POST: This is the _only_ writer. */  	dev->last_switch = jiffies; -	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { +	if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock)) {  		DRM_ERROR("Lock isn't held after context switch\n");  	} @@ -421,7 +422,7 @@ int drm_newctx(struct drm_device *dev, void *data,  	struct drm_ctx *ctx = data;  	DRM_DEBUG("%d\n", ctx->handle); -	drm_context_switch_complete(dev, ctx->handle); +	drm_context_switch_complete(dev, file_priv, ctx->handle);  	return 0;  } diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c new file mode 100644 index 00000000..6b8cb9c7 --- /dev/null +++ b/linux-core/drm_crtc.c @@ -0,0 +1,2437 @@ +/* + * Copyright (c) 2006-2007 Intel Corporation + * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> + * + * DRM core CRTC related functions + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission.  The copyright holders make no representations + * about the suitability of this software for any purpose.  It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + * + * Authors: + *      Keith Packard + *	Eric Anholt <eric@anholt.net> + *      Dave Airlie <airlied@linux.ie> + *      Jesse Barnes <jesse.barnes@intel.com> + */ +#include <linux/list.h> +#include "drm.h" +#include "drmP.h" +#include "drm_crtc.h" + +struct drm_prop_enum_list { +	int type; +	char *name; +}; + +/* + * Global properties + */ +static struct drm_prop_enum_list drm_dpms_enum_list[] = +{ { DPMSModeOn, "On" }, +  { DPMSModeStandby, "Standby" }, +  { DPMSModeSuspend, "Suspend" }, +  { DPMSModeOff, "Off" } +}; +static struct drm_prop_enum_list drm_conn_enum_list[] =  +{ { ConnectorVGA, "VGA" }, +  { ConnectorDVII, "DVI-I" }, +  { ConnectorDVID, "DVI-D" }, +  { ConnectorDVIA, "DVI-A" }, +  { ConnectorComposite, "Composite" }, +  { ConnectorSVIDEO, "SVIDEO" }, +  { ConnectorLVDS, "LVDS" }, +  { ConnectorComponent, "Component" }, +  { Connector9PinDIN, "9-pin DIN" }, +  { ConnectorDisplayPort, "DisplayPort" }, +  { ConnectorHDMIA, "HDMI Type A" }, +  { ConnectorHDMIB, "HDMI Type B" }, +}; +static struct drm_prop_enum_list drm_output_enum_list[] = +{ { DRM_MODE_OUTPUT_NONE, "None" }, +  { DRM_MODE_OUTPUT_DAC, "DAC" }, +  { DRM_MODE_OUTPUT_TMDS, "TMDS" }, +  { DRM_MODE_OUTPUT_LVDS, "LVDS" }, +  { DRM_MODE_OUTPUT_TVDAC, "TV" }, +}; + +char *drm_get_output_name(struct drm_output *output) +{ +	static char buf[32]; + +	snprintf(buf, 32, "%s-%d", drm_output_enum_list[output->output_type].name, +		 output->output_type_id); +	return buf; +} + +/** + * drm_idr_get - allocate a new identifier + * @dev: DRM device + * @ptr: object pointer, used to generate unique ID + * + * LOCKING: + * Caller must hold DRM mode_config lock. + * + * Create a unique identifier based on @ptr in @dev's identifier space.  Used + * for tracking modes, CRTCs and outputs. + * + * RETURNS: + * New unique (relative to other objects in @dev) integer identifier for the + * object. + */ +int drm_idr_get(struct drm_device *dev, void *ptr) +{ +	int new_id = 0; +	int ret; +again: +	if (idr_pre_get(&dev->mode_config.crtc_idr, GFP_KERNEL) == 0) { +		DRM_ERROR("Ran out memory getting a mode number\n"); +		return 0; +	} + +	ret = idr_get_new_above(&dev->mode_config.crtc_idr, ptr, 1, &new_id); +	if (ret == -EAGAIN) +		goto again;	 + +	return new_id; +} + +/** + * drm_idr_put - free an identifer + * @dev: DRM device + * @id: ID to free + * + * LOCKING: + * Caller must hold DRM mode_config lock. + * + * Free @id from @dev's unique identifier pool. + */ +void drm_idr_put(struct drm_device *dev, int id) +{ +	idr_remove(&dev->mode_config.crtc_idr, id); +} + +/** + * drm_crtc_from_fb - find the CRTC structure associated with an fb + * @dev: DRM device + * @fb: framebuffer in question + * + * LOCKING: + * Caller must hold mode_config lock. + * + * Find CRTC in the mode_config structure that matches @fb. + * + * RETURNS: + * Pointer to the CRTC or NULL if it wasn't found. + */ +struct drm_crtc *drm_crtc_from_fb(struct drm_device *dev, +				  struct drm_framebuffer *fb) +{ +	struct drm_crtc *crtc; + +	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { +		if (crtc->fb == fb) +			return crtc; +	} +	return NULL; +} + +/** + * drm_framebuffer_create - create a new framebuffer object + * @dev: DRM device + * + * LOCKING: + * Caller must hold mode config lock. + * + * Creates a new framebuffer objects and adds it to @dev's DRM mode_config. + * + * RETURNS: + * Pointer to new framebuffer or NULL on error. + */ +struct drm_framebuffer *drm_framebuffer_create(struct drm_device *dev) +{ +	struct drm_framebuffer *fb; + +	fb = kzalloc(sizeof(struct drm_framebuffer), GFP_KERNEL); +	if (!fb) +		return NULL; +	 +	fb->id = drm_idr_get(dev, fb); +	fb->dev = dev; +	dev->mode_config.num_fb++; +	list_add(&fb->head, &dev->mode_config.fb_list); + +	return fb; +} +EXPORT_SYMBOL(drm_framebuffer_create); + +/** + * drm_framebuffer_destroy - remove a framebuffer object + * @fb: framebuffer to remove + * + * LOCKING: + * Caller must hold mode config lock. + * + * Scans all the CRTCs in @dev's mode_config.  If they're using @fb, removes + * it, setting it to NULL. + */ +void drm_framebuffer_destroy(struct drm_framebuffer *fb) +{ +	struct drm_device *dev = fb->dev; +	struct drm_crtc *crtc; + +	/* remove from any CRTC */ +	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { +		if (crtc->fb == fb) +			crtc->fb = NULL; +	} + +	drm_idr_put(dev, fb->id); +	list_del(&fb->head); +	dev->mode_config.num_fb--; + +	kfree(fb); +} +EXPORT_SYMBOL(drm_framebuffer_destroy); + +/** + * drm_crtc_create - create a new CRTC object + * @dev: DRM device + * @funcs: callbacks for the new CRTC + * + * LOCKING: + * Caller must hold mode config lock. + * + * Creates a new CRTC object and adds it to @dev's mode_config structure. + * + * RETURNS: + * Pointer to new CRTC object or NULL on error. + */ +struct drm_crtc *drm_crtc_create(struct drm_device *dev, +				 const struct drm_crtc_funcs *funcs) +{ +	struct drm_crtc *crtc; + +	crtc = kzalloc(sizeof(struct drm_crtc), GFP_KERNEL); +	if (!crtc) +		return NULL; + +	crtc->dev = dev; +	crtc->funcs = funcs; + +	crtc->id = drm_idr_get(dev, crtc); + +	list_add_tail(&crtc->head, &dev->mode_config.crtc_list); +	dev->mode_config.num_crtc++; + +	return crtc; +} +EXPORT_SYMBOL(drm_crtc_create); + +/** + * drm_crtc_destroy - remove a CRTC object + * @crtc: CRTC to remove + * + * LOCKING: + * Caller must hold mode config lock. + * + * Cleanup @crtc.  Calls @crtc's cleanup function, then removes @crtc from + * its associated DRM device's mode_config.  Frees it afterwards. + */ +void drm_crtc_destroy(struct drm_crtc *crtc) +{ +	struct drm_device *dev = crtc->dev; + +	if (crtc->funcs->cleanup) +		(*crtc->funcs->cleanup)(crtc); + +	drm_idr_put(dev, crtc->id); +	list_del(&crtc->head); +	dev->mode_config.num_crtc--; +	kfree(crtc); +} +EXPORT_SYMBOL(drm_crtc_destroy); + +/** + * drm_crtc_in_use - check if a given CRTC is in a mode_config + * @crtc: CRTC to check + * + * LOCKING: + * Caller must hold mode config lock. + * + * Walk @crtc's DRM device's mode_config and see if it's in use. + * + * RETURNS: + * True if @crtc is part of the mode_config, false otherwise. + */ +bool drm_crtc_in_use(struct drm_crtc *crtc) +{ +	struct drm_output *output; +	struct drm_device *dev = crtc->dev; +	/* FIXME: Locking around list access? */ +	list_for_each_entry(output, &dev->mode_config.output_list, head) +		if (output->crtc == crtc) +			return true; +	return false; +} +EXPORT_SYMBOL(drm_crtc_in_use); + +/* + * Detailed mode info for a standard 640x480@60Hz monitor + */ +static struct drm_display_mode std_mode[] = { +	{ DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 25200, 640, 656, +		   752, 800, 0, 480, 490, 492, 525, 0, +		   V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */ +}; + +/** + * drm_crtc_probe_output_modes - get complete set of display modes + * @dev: DRM device + * @maxX: max width for modes + * @maxY: max height for modes + * + * LOCKING: + * Caller must hold mode config lock. + * + * Based on @dev's mode_config layout, scan all the outputs and try to detect + * modes on them.  Modes will first be added to the output's probed_modes + * list, then culled (based on validity and the @maxX, @maxY parameters) and + * put into the normal modes list. + * + * Intended to be used either at bootup time or when major configuration + * changes have occurred. + * + * FIXME: take into account monitor limits + */ +void drm_crtc_probe_single_output_modes(struct drm_output *output, int maxX, int maxY) +{ +	struct drm_device *dev = output->dev; +	struct drm_display_mode *mode, *t; +	int ret; +	//if (maxX == 0 || maxY == 0)  +	// TODO + +	/* set all modes to the unverified state */ +	list_for_each_entry_safe(mode, t, &output->modes, head) +		mode->status = MODE_UNVERIFIED; +		 +	output->status = (*output->funcs->detect)(output); +	 +	if (output->status == output_status_disconnected) { +		DRM_DEBUG("%s is disconnected\n", drm_get_output_name(output)); +		/* TODO set EDID to NULL */ +		return; +	} +	 +	ret = (*output->funcs->get_modes)(output); +	 +	if (ret) { +		drm_mode_output_list_update(output); +	} +	 +	if (maxX && maxY) +		drm_mode_validate_size(dev, &output->modes, maxX, +				       maxY, 0); +	list_for_each_entry_safe(mode, t, &output->modes, head) { +		if (mode->status == MODE_OK) +			mode->status = (*output->funcs->mode_valid)(output,mode); +	} +	 +	 +	drm_mode_prune_invalid(dev, &output->modes, TRUE); +	 +	if (list_empty(&output->modes)) { +		struct drm_display_mode *stdmode; +		 +		DRM_DEBUG("No valid modes on %s\n", drm_get_output_name(output)); +		 +		/* Should we do this here ??? +		 * When no valid EDID modes are available we end up +		 * here and bailed in the past, now we add a standard +		 * 640x480@60Hz mode and carry on. +		 */ +		stdmode = drm_mode_duplicate(dev, &std_mode[0]); +		drm_mode_probed_add(output, stdmode); +		drm_mode_list_concat(&output->probed_modes, +				     &output->modes); +		 +		DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n", +			  drm_get_output_name(output)); +	} +	 +	drm_mode_sort(&output->modes); +	 +	DRM_DEBUG("Probed modes for %s\n", drm_get_output_name(output)); +	list_for_each_entry_safe(mode, t, &output->modes, head) { +		mode->vrefresh = drm_mode_vrefresh(mode); +		 +		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); +		drm_mode_debug_printmodeline(dev, mode); +	} +} + +void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) +{ +	struct drm_output *output; + +	list_for_each_entry(output, &dev->mode_config.output_list, head) { +		drm_crtc_probe_single_output_modes(output, maxX, maxY); +	} +} +EXPORT_SYMBOL(drm_crtc_probe_output_modes); + +/** + * drm_crtc_set_mode - set a mode + * @crtc: CRTC to program + * @mode: mode to use + * @x: width of mode + * @y: height of mode + * + * LOCKING: + * Caller must hold mode config lock. + * + * Try to set @mode on @crtc.  Give @crtc and its associated outputs a chance + * to fixup or reject the mode prior to trying to set it. + * + * RETURNS: + * True if the mode was set successfully, or false otherwise. + */ +bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, +		       int x, int y) +{ +	struct drm_device *dev = crtc->dev; +	struct drm_display_mode *adjusted_mode, saved_mode; +	int saved_x, saved_y; +	bool didLock = false; +	bool ret = false; +	struct drm_output *output; + +	adjusted_mode = drm_mode_duplicate(dev, mode); + +	crtc->enabled = drm_crtc_in_use(crtc); + +	if (!crtc->enabled) { +		return true; +	} + +	didLock = crtc->funcs->lock(crtc); + +	saved_mode = crtc->mode; +	saved_x = crtc->x; +	saved_y = crtc->y; +	 +	/* Update crtc values up front so the driver can rely on them for mode +	 * setting. +	 */ +	crtc->mode = *mode; +	crtc->x = x; +	crtc->y = y; + +	/* XXX short-circuit changes to base location only */ +	 +	/* Pass our mode to the outputs and the CRTC to give them a chance to +	 * adjust it according to limitations or output properties, and also +	 * a chance to reject the mode entirely. +	 */ +	list_for_each_entry(output, &dev->mode_config.output_list, head) { +		 +		if (output->crtc != crtc) +			continue; +		 +		if (!output->funcs->mode_fixup(output, mode, adjusted_mode)) { +			goto done; +		} +	} +	 +	if (!crtc->funcs->mode_fixup(crtc, mode, adjusted_mode)) { +		goto done; +	} + +	/* Prepare the outputs and CRTCs before setting the mode. */ +	list_for_each_entry(output, &dev->mode_config.output_list, head) { + +		if (output->crtc != crtc) +			continue; +		 +		/* Disable the output as the first thing we do. */ +		output->funcs->prepare(output); +	} +	 +	crtc->funcs->prepare(crtc); +	 +	/* Set up the DPLL and any output state that needs to adjust or depend +	 * on the DPLL. +	 */ +	crtc->funcs->mode_set(crtc, mode, adjusted_mode, x, y); + +	list_for_each_entry(output, &dev->mode_config.output_list, head) { + +		if (output->crtc != crtc) +			continue; +		 +		DRM_INFO("%s: set mode %s %x\n", drm_get_output_name(output), mode->name, mode->mode_id); + +		output->funcs->mode_set(output, mode, adjusted_mode); +	} +	 +	/* Now, enable the clocks, plane, pipe, and outputs that we set up. */ +	crtc->funcs->commit(crtc); + +	list_for_each_entry(output, &dev->mode_config.output_list, head) { + +		if (output->crtc != crtc) +			continue; +		 +		output->funcs->commit(output); + +#if 0 // TODO def RANDR_12_INTERFACE +		if (output->randr_output) +			RRPostPendingProperties (output->randr_output); +#endif +	} +	 +	/* XXX free adjustedmode */ +	drm_mode_destroy(dev, adjusted_mode); +	ret = TRUE; +	/* TODO */ +//	if (scrn->pScreen) +//		drm_crtc_set_screen_sub_pixel_order(dev); + +done: +	if (!ret) { +		crtc->x = saved_x; +		crtc->y = saved_y; +		crtc->mode = saved_mode; +	} +	 +	if (didLock) +		crtc->funcs->unlock (crtc); +	 +	return ret; +} +EXPORT_SYMBOL(drm_crtc_set_mode); + +/** + * drm_disable_unused_functions - disable unused objects + * @dev: DRM device + * + * LOCKING: + * Caller must hold mode config lock. + * + * If an output or CRTC isn't part of @dev's mode_config, it can be disabled + * by calling its dpms function, which should power it off. + */ +void drm_disable_unused_functions(struct drm_device *dev) +{ +	struct drm_output *output; +	struct drm_crtc *crtc; + +	list_for_each_entry(output, &dev->mode_config.output_list, head) { +		if (!output->crtc) +			(*output->funcs->dpms)(output, DPMSModeOff); +	} + +	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { +		if (!crtc->enabled) +			crtc->funcs->dpms(crtc, DPMSModeOff); +	} +} +EXPORT_SYMBOL(drm_disable_unused_functions); + +/** + * drm_mode_probed_add - add a mode to the specified output's probed mode list + * @output: output the new mode + * @mode: mode data + * + * LOCKING: + * Caller must hold mode config lock. + *  + * Add @mode to @output's mode list for later use. + */ +void drm_mode_probed_add(struct drm_output *output, +			 struct drm_display_mode *mode) +{ +	list_add(&mode->head, &output->probed_modes); +} +EXPORT_SYMBOL(drm_mode_probed_add); + +/** + * drm_mode_remove - remove and free a mode + * @output: output list to modify + * @mode: mode to remove + * + * LOCKING: + * Caller must hold mode config lock. + *  + * Remove @mode from @output's mode list, then free it. + */ +void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode) +{ +	list_del(&mode->head); +	kfree(mode); +} +EXPORT_SYMBOL(drm_mode_remove); + +/** + * drm_output_create - create a new output + * @dev: DRM device + * @funcs: callbacks for this output + * @name: user visible name of the output + * + * LOCKING: + * Caller must hold @dev's mode_config lock. + * + * Creates a new drm_output structure and adds it to @dev's mode_config + * structure. + * + * RETURNS: + * Pointer to the new output or NULL on error. + */ +struct drm_output *drm_output_create(struct drm_device *dev, +				     const struct drm_output_funcs *funcs, +				     int output_type) +{ +	struct drm_output *output = NULL; + +	output = kzalloc(sizeof(struct drm_output), GFP_KERNEL); +	if (!output) +		return NULL; +		 +	output->dev = dev; +	output->funcs = funcs; +	output->id = drm_idr_get(dev, output); +	output->output_type = output_type; +	output->output_type_id = 1; /* TODO */ +	output->subpixel_order = SubPixelUnknown; +	INIT_LIST_HEAD(&output->user_modes); +	INIT_LIST_HEAD(&output->probed_modes); +	INIT_LIST_HEAD(&output->modes); +	/* randr_output? */ +	/* output_set_monitor(output)? */ +	/* check for output_ignored(output)? */ + +	mutex_lock(&dev->mode_config.mutex); +	list_add_tail(&output->head, &dev->mode_config.output_list); +	dev->mode_config.num_output++; + +	drm_output_attach_property(output, dev->mode_config.edid_property, 0); + +	drm_output_attach_property(output, dev->mode_config.dpms_property, 0); + +	mutex_unlock(&dev->mode_config.mutex); + +	return output; + +} +EXPORT_SYMBOL(drm_output_create); + +/** + * drm_output_destroy - remove an output + * @output: output to remove + * + * LOCKING: + * Caller must hold @dev's mode_config lock. + * + * Call @output's cleanup function, then remove the output from the DRM + * mode_config after freeing @output's modes. + */ +void drm_output_destroy(struct drm_output *output) +{ +	struct drm_device *dev = output->dev; +	struct drm_display_mode *mode, *t; + +	if (*output->funcs->cleanup) +		(*output->funcs->cleanup)(output); + +	list_for_each_entry_safe(mode, t, &output->probed_modes, head) +		drm_mode_remove(output, mode); + +	list_for_each_entry_safe(mode, t, &output->modes, head) +		drm_mode_remove(output, mode); + +	list_for_each_entry_safe(mode, t, &output->user_modes, head) +		drm_mode_remove(output, mode); + +	mutex_lock(&dev->mode_config.mutex); +	drm_idr_put(dev, output->id); +	list_del(&output->head); +	mutex_unlock(&dev->mode_config.mutex); +	kfree(output); +} +EXPORT_SYMBOL(drm_output_destroy); + + +/** + * drm_mode_create - create a new display mode + * @dev: DRM device + * + * LOCKING: + * None. + * + * Create a new drm_display_mode, give it an ID, and return it. + * + * RETURNS: + * Pointer to new mode on success, NULL on error. + */ +struct drm_display_mode *drm_mode_create(struct drm_device *dev) +{ +	struct drm_display_mode *nmode; + +	nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL); +	if (!nmode) +		return NULL; + +	nmode->mode_id = drm_idr_get(dev, nmode); +	return nmode; +} +EXPORT_SYMBOL(drm_mode_create); + +/** + * drm_mode_destroy - remove a mode + * @dev: DRM device + * @mode: mode to remove + * + * LOCKING: + * Caller must hold mode config lock. + * + * Free @mode's unique identifier, then free it. + */ +void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) +{ +	drm_idr_put(dev, mode->mode_id); + +	kfree(mode); +} +EXPORT_SYMBOL(drm_mode_destroy); + +static int drm_mode_create_standard_output_properties(struct drm_device *dev) +{ +	int i; + +	/* +	 * Standard properties (apply to all outputs) +	 */ +	dev->mode_config.edid_property = +		drm_property_create(dev, DRM_MODE_PROP_BLOB | DRM_MODE_PROP_IMMUTABLE, +				    "EDID", 0); + +	dev->mode_config.dpms_property = +		drm_property_create(dev, DRM_MODE_PROP_ENUM, "DPMS", 4); + +	for (i = 0; i < ARRAY_SIZE(drm_dpms_enum_list); i++) +		drm_property_add_enum(dev->mode_config.dpms_property, i, drm_dpms_enum_list[i].type, drm_dpms_enum_list[i].name); + +	dev->mode_config.connector_type_property = +		drm_property_create(dev, DRM_MODE_PROP_ENUM | DRM_MODE_PROP_IMMUTABLE, +				    "Connector Type", 10); +	for (i = 0; i < ARRAY_SIZE(drm_conn_enum_list); i++) +		drm_property_add_enum(dev->mode_config.connector_type_property, i, drm_conn_enum_list[i].type, drm_conn_enum_list[i].name); + +	dev->mode_config.connector_num_property = +		drm_property_create(dev, DRM_MODE_PROP_RANGE | DRM_MODE_PROP_IMMUTABLE, +				    "Connector ID", 2); +	dev->mode_config.connector_num_property->values[0] = 0; +	dev->mode_config.connector_num_property->values[1] = 20; + +	/* +	 * TV specific properties +	 */ +	dev->mode_config.tv_left_margin_property = +		drm_property_create(dev, DRM_MODE_PROP_RANGE | +				    DRM_MODE_PROP_IMMUTABLE, +				    "left margin", 2); +	dev->mode_config.tv_left_margin_property->values[0] = 0; +	dev->mode_config.tv_left_margin_property->values[1] = 100; + +	dev->mode_config.tv_right_margin_property = +		drm_property_create(dev, DRM_MODE_PROP_RANGE | +				    DRM_MODE_PROP_IMMUTABLE, +				    "right margin", 2); +	dev->mode_config.tv_right_margin_property->values[0] = 0; +	dev->mode_config.tv_right_margin_property->values[1] = 100; + +	dev->mode_config.tv_top_margin_property = +		drm_property_create(dev, DRM_MODE_PROP_RANGE | +				    DRM_MODE_PROP_IMMUTABLE, +				    "top margin", 2); +	dev->mode_config.tv_top_margin_property->values[0] = 0; +	dev->mode_config.tv_top_margin_property->values[1] = 100; + +	dev->mode_config.tv_bottom_margin_property = +		drm_property_create(dev, DRM_MODE_PROP_RANGE | +				    DRM_MODE_PROP_IMMUTABLE, +				    "bottom margin", 2); +	dev->mode_config.tv_bottom_margin_property->values[0] = 0; +	dev->mode_config.tv_bottom_margin_property->values[1] = 100; + + +	return 0; +} + +/** + * drm_mode_config_init - initialize DRM mode_configuration structure + * @dev: DRM device + * + * LOCKING: + * None, should happen single threaded at init time. + * + * Initialize @dev's mode_config structure, used for tracking the graphics + * configuration of @dev. + */ +void drm_mode_config_init(struct drm_device *dev) +{ +	mutex_init(&dev->mode_config.mutex); +	INIT_LIST_HEAD(&dev->mode_config.fb_list); +	INIT_LIST_HEAD(&dev->mode_config.crtc_list); +	INIT_LIST_HEAD(&dev->mode_config.output_list); +	INIT_LIST_HEAD(&dev->mode_config.property_list); +	INIT_LIST_HEAD(&dev->mode_config.property_blob_list); +	idr_init(&dev->mode_config.crtc_idr); + +	drm_mode_create_standard_output_properties(dev); + +	/* Just to be sure */ +	dev->mode_config.num_fb = 0; +	dev->mode_config.num_output = 0; +	dev->mode_config.num_crtc = 0; +	dev->mode_config.hotplug_counter = 0; +} +EXPORT_SYMBOL(drm_mode_config_init); + +/** + * drm_get_buffer_object - find the buffer object for a given handle + * @dev: DRM device + * @bo: pointer to caller's buffer_object pointer + * @handle: handle to lookup + * + * LOCKING: + * Must take @dev's struct_mutex to protect buffer object lookup. + * + * Given @handle, lookup the buffer object in @dev and put it in the caller's + * @bo pointer. + * + * RETURNS: + * Zero on success, -EINVAL if the handle couldn't be found. + */ +static int drm_get_buffer_object(struct drm_device *dev, struct drm_buffer_object **bo, unsigned long handle) +{ +	struct drm_user_object *uo; +	struct drm_hash_item *hash; +	int ret; + +	*bo = NULL; + +	mutex_lock(&dev->struct_mutex); +	ret = drm_ht_find_item(&dev->object_hash, handle, &hash); +	if (ret) { +		DRM_ERROR("Couldn't find handle.\n"); +		ret = -EINVAL; +		goto out_err; +	} + +	uo = drm_hash_entry(hash, struct drm_user_object, hash); +	if (uo->type != drm_buffer_type) { +		ret = -EINVAL; +		goto out_err; +	} +	 +	*bo = drm_user_object_entry(uo, struct drm_buffer_object, base); +	ret = 0; +out_err: +	mutex_unlock(&dev->struct_mutex); +	return ret; +} + +/** + * drm_pick_crtcs - pick crtcs for output devices + * @dev: DRM device + * + * LOCKING: + * Caller must hold mode config lock. + */ +static void drm_pick_crtcs (struct drm_device *dev) +{ +	int c, o, assigned; +	struct drm_output *output, *output_equal; +	struct drm_crtc   *crtc; +	struct drm_display_mode *des_mode = NULL, *modes, *modes_equal; + +	list_for_each_entry(output, &dev->mode_config.output_list, head) { +       		output->crtc = NULL; +     +    		/* Don't hook up outputs that are disconnected ?? +		 * +		 * This is debateable. Do we want fixed /dev/fbX or +		 * dynamic on hotplug (need mode code for that though) ? +		 * +		 * If we don't hook up outputs now, then we only create +		 * /dev/fbX for the output that's enabled, that's good as +		 * the users console will be on that output. +		 * +		 * If we do hook up outputs that are disconnected now, then +		 * the user may end up having to muck about with the fbcon +		 * map flags to assign his console to the enabled output. Ugh. +		 */ +    		if (output->status != output_status_connected) +			continue; + +		des_mode = NULL; +		list_for_each_entry(des_mode, &output->modes, head) { +			if (des_mode->type & DRM_MODE_TYPE_PREFERRED) +				break; +		} + +		/* No preferred mode, let's just select the first available */ +		if (!des_mode || !(des_mode->type & DRM_MODE_TYPE_PREFERRED)) { +			list_for_each_entry(des_mode, &output->modes, head) { +				if (des_mode) +					break; +			} +		} + +		c = -1; +		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { +			assigned = 0; + +			c++; +			if ((output->possible_crtcs & (1 << c)) == 0) +		    		continue; +	 +			list_for_each_entry(output_equal, &dev->mode_config.output_list, head) { +				if (output->id == output_equal->id) +					continue; + +				/* Find out if crtc has been assigned before */ +				if (output_equal->crtc == crtc) +					assigned = 1; +			} + +#if 1 /* continue for now */ +			if (assigned) +				continue; +#endif + +			o = -1; +			list_for_each_entry(output_equal, &dev->mode_config.output_list, head) { +				o++; +				if (output->id == output_equal->id) +					continue; + +				list_for_each_entry(modes, &output->modes, head) { +					list_for_each_entry(modes_equal, &output_equal->modes, head) { +						if (drm_mode_equal (modes, modes_equal)) { +							if ((output->possible_clones & output_equal->possible_clones) && (output_equal->crtc == crtc)) { +								printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_output_name(output),output->possible_clones,drm_get_output_name(output_equal),output_equal->possible_clones); +								assigned = 0; +								goto clone; +							} +						} +					} +				} +			} + +clone: +			/* crtc has been assigned skip it */ +			if (assigned) +				continue; + +			/* Found a CRTC to attach to, do it ! */ +			output->crtc = crtc; +			output->crtc->desired_mode = des_mode; +			output->initial_x = 0; +			output->initial_y = 0; +			DRM_DEBUG("Desired mode for CRTC %d is 0x%x:%s\n",c,des_mode->mode_id, des_mode->name); +			break; +    		} +	} +} +EXPORT_SYMBOL(drm_pick_crtcs); + +/** + * drm_initial_config - setup a sane initial output configuration + * @dev: DRM device + * @can_grow: this configuration is growable + * + * LOCKING: + * Called at init time, must take mode config lock. + * + * Scan the CRTCs and outputs and try to put together an initial setup. + * At the moment, this is a cloned configuration across all heads with + * a new framebuffer object as the backing store. + * + * RETURNS: + * Zero if everything went ok, nonzero otherwise. + */ +bool drm_initial_config(struct drm_device *dev, bool can_grow) +{ +	struct drm_output *output; +	struct drm_crtc *crtc; +	int ret = false; + +	mutex_lock(&dev->mode_config.mutex); + +	drm_crtc_probe_output_modes(dev, 2048, 2048); + +	drm_pick_crtcs(dev); + +	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + +		/* can't setup the crtc if there's no assigned mode */ +		if (!crtc->desired_mode) +			continue; + +		/* Now setup the fbdev for attached crtcs */ +		dev->driver->fb_probe(dev, crtc); +	} + +	/* This is a little screwy, as we've already walked the outputs  +	 * above, but it's a little bit of magic too. There's the potential +	 * for things not to get setup above if an existing device gets +	 * re-assigned thus confusing the hardware. By walking the outputs +	 * this fixes up their crtc's. +	 */ +	list_for_each_entry(output, &dev->mode_config.output_list, head) { + +		/* can't setup the output if there's no assigned mode */ +		if (!output->crtc || !output->crtc->desired_mode) +			continue; + +		/* and needs an attached fb */ +		if (output->crtc->fb) +			drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0); +	} + +	drm_disable_unused_functions(dev); + +	mutex_unlock(&dev->mode_config.mutex); +	return ret; +} +EXPORT_SYMBOL(drm_initial_config); + +/** + * drm_mode_config_cleanup - free up DRM mode_config info + * @dev: DRM device + * + * LOCKING: + * Caller must hold mode config lock. + * + * Free up all the outputs and CRTCs associated with this DRM device, then + * free up the framebuffers and associated buffer objects. + * + * FIXME: cleanup any dangling user buffer objects too + */ +void drm_mode_config_cleanup(struct drm_device *dev) +{ +	struct drm_output *output, *ot; +	struct drm_crtc *crtc, *ct; +	struct drm_framebuffer *fb, *fbt; +	struct drm_property *property, *pt; + +	list_for_each_entry_safe(output, ot, &dev->mode_config.output_list, head) { +		drm_output_destroy(output); +	} + +	list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, head) { +		drm_property_destroy(dev, property); +	} + +	list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { +		/* there should only be bo of kernel type left */ +		if (fb->bo->type != drm_bo_type_kernel) +			drm_framebuffer_destroy(fb); +		else +			dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb)); +	} + +	list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { +		drm_crtc_destroy(crtc); +	} + +} +EXPORT_SYMBOL(drm_mode_config_cleanup); + +/** + * drm_crtc_set_config - set a new config from userspace + * @crtc: CRTC to setup + * @crtc_info: user provided configuration + * @new_mode: new mode to set + * @output_set: set of outputs for the new config + * @fb: new framebuffer + * + * LOCKING: + * Caller must hold mode config lock. + * + * Setup a new configuration, provided by the user in @crtc_info, and enable + * it. + * + * RETURNS: + * Zero. (FIXME) + */ +int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, struct drm_display_mode *new_mode, struct drm_output **output_set, struct drm_framebuffer *fb) +{ +	struct drm_device *dev = crtc->dev; +	struct drm_crtc **save_crtcs, *new_crtc; +	bool save_enabled = crtc->enabled; +	bool changed = false; +	bool flip_or_move = false; +	struct drm_output *output; +	int count = 0, ro; + +	save_crtcs = kzalloc(dev->mode_config.num_crtc * sizeof(struct drm_crtc *), GFP_KERNEL); +	if (!save_crtcs) +		return -ENOMEM; + +	/* We should be able to check here if the fb has the same properties +	 * and then just flip_or_move it */ +	if (crtc->fb != fb) +		changed = true; + +	if (crtc_info->x != crtc->x || crtc_info->y != crtc->y) +		flip_or_move = true; + +	if (new_mode && !drm_mode_equal(new_mode, &crtc->mode)) +		changed = true; + +	list_for_each_entry(output, &dev->mode_config.output_list, head) { +		save_crtcs[count++] = output->crtc; + +		if (output->crtc == crtc) +			new_crtc = NULL; +		else +			new_crtc = output->crtc; + +		for (ro = 0; ro < crtc_info->count_outputs; ro++) { +			if (output_set[ro] == output) +				new_crtc = crtc; +		} +		if (new_crtc != output->crtc) { +			changed = true; +			output->crtc = new_crtc; +		} +	} + +	/* mode_set_base is not a required function */ +	if (flip_or_move && !crtc->funcs->mode_set_base) +		changed = true; + +	if (changed) { +		crtc->fb = fb; +		crtc->enabled = (new_mode != NULL); +		if (new_mode != NULL) { +			DRM_DEBUG("attempting to set mode from userspace\n"); +			drm_mode_debug_printmodeline(dev, new_mode); +			if (!drm_crtc_set_mode(crtc, new_mode, crtc_info->x, +					       crtc_info->y)) { +				crtc->enabled = save_enabled; +				count = 0; +				list_for_each_entry(output, &dev->mode_config.output_list, head) +					output->crtc = save_crtcs[count++]; +				kfree(save_crtcs); +				return -EINVAL; +			} +			crtc->desired_x = crtc_info->x; +			crtc->desired_y = crtc_info->y; +			crtc->desired_mode = new_mode; +		} +		drm_disable_unused_functions(dev); +	} else if (flip_or_move) { +		crtc->funcs->mode_set_base(crtc, crtc_info->x, crtc_info->y); +	} + +	kfree(save_crtcs); +	return 0; +} + +/** + * drm_hotplug_stage_two + * @dev DRM device + * @output hotpluged output + * + * LOCKING. + * Caller must hold mode config lock, function might grap struct lock. + * + * Stage two of a hotplug. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, +			  bool connected) +{ +	int has_config = 0; + +	/* We might want to do something more here */ +	if (!connected) { +		DRM_DEBUG("not connected\n"); +		dev->mode_config.hotplug_counter++; +		return 0; +	} + +	if (output->crtc && output->crtc->desired_mode) { +		DRM_DEBUG("drm thinks that the output already has a config\n"); +		has_config = 1; +	} + +	drm_crtc_probe_output_modes(dev, 2048, 2048); + +	if (!has_config) +		drm_pick_crtcs(dev); + +	if (!output->crtc || !output->crtc->desired_mode) { +		DRM_DEBUG("could not find a desired mode or crtc for output\n"); +		goto out_err; +	} + +	/* We should realy check if there is a fb using this crtc */ +	if (!has_config) +		dev->driver->fb_probe(dev, output->crtc); +	else { +		dev->driver->fb_resize(dev, output->crtc); + +		if (!drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0)) +			DRM_ERROR("failed to set mode after hotplug\n"); +	} + +	drm_disable_unused_functions(dev); + +	dev->mode_config.hotplug_counter++; +	return 0; + +out_err: +	dev->mode_config.hotplug_counter++; +	return 1; +} +EXPORT_SYMBOL(drm_hotplug_stage_two); + +int drm_mode_hotplug_ioctl(struct drm_device *dev, +			   void *data, struct drm_file *file_priv) +{ +	struct drm_mode_hotplug *arg = data; + +	arg->counter = dev->mode_config.hotplug_counter; + +	return 0; +} + +/** + * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo + * @out: drm_mode_modeinfo struct to return to the user + * @in: drm_display_mode to use + * + * LOCKING: + * None. + * + * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to + * the user. + */ +void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, struct drm_display_mode *in) +{ +	out->clock = in->clock; +	out->hdisplay = in->hdisplay; +	out->hsync_start = in->hsync_start; +	out->hsync_end = in->hsync_end; +	out->htotal = in->htotal; +	out->hskew = in->hskew; +	out->vdisplay = in->vdisplay; +	out->vsync_start = in->vsync_start; +	out->vsync_end = in->vsync_end; +	out->vtotal = in->vtotal; +	out->vscan = in->vscan; +	out->vrefresh = in->vrefresh; +	out->flags = in->flags; +	out->type = in->type; +	strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); +	out->name[DRM_DISPLAY_MODE_LEN-1] = 0; +} + +/** + * drm_crtc_convert_to_umode - convert a modeinfo into a drm_display_mode + * @out: drm_display_mode to return to the user + * @in: drm_mode_modeinfo to use + * + * LOCKING: + * None. + * + * Convert a drmo_mode_modeinfo into a drm_display_mode structure to return to + * the caller. + */ +void drm_crtc_convert_umode(struct drm_display_mode *out, struct drm_mode_modeinfo *in) +{ +	out->clock = in->clock; +	out->hdisplay = in->hdisplay; +	out->hsync_start = in->hsync_start; +	out->hsync_end = in->hsync_end; +	out->htotal = in->htotal; +	out->hskew = in->hskew; +	out->vdisplay = in->vdisplay; +	out->vsync_start = in->vsync_start; +	out->vsync_end = in->vsync_end; +	out->vtotal = in->vtotal; +	out->vscan = in->vscan; +	out->vrefresh = in->vrefresh; +	out->flags = in->flags; +	out->type = in->type; +	strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); +	out->name[DRM_DISPLAY_MODE_LEN-1] = 0; +} +	 +/** + * drm_mode_getresources - get graphics configuration + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * LOCKING: + * Takes mode config lock. + * + * Construct a set of configuration description structures and return + * them to the user, including CRTC, output and framebuffer configuration. + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_mode_getresources(struct drm_device *dev, +			  void *data, struct drm_file *file_priv) +{ +	struct drm_mode_card_res *card_res = data; +	struct list_head *lh; +	struct drm_framebuffer *fb; +	struct drm_output *output; +	struct drm_crtc *crtc; +	int ret = 0; +	int output_count = 0; +	int crtc_count = 0; +	int fb_count = 0; +	int copied = 0; +	uint32_t __user *fb_id; +	uint32_t __user *crtc_id; +	uint32_t __user *output_id; + +	mutex_lock(&dev->mode_config.mutex); + +	list_for_each(lh, &dev->mode_config.fb_list) +		fb_count++; + +	list_for_each(lh, &dev->mode_config.crtc_list) +		crtc_count++; + +	list_for_each(lh, &dev->mode_config.output_list) +		output_count++; + +	card_res->max_height = dev->mode_config.max_height; +	card_res->min_height = dev->mode_config.min_height; +	card_res->max_width = dev->mode_config.max_width; +	card_res->min_width = dev->mode_config.min_width; + +	/* handle this in 4 parts */ +	/* FBs */ +	if (card_res->count_fbs >= fb_count) { +		copied = 0; +		fb_id = (uint32_t *)(unsigned long)card_res->fb_id_ptr; +		list_for_each_entry(fb, &dev->mode_config.fb_list, head) { +			if (put_user(fb->id, fb_id + copied)) { +				ret = -EFAULT; +				goto out; +			} +			copied++; +		} +	} +	card_res->count_fbs = fb_count; + +	/* CRTCs */ +	if (card_res->count_crtcs >= crtc_count) { +		copied = 0; +		crtc_id = (uint32_t *)(unsigned long)card_res->crtc_id_ptr; +		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head){ +			DRM_DEBUG("CRTC ID is %d\n", crtc->id); +			if (put_user(crtc->id, crtc_id + copied)) { +				ret = -EFAULT; +				goto out; +			} +			copied++; +		} +	} +	card_res->count_crtcs = crtc_count; + + +	/* Outputs */ +	if (card_res->count_outputs >= output_count) { +		copied = 0; +		output_id = (uint32_t *)(unsigned long)card_res->output_id_ptr; +		list_for_each_entry(output, &dev->mode_config.output_list, +				    head) { + 			DRM_DEBUG("OUTPUT ID is %d\n", output->id); +			if (put_user(output->id, output_id + copied)) { +				ret = -EFAULT; +				goto out; +			} +			copied++; +		} +	} +	card_res->count_outputs = output_count; +	 +	DRM_DEBUG("Counted %d %d\n", card_res->count_crtcs, +		  card_res->count_outputs); + +out:	 +	mutex_unlock(&dev->mode_config.mutex); +	return ret; +} + +/** + * drm_mode_getcrtc - get CRTC configuration + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * LOCKING: + * Caller? (FIXME) + * + * Construct a CRTC configuration structure to return to the user. + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_mode_getcrtc(struct drm_device *dev, +		     void *data, struct drm_file *file_priv) +{ +	struct drm_mode_crtc *crtc_resp = data; +	struct drm_crtc *crtc; +	struct drm_output *output; +	int ocount; +	int ret = 0; + +	mutex_lock(&dev->mode_config.mutex); +	crtc = idr_find(&dev->mode_config.crtc_idr, crtc_resp->crtc_id); +	if (!crtc || (crtc->id != crtc_resp->crtc_id)) { +		ret = -EINVAL; +		goto out; +	} + +	crtc_resp->x = crtc->x; +	crtc_resp->y = crtc->y; + +	if (crtc->fb) +		crtc_resp->fb_id = crtc->fb->id; +	else +		crtc_resp->fb_id = 0; + +	crtc_resp->outputs = 0; +	if (crtc->enabled) { + +		drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode); +		crtc_resp->mode_valid = 1; +		ocount = 0; +		list_for_each_entry(output, &dev->mode_config.output_list, head) { +			if (output->crtc == crtc) +				crtc_resp->outputs |= 1 << (ocount++); +		} +		 +	} else { +		crtc_resp->mode_valid = 0; +	} + +out: +	mutex_unlock(&dev->mode_config.mutex); +	return ret; +} + +/** + * drm_mode_getoutput - get output configuration + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * LOCKING: + * Caller? (FIXME) + * + * Construct a output configuration structure to return to the user. + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_mode_getoutput(struct drm_device *dev, +		       void *data, struct drm_file *file_priv) +{ +	struct drm_mode_get_output *out_resp = data; +	struct drm_output *output; +	struct drm_display_mode *mode; +	int mode_count = 0; +	int props_count = 0; +	int ret = 0; +	int copied = 0; +	int i; +	struct drm_mode_modeinfo u_mode; +	struct drm_mode_modeinfo __user *mode_ptr; +	uint32_t __user *prop_ptr; +	uint64_t __user *prop_values; + +	memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); + +	DRM_DEBUG("output id %d:\n", out_resp->output); + +	mutex_lock(&dev->mode_config.mutex); +	output= idr_find(&dev->mode_config.crtc_idr, out_resp->output); +	if (!output || (output->id != out_resp->output)) { +		ret = -EINVAL; +		goto out; +	} + +	list_for_each_entry(mode, &output->modes, head) +		mode_count++; +	 +	for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { +		if (output->property_ids[i] != 0) { +			props_count++; +		} +	} + +	if (out_resp->count_modes == 0) { +		drm_crtc_probe_single_output_modes(output, dev->mode_config.max_width, dev->mode_config.max_height); +	} + +	out_resp->output_type = output->output_type; +	out_resp->output_type_id = output->output_type_id; +	out_resp->mm_width = output->mm_width; +	out_resp->mm_height = output->mm_height; +	out_resp->subpixel = output->subpixel_order; +	out_resp->connection = output->status; +	if (output->crtc) +		out_resp->crtc = output->crtc->id; +	else +		out_resp->crtc = 0; + +	out_resp->crtcs = output->possible_crtcs; +	out_resp->clones = output->possible_clones; + +	if ((out_resp->count_modes >= mode_count) && mode_count) { +		copied = 0; +		mode_ptr = (struct drm_mode_modeinfo *)(unsigned long)out_resp->modes_ptr; +		list_for_each_entry(mode, &output->modes, head) { +			drm_crtc_convert_to_umode(&u_mode, mode); +			if (copy_to_user(mode_ptr + copied, +					 &u_mode, sizeof(u_mode))) { +				ret = -EFAULT; +				goto out; +			} +			copied++; +			 +		} +	} +	out_resp->count_modes = mode_count; + +	if ((out_resp->count_props >= props_count) && props_count) { +		copied = 0; +		prop_ptr = (uint32_t *)(unsigned long)(out_resp->props_ptr); +		prop_values = (uint64_t *)(unsigned long)(out_resp->prop_values_ptr); +		for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { +			if (output->property_ids[i] != 0) { +				if (put_user(output->property_ids[i], prop_ptr + copied)) { +					ret = -EFAULT; +					goto out; +				} + +				if (put_user(output->property_values[i], prop_values + copied)) { +					ret = -EFAULT; +					goto out; +				} +				copied++; +			} +		} +	} +	out_resp->count_props = props_count; + +out: +	mutex_unlock(&dev->mode_config.mutex); +	return ret; +} + +/** + * drm_mode_setcrtc - set CRTC configuration + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * LOCKING: + * Caller? (FIXME) + * + * Build a new CRTC configuration based on user request. + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_mode_setcrtc(struct drm_device *dev, +		     void *data, struct drm_file *file_priv) +{ +	struct drm_mode_crtc *crtc_req = data; +	struct drm_crtc *crtc; +	struct drm_output **output_set = NULL, *output; +	struct drm_framebuffer *fb = NULL; +	struct drm_display_mode *mode = NULL; +	int ret = 0; +	int i; +	uint32_t __user *set_outputs_ptr; + +	mutex_lock(&dev->mode_config.mutex); +	crtc = idr_find(&dev->mode_config.crtc_idr, crtc_req->crtc_id); +	if (!crtc || (crtc->id != crtc_req->crtc_id)) { +		DRM_DEBUG("Unknown CRTC ID %d\n", crtc_req->crtc_id); +		ret = -EINVAL; +		goto out; +	} + +	if (crtc_req->mode_valid) { +		/* if we have a mode we need a framebuffer */ +		if (crtc_req->fb_id) { +			fb = idr_find(&dev->mode_config.crtc_idr, crtc_req->fb_id); +			if (!fb || (fb->id != crtc_req->fb_id)) { +				DRM_DEBUG("Unknown FB ID%d\n", crtc_req->fb_id); +				ret = -EINVAL; +				goto out; +			} +		} + +		mode = drm_mode_create(dev); +		drm_crtc_convert_umode(mode, &crtc_req->mode); +		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); +	} + +	if (crtc_req->count_outputs == 0 && mode) { +		DRM_DEBUG("Count outputs is 0 but mode set\n"); +		ret = -EINVAL; +		goto out; +	} + +	if (crtc_req->count_outputs > 0 && !mode && !fb) { +		DRM_DEBUG("Count outputs is %d but no mode or fb set\n", crtc_req->count_outputs); +		ret = -EINVAL; +		goto out; +	} + +	if (crtc_req->count_outputs > 0) { +		u32 out_id; +		/* Maybe we should check that count_outputs is a sensible value. */ +		output_set = kmalloc(crtc_req->count_outputs * +				     sizeof(struct drm_output *), GFP_KERNEL); +		if (!output_set) { +			ret = -ENOMEM; +			goto out; +		} + +		for (i = 0; i < crtc_req->count_outputs; i++) { +			set_outputs_ptr = (uint32_t *)(unsigned long)crtc_req->set_outputs_ptr; +			if (get_user(out_id, &set_outputs_ptr[i])) { +				ret = -EFAULT; +				goto out; +			} + +			output = idr_find(&dev->mode_config.crtc_idr, out_id); +			if (!output || (out_id != output->id)) { +				DRM_DEBUG("Output id %d unknown\n", out_id); +				ret = -EINVAL; +				goto out; +			} + +			output_set[i] = output; +		} +	} + +	/* What happens to output_set, leak? */ +	ret = drm_crtc_set_config(crtc, crtc_req, mode, output_set, fb); + +out: +	mutex_unlock(&dev->mode_config.mutex); +	return ret; +} + +int drm_mode_cursor_ioctl(struct drm_device *dev, +			void *data, struct drm_file *file_priv) +{ +	struct drm_mode_cursor *req = data; +	struct drm_crtc *crtc; +	struct drm_buffer_object *bo = NULL; /* must be set */ +	int ret = 0; + +	DRM_DEBUG("\n"); + +	if (!req->flags) { +		DRM_ERROR("no operation set\n"); +		return -EINVAL; +	} + +	mutex_lock(&dev->mode_config.mutex); +	crtc = idr_find(&dev->mode_config.crtc_idr, req->crtc); +	if (!crtc || (crtc->id != req->crtc)) { +		DRM_DEBUG("Unknown CRTC ID %d\n", req->crtc); +		ret = -EINVAL; +		goto out; +	} + +	if (req->flags & DRM_MODE_CURSOR_BO) { +		/* Turn of the cursor if handle is 0 */ +		if (req->handle) +			ret = drm_get_buffer_object(dev, &bo, req->handle); + +		if (ret) { +			DRM_ERROR("invalid buffer id\n"); +			ret = -EINVAL; +			goto out; +		} + +		if (crtc->funcs->cursor_set) { +			ret = crtc->funcs->cursor_set(crtc, bo, req->width, req->height); +		} else { +			DRM_ERROR("crtc does not support cursor\n"); +			ret = -EFAULT; +			goto out; +		} +	} + +	if (req->flags & DRM_MODE_CURSOR_MOVE) { +		if (crtc->funcs->cursor_move) { +			ret = crtc->funcs->cursor_move(crtc, req->x, req->y); +		} else { +			DRM_ERROR("crtc does not support cursor\n"); +			ret = -EFAULT; +			goto out; +		} +	} +out: +	mutex_unlock(&dev->mode_config.mutex); +	return ret; +} + +/** + * drm_mode_addfb - add an FB to the graphics configuration + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * LOCKING: + * Takes mode config lock. + * + * Add a new FB to the specified CRTC, given a user request. + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_mode_addfb(struct drm_device *dev, +		   void *data, struct drm_file *file_priv) +{ +	struct drm_mode_fb_cmd *r = data; +	struct drm_mode_config *config = &dev->mode_config; +	struct drm_framebuffer *fb; +	struct drm_buffer_object *bo; +	int ret = 0; + +	if ((config->min_width > r->width) || (r->width > config->max_width)) { +		DRM_ERROR("mode new framebuffer width not within limits\n"); +		return -EINVAL; +	} +	if ((config->min_height > r->height) || (r->height > config->max_height)) { +		DRM_ERROR("mode new framebuffer height not within limits\n"); +		return -EINVAL; +	} + +	mutex_lock(&dev->mode_config.mutex); +	/* TODO check limits are okay */ +	ret = drm_get_buffer_object(dev, &bo, r->handle); +	if (ret || !bo) { +		DRM_ERROR("BO handle not valid\n"); +		ret = -EINVAL; +		goto out; +	} + +	/* TODO check buffer is sufficently large */ +	/* TODO setup destructor callback */ + +	fb = drm_framebuffer_create(dev); +	if (!fb) { +		DRM_ERROR("could not create framebuffer\n"); +		ret = -EINVAL; +		goto out; +	} + +	fb->width = r->width; +	fb->height = r->height; +	fb->pitch = r->pitch; +	fb->bits_per_pixel = r->bpp; +	fb->depth = r->depth; +	fb->offset = bo->offset; +	fb->bo = bo; + +	r->buffer_id = fb->id; + +	list_add(&fb->filp_head, &file_priv->fbs); + +out: +	mutex_unlock(&dev->mode_config.mutex); +	return ret; +} + +/** + * drm_mode_rmfb - remove an FB from the configuration + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * LOCKING: + * Takes mode config lock. + * + * Remove the FB specified by the user. + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_mode_rmfb(struct drm_device *dev, +		   void *data, struct drm_file *file_priv) +{ +	struct drm_framebuffer *fb = 0; +	struct drm_framebuffer *fbl = 0; +	uint32_t *id = data; +	int ret = 0; +	int found = 0; + +	mutex_lock(&dev->mode_config.mutex); +	fb = idr_find(&dev->mode_config.crtc_idr, *id); +	/* TODO check that we realy get a framebuffer back. */ +	if (!fb || (*id != fb->id)) { +		DRM_ERROR("mode invalid framebuffer id\n"); +		ret = -EINVAL; +		goto out; +	} + +	list_for_each_entry(fbl, &file_priv->fbs, filp_head) +		if (fb == fbl) +			found = 1; + +	if (!found) { +		DRM_ERROR("tried to remove a fb that we didn't own\n"); +		ret = -EINVAL; +		goto out; +	} + +	/* TODO release all crtc connected to the framebuffer */ +	/* TODO unhock the destructor from the buffer object */ + +	if (fb->bo->type == drm_bo_type_kernel) +		DRM_ERROR("the bo type should not be of kernel type\n"); + +	list_del(&fb->filp_head); +	drm_framebuffer_destroy(fb); + +out: +	mutex_unlock(&dev->mode_config.mutex); +	return ret; +} + +/** + * drm_mode_getfb - get FB info + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * LOCKING: + * Caller? (FIXME) + * + * Lookup the FB given its ID and return info about it. + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_mode_getfb(struct drm_device *dev, +		   void *data, struct drm_file *file_priv) +{ +	struct drm_mode_fb_cmd *r = data; +	struct drm_framebuffer *fb; +	int ret = 0; + +	mutex_lock(&dev->mode_config.mutex); +	fb = idr_find(&dev->mode_config.crtc_idr, r->buffer_id); +	if (!fb || (r->buffer_id != fb->id)) { +		DRM_ERROR("invalid framebuffer id\n"); +		ret = -EINVAL; +		goto out; +	} + +	r->height = fb->height; +	r->width = fb->width; +	r->depth = fb->depth; +	r->bpp = fb->bits_per_pixel; +	r->handle = fb->bo->base.hash.key; +	r->pitch = fb->pitch; + +out: +	mutex_unlock(&dev->mode_config.mutex); +	return ret; +} + +/** + * drm_fb_release - remove and free the FBs on this file + * @filp: file * from the ioctl + * + * LOCKING: + * Takes mode config lock. + * + * Destroy all the FBs associated with @filp. + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ +void drm_fb_release(struct file *filp) +{ +	struct drm_file *priv = filp->private_data; +	struct drm_device *dev = priv->minor->dev; +	struct drm_framebuffer *fb, *tfb; + +	mutex_lock(&dev->mode_config.mutex); +	list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { +		list_del(&fb->filp_head); +		if (fb->bo->type == drm_bo_type_kernel) +			DRM_ERROR("the bo type should not be of kernel_type, the kernel will probably explode, why Dave\n"); + +		drm_framebuffer_destroy(fb); +	} +	mutex_unlock(&dev->mode_config.mutex); +} + +/* + * + */ + +static int drm_mode_attachmode(struct drm_device *dev, +			       struct drm_output *output, +			       struct drm_display_mode *mode) +{ +	int ret = 0; + +	list_add_tail(&mode->head, &output->user_modes); +	return ret; +} + +int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc, +			     struct drm_display_mode *mode) +{ +	struct drm_output *output; +	int ret = 0; +	struct drm_display_mode *dup_mode; +	int need_dup = 0; +	list_for_each_entry(output, &dev->mode_config.output_list, head) { +		if (output->crtc == crtc) { +			if (need_dup) +				dup_mode = drm_mode_duplicate(dev, mode); +			else +				dup_mode = mode; +			ret = drm_mode_attachmode(dev, output, dup_mode);  +			if (ret) +				return ret; +			need_dup = 1; +		} +	} +	return 0; +} +EXPORT_SYMBOL(drm_mode_attachmode_crtc); + +static int drm_mode_detachmode(struct drm_device *dev, +			       struct drm_output *output, +			       struct drm_display_mode *mode) +{ +	int found = 0; +	int ret = 0; +	struct drm_display_mode *match_mode, *t; + +	list_for_each_entry_safe(match_mode, t, &output->user_modes, head) { +		if (drm_mode_equal(match_mode, mode)) { +			list_del(&match_mode->head); +			drm_mode_destroy(dev, match_mode); +			found = 1; +			break; +		} +	} + +	if (!found) +		ret = -EINVAL; + +	return ret; +} + +int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode) +{ +	struct drm_output *output; + +	list_for_each_entry(output, &dev->mode_config.output_list, head) { +		drm_mode_detachmode(dev, output, mode); +	} +	return 0; +} +EXPORT_SYMBOL(drm_mode_detachmode_crtc); + +/** + * drm_fb_attachmode - Attach a user mode to an output + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * This attaches a user specified mode to an output. + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_mode_attachmode_ioctl(struct drm_device *dev, +			      void *data, struct drm_file *file_priv) +{ +	struct drm_mode_mode_cmd *mode_cmd = data; +	struct drm_output *output; +	struct drm_display_mode *mode; +	struct drm_mode_modeinfo *umode = &mode_cmd->mode; +	int ret = 0; + +	mutex_lock(&dev->mode_config.mutex); + +	output = idr_find(&dev->mode_config.crtc_idr, mode_cmd->output_id); +	if (!output || (output->id != mode_cmd->output_id)) { +		ret = -EINVAL; +		goto out; +	} + +	mode = drm_mode_create(dev); +	if (!mode) { +		ret = -ENOMEM; +		goto out; +	} +	 +	drm_crtc_convert_umode(mode, umode); + +	ret = drm_mode_attachmode(dev, output, mode); +out: +	mutex_unlock(&dev->mode_config.mutex); +	return ret; +} + + +/** + * drm_fb_detachmode - Detach a user specified mode from an output + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_mode_detachmode_ioctl(struct drm_device *dev, +			      void *data, struct drm_file *file_priv) +{ +	struct drm_mode_mode_cmd *mode_cmd = data; +	struct drm_output *output; +	struct drm_display_mode mode; +	struct drm_mode_modeinfo *umode = &mode_cmd->mode; +	int ret = 0; + +	mutex_lock(&dev->mode_config.mutex); + +	output = idr_find(&dev->mode_config.crtc_idr, mode_cmd->output_id); +	if (!output || (output->id != mode_cmd->output_id)) { +		ret = -EINVAL; +		goto out; +	} +	 +	drm_crtc_convert_umode(&mode, umode); +	ret = drm_mode_detachmode(dev, output, &mode); +out:	        +	mutex_unlock(&dev->mode_config.mutex); +	return ret; +} + +struct drm_property *drm_property_create(struct drm_device *dev, int flags, +					 const char *name, int num_values) +{ +	struct drm_property *property = NULL; + +	property = kzalloc(sizeof(struct drm_property), GFP_KERNEL); +	if (!property) +		return NULL; + +	if (num_values) { +		property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL); +		if (!property->values) +			goto fail; +	} + +	property->id = drm_idr_get(dev, property); +	property->flags = flags; +	property->num_values = num_values; +	INIT_LIST_HEAD(&property->enum_blob_list); + +	if (name) +		strncpy(property->name, name, DRM_PROP_NAME_LEN); + +	list_add_tail(&property->head, &dev->mode_config.property_list); +	return property; +fail: +	kfree(property); +	return NULL; +} +EXPORT_SYMBOL(drm_property_create); + +int drm_property_add_enum(struct drm_property *property, int index, +			  uint64_t value, const char *name) +{ +	struct drm_property_enum *prop_enum; + +	if (!(property->flags & DRM_MODE_PROP_ENUM)) +		return -EINVAL; + +	if (!list_empty(&property->enum_blob_list)) { +		list_for_each_entry(prop_enum, &property->enum_blob_list, head) { +			if (prop_enum->value == value) { +				strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);  +				prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; +				return 0; +			} +		} +	} + +	prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL); +	if (!prop_enum) +		return -ENOMEM; + +	strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);  +	prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; +	prop_enum->value = value; + +	property->values[index] = value; +	list_add_tail(&prop_enum->head, &property->enum_blob_list); +	return 0; +} +EXPORT_SYMBOL(drm_property_add_enum); + +void drm_property_destroy(struct drm_device *dev, struct drm_property *property) +{ +	struct drm_property_enum *prop_enum, *pt; + +	list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) { +		list_del(&prop_enum->head); +		kfree(prop_enum); +	} + +	if (property->num_values) +		kfree(property->values); +	drm_idr_put(dev, property->id); +	list_del(&property->head); +	kfree(property);	 +} +EXPORT_SYMBOL(drm_property_destroy); + +int drm_output_attach_property(struct drm_output *output, +			       struct drm_property *property, uint64_t init_val) +{ +	int i; + +	for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { +		if (output->property_ids[i] == 0) { +			output->property_ids[i] = property->id; +			output->property_values[i] = init_val; +			break; +		} +	} + +	if (i == DRM_OUTPUT_MAX_PROPERTY) +		return -EINVAL; +	return 0; +} +EXPORT_SYMBOL(drm_output_attach_property); + +int drm_output_property_set_value(struct drm_output *output, +				  struct drm_property *property, uint64_t value) +{ +	int i; + +	for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { +		if (output->property_ids[i] == property->id) { +			output->property_values[i] = value; +			break; +		} +	} + +	if (i == DRM_OUTPUT_MAX_PROPERTY) +		return -EINVAL; +	return 0; +} +EXPORT_SYMBOL(drm_output_property_set_value); + +int drm_mode_getproperty_ioctl(struct drm_device *dev, +			       void *data, struct drm_file *file_priv) +{ +	struct drm_mode_get_property *out_resp = data; +	struct drm_property *property; +	int enum_count = 0; +	int blob_count = 0; +	int value_count = 0; +	int ret = 0, i; +	int copied; +	struct drm_property_enum *prop_enum; +	struct drm_mode_property_enum __user *enum_ptr; +	struct drm_property_blob *prop_blob; +	uint32_t *blob_id_ptr; +	uint64_t __user *values_ptr; +	uint32_t __user *blob_length_ptr; + +	mutex_lock(&dev->mode_config.mutex); +	property = idr_find(&dev->mode_config.crtc_idr, out_resp->prop_id); +	if (!property || (property->id != out_resp->prop_id)) { +		ret = -EINVAL; +		goto done; +	} + +	if (property->flags & DRM_MODE_PROP_ENUM) { +		list_for_each_entry(prop_enum, &property->enum_blob_list, head) +			enum_count++; +	} else if (property->flags & DRM_MODE_PROP_BLOB) { +		list_for_each_entry(prop_blob, &property->enum_blob_list, head) +			blob_count++; +	} + +	value_count = property->num_values; + +	strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); +	out_resp->name[DRM_PROP_NAME_LEN-1] = 0; +	out_resp->flags = property->flags; + +	if ((out_resp->count_values >= value_count) && value_count) { +		values_ptr = (uint64_t *)(unsigned long)out_resp->values_ptr; +		for (i = 0; i < value_count; i++) { +			if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) { +				ret = -EFAULT; +				goto done; +			} +		} +	} +	out_resp->count_values = value_count; + +	if (property->flags & DRM_MODE_PROP_ENUM) { + +		if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { +			copied = 0; +			enum_ptr = (struct drm_mode_property_enum *)(unsigned long)out_resp->enum_blob_ptr; +			list_for_each_entry(prop_enum, &property->enum_blob_list, head) { +				 +				if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { +					ret = -EFAULT; +					goto done; +				} +				 +				if (copy_to_user(&enum_ptr[copied].name, +						 &prop_enum->name, DRM_PROP_NAME_LEN)) { +					ret = -EFAULT; +					goto done; +				} +				copied++; +			} +		} +		out_resp->count_enum_blobs = enum_count; +	} + +	if (property->flags & DRM_MODE_PROP_BLOB) { +		if ((out_resp->count_enum_blobs >= blob_count) && blob_count) { +			copied = 0; +			blob_id_ptr = (uint32_t *)(unsigned long)out_resp->enum_blob_ptr; +			blob_length_ptr = (uint32_t *)(unsigned long)out_resp->values_ptr; +			 +			list_for_each_entry(prop_blob, &property->enum_blob_list, head) { +				if (put_user(prop_blob->id, blob_id_ptr + copied)) { +					ret = -EFAULT; +					goto done; +				} +				 +				if (put_user(prop_blob->length, blob_length_ptr + copied)) { +					ret = -EFAULT; +					goto done; +				} +				 +				copied++; +			} +		} +		out_resp->count_enum_blobs = enum_count; +	} +done: +	mutex_unlock(&dev->mode_config.mutex); +	return ret; +} + +static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length, +							  void *data) +{ +	struct drm_property_blob *blob; + +	if (!length || !data) +		return NULL; + +	blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); +	if (!blob) +		return NULL; + +	blob->data = (void *)((char *)blob + sizeof(struct drm_property_blob)); +	blob->length = length; + +	memcpy(blob->data, data, length); + +	blob->id = drm_idr_get(dev, blob); +	 +	list_add_tail(&blob->head, &dev->mode_config.property_blob_list); +	return blob; +} + +static void drm_property_destroy_blob(struct drm_device *dev, +			       struct drm_property_blob *blob) +{ +	drm_idr_put(dev, blob->id); +	list_del(&blob->head); +	kfree(blob); +} + +int drm_mode_getblob_ioctl(struct drm_device *dev, +			   void *data, struct drm_file *file_priv) +{ +	struct drm_mode_get_blob *out_resp = data; +	struct drm_property_blob *blob; +	int ret = 0; +	void *blob_ptr; + +	mutex_lock(&dev->mode_config.mutex); +	 +	blob = idr_find(&dev->mode_config.crtc_idr, out_resp->blob_id); +	if (!blob || (blob->id != out_resp->blob_id)) { +		ret = -EINVAL; +		goto done; +	} + +	if (out_resp->length == blob->length) { +		blob_ptr = (void *)(unsigned long)out_resp->data; +		if (copy_to_user(blob_ptr, blob->data, blob->length)){ +			ret = -EFAULT; +			goto done; +		} +	} +	out_resp->length = blob->length; + +done: +	mutex_unlock(&dev->mode_config.mutex); +	return ret; +} + +int drm_mode_output_update_edid_property(struct drm_output *output, struct edid *edid) +{ +	struct drm_device *dev = output->dev; +	int ret = 0; +	if (output->edid_blob_ptr) +		drm_property_destroy_blob(dev, output->edid_blob_ptr); + +	output->edid_blob_ptr = drm_property_create_blob(output->dev, 128, edid); +	 +	ret = drm_output_property_set_value(output, dev->mode_config.edid_property, output->edid_blob_ptr->id); +	return ret; +} +EXPORT_SYMBOL(drm_mode_output_update_edid_property); + +int drm_mode_output_property_set_ioctl(struct drm_device *dev, +				       void *data, struct drm_file *file_priv) +{ +	struct drm_mode_output_set_property *out_resp = data; +	struct drm_property *property; +	struct drm_output *output; +	int ret = -EINVAL; +	int i; + +	mutex_lock(&dev->mode_config.mutex); +	output = idr_find(&dev->mode_config.crtc_idr, out_resp->output_id); +	if (!output || (output->id != out_resp->output_id)) { +		goto out; +	} + +	for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { +		if (output->property_ids[i] == out_resp->prop_id) +			break; +	} + +	if (i == DRM_OUTPUT_MAX_PROPERTY) { +		goto out; +	} +	 +	property = idr_find(&dev->mode_config.crtc_idr, out_resp->prop_id); +	if (!property || (property->id != out_resp->prop_id)) { +		goto out; +	} + +	if (property->flags & DRM_MODE_PROP_IMMUTABLE) +		goto out; + +	if (property->flags & DRM_MODE_PROP_RANGE) { +		if (out_resp->value < property->values[0]) +			goto out; + +		if (out_resp->value > property->values[1]) +			goto out; +	} else { +		int found = 0; +		for (i = 0; i < property->num_values; i++) { +			if (property->values[i] == out_resp->value) { +				found = 1; +				break; +			} +		} +		if (!found) { +			goto out; +		} +	} + +	if (output->funcs->set_property) +		ret = output->funcs->set_property(output, property, out_resp->value); + +out: +	mutex_unlock(&dev->mode_config.mutex); +	return ret; +} + diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h new file mode 100644 index 00000000..43ef95ed --- /dev/null +++ b/linux-core/drm_crtc.h @@ -0,0 +1,667 @@ +/* + * Copyright © 2006 Keith Packard + * Copyright © 2007 Intel Corporation + *   Jesse Barnes <jesse.barnes@intel.com> + */ +#ifndef __DRM_CRTC_H__ +#define __DRM_CRTC_H__ + +#include <linux/i2c.h> +#include <linux/spinlock.h> +#include <linux/types.h> +#include <linux/idr.h> + +#include <linux/fb.h> + +struct drm_device; + +/* + * Note on terminology:  here, for brevity and convenience, we refer to output + * control chips as 'CRTCs'.  They can control any type of output, VGA, LVDS, + * DVI, etc.  And 'screen' refers to the whole of the visible display, which + * may span multiple monitors (and therefore multiple CRTC and output + * structures). + */ + +enum drm_mode_status { +    MODE_OK	= 0,	/* Mode OK */ +    MODE_HSYNC,		/* hsync out of range */ +    MODE_VSYNC,		/* vsync out of range */ +    MODE_H_ILLEGAL,	/* mode has illegal horizontal timings */ +    MODE_V_ILLEGAL,	/* mode has illegal horizontal timings */ +    MODE_BAD_WIDTH,	/* requires an unsupported linepitch */ +    MODE_NOMODE,	/* no mode with a maching name */ +    MODE_NO_INTERLACE,	/* interlaced mode not supported */ +    MODE_NO_DBLESCAN,	/* doublescan mode not supported */ +    MODE_NO_VSCAN,	/* multiscan mode not supported */ +    MODE_MEM,		/* insufficient video memory */ +    MODE_VIRTUAL_X,	/* mode width too large for specified virtual size */ +    MODE_VIRTUAL_Y,	/* mode height too large for specified virtual size */ +    MODE_MEM_VIRT,	/* insufficient video memory given virtual size */ +    MODE_NOCLOCK,	/* no fixed clock available */ +    MODE_CLOCK_HIGH,	/* clock required is too high */ +    MODE_CLOCK_LOW,	/* clock required is too low */ +    MODE_CLOCK_RANGE,	/* clock/mode isn't in a ClockRange */ +    MODE_BAD_HVALUE,	/* horizontal timing was out of range */ +    MODE_BAD_VVALUE,	/* vertical timing was out of range */ +    MODE_BAD_VSCAN,	/* VScan value out of range */ +    MODE_HSYNC_NARROW,	/* horizontal sync too narrow */ +    MODE_HSYNC_WIDE,	/* horizontal sync too wide */ +    MODE_HBLANK_NARROW,	/* horizontal blanking too narrow */ +    MODE_HBLANK_WIDE,	/* horizontal blanking too wide */ +    MODE_VSYNC_NARROW,	/* vertical sync too narrow */ +    MODE_VSYNC_WIDE,	/* vertical sync too wide */ +    MODE_VBLANK_NARROW,	/* vertical blanking too narrow */ +    MODE_VBLANK_WIDE,	/* vertical blanking too wide */ +    MODE_PANEL,         /* exceeds panel dimensions */ +    MODE_INTERLACE_WIDTH, /* width too large for interlaced mode */ +    MODE_ONE_WIDTH,     /* only one width is supported */ +    MODE_ONE_HEIGHT,    /* only one height is supported */ +    MODE_ONE_SIZE,      /* only one resolution is supported */ +    MODE_NO_REDUCED,    /* monitor doesn't accept reduced blanking */ +    MODE_UNVERIFIED = -3, /* mode needs to reverified */ +    MODE_BAD = -2,	/* unspecified reason */ +    MODE_ERROR	= -1	/* error condition */ +}; + +#define DRM_MODE_TYPE_CLOCK_CRTC_C (DRM_MODE_TYPE_CLOCK_C | \ +				    DRM_MODE_TYPE_CRTC_C) + +#define DRM_MODE(nm, t, c, hd, hss, hse, ht, hsk, vd, vss, vse, vt, vs, f) \ +	.name = nm, .status = 0, .type = (t), .clock = (c), \ +	.hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \ +	.htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \ +	.vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \ +	.vscan = (vs), .flags = (f), .vrefresh = 0 + +struct drm_display_mode { +	/* Header */ +	struct list_head head; +	char name[DRM_DISPLAY_MODE_LEN]; +	int mode_id; +	int output_count; +	enum drm_mode_status status; +	int type; + +	/* Proposed mode values */ +	int clock; +	int hdisplay; +	int hsync_start; +	int hsync_end; +	int htotal; +	int hskew; +	int vdisplay; +	int vsync_start; +	int vsync_end; +	int vtotal; +	int vscan; +	unsigned int flags; + +	/* Actual mode we give to hw */ +	int clock_index; +	int synth_clock; +	int crtc_hdisplay; +	int crtc_hblank_start; +	int crtc_hblank_end; +	int crtc_hsync_start; +	int crtc_hsync_end; +	int crtc_htotal; +	int crtc_hskew; +	int crtc_vdisplay; +	int crtc_vblank_start; +	int crtc_vblank_end; +	int crtc_vsync_start; +	int crtc_vsync_end; +	int crtc_vtotal; +	int crtc_hadjusted; +	int crtc_vadjusted; + +	/* Driver private mode info */ +	int private_size; +	int *private; +	int private_flags; + +	int vrefresh; +	float hsync; +}; + +/* Video mode flags */ +#define V_PHSYNC	(1<<0) +#define V_NHSYNC	(1<<1) +#define V_PVSYNC	(1<<2) +#define V_NVSYNC	(1<<3) +#define V_INTERLACE	(1<<4) +#define V_DBLSCAN	(1<<5) +#define V_CSYNC		(1<<6) +#define V_PCSYNC	(1<<7) +#define V_NCSYNC	(1<<8) +#define V_HSKEW		(1<<9) /* hskew provided */ +#define V_BCAST		(1<<10) +#define V_PIXMUX	(1<<11) +#define V_DBLCLK	(1<<12) +#define V_CLKDIV2	(1<<13) + +#define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */ + +#define DPMSModeOn 0 +#define DPMSModeStandby 1 +#define DPMSModeSuspend 2 +#define DPMSModeOff 3 + +#define ConnectorUnknown 0 +#define ConnectorVGA 1 +#define ConnectorDVII 2 +#define ConnectorDVID 3 +#define ConnectorDVIA 4 +#define ConnectorComposite 5 +#define ConnectorSVIDEO 6 +#define ConnectorLVDS 7 +#define ConnectorComponent 8 +#define Connector9PinDIN 9 +#define ConnectorDisplayPort 10 +#define ConnectorHDMIA 11 +#define ConnectorHDMIB 12 + +enum drm_output_status { +	output_status_connected = 1, +	output_status_disconnected = 2, +	output_status_unknown = 3, +}; + +enum subpixel_order { +	SubPixelUnknown = 0, +	SubPixelHorizontalRGB, +	SubPixelHorizontalBGR, +	SubPixelVerticalRGB, +	SubPixelVerticalBGR, +	SubPixelNone, +}; + +/* + * Describes a given display (e.g. CRT or flat panel) and its limitations. + */ +struct drm_display_info { +	char name[DRM_DISPLAY_INFO_LEN]; +	/* Input info */ +	bool serration_vsync; +	bool sync_on_green; +	bool composite_sync; +	bool separate_syncs; +	bool blank_to_black; +	unsigned char video_level; +	bool digital; +	/* Physical size */ +        unsigned int width_mm; +	unsigned int height_mm; + +	/* Display parameters */ +	unsigned char gamma; /* FIXME: storage format */ +	bool gtf_supported; +	bool standard_color; +	enum { +		monochrome, +		rgb, +		other, +		unknown, +	} display_type; +	bool active_off_supported; +	bool suspend_supported; +	bool standby_supported; + +	/* Color info FIXME: storage format */ +	unsigned short redx, redy; +	unsigned short greenx, greeny; +	unsigned short bluex, bluey; +	unsigned short whitex, whitey; + +	/* Clock limits FIXME: storage format */ +	unsigned int min_vfreq, max_vfreq; +	unsigned int min_hfreq, max_hfreq; +	unsigned int pixel_clock; + +	/* White point indices FIXME: storage format */ +	unsigned int wpx1, wpy1; +	unsigned int wpgamma1; +	unsigned int wpx2, wpy2; +	unsigned int wpgamma2; + +	/* Preferred mode (if any) */ +	struct drm_display_mode *preferred_mode; +	char *raw_edid; /* if any */ +}; + +struct drm_framebuffer { +	struct drm_device *dev; +	struct list_head head; +	int id; /* idr assigned */ +	unsigned int pitch; +	unsigned long offset; +	unsigned int width; +	unsigned int height; +	/* depth can be 15 or 16 */ +	unsigned int depth; +	int bits_per_pixel; +	int flags; +	struct drm_buffer_object *bo; +	void *fbdev; +	u32 pseudo_palette[17]; +	void *virtual_base; +	struct list_head filp_head; +}; + +struct drm_property_blob { +	struct list_head head; +	unsigned int length; +	unsigned int id; +	void *data; +}; + +struct drm_property_enum { +	uint64_t value; +	struct list_head head; +	char name[DRM_PROP_NAME_LEN]; +}; + +struct drm_property { +	struct list_head head; +	int id; /* idr assigned */ +	uint32_t flags; +	char name[DRM_PROP_NAME_LEN]; +	uint32_t num_values; +	uint64_t *values; + +	struct list_head enum_blob_list; +}; + +struct drm_crtc; +struct drm_output; + +/** + * drm_crtc_funcs - control CRTCs for a given device + * @dpms: control display power levels + * @save: save CRTC state + * @resore: restore CRTC state + * @lock: lock the CRTC + * @unlock: unlock the CRTC + * @shadow_allocate: allocate shadow pixmap + * @shadow_create: create shadow pixmap for rotation support + * @shadow_destroy: free shadow pixmap + * @mode_fixup: fixup proposed mode + * @mode_set: set the desired mode on the CRTC + * @gamma_set: specify color ramp for CRTC + * @cleanup: cleanup driver private state prior to close + * + * The drm_crtc_funcs structure is the central CRTC management structure + * in the DRM.  Each CRTC controls one or more outputs (note that the name + * CRTC is simply historical, a CRTC may control LVDS, VGA, DVI, TV out, etc. + * outputs, not just CRTs). + * + * Each driver is responsible for filling out this structure at startup time, + * in addition to providing other modesetting features, like i2c and DDC + * bus accessors. + */ +struct drm_crtc_funcs { +	/* +	 * Control power levels on the CRTC.  If the mode passed in is +	 * unsupported, the provider must use the next lowest power level. +	 */ +	void (*dpms)(struct drm_crtc *crtc, int mode); + +	/* JJJ:  Are these needed? */ +	/* Save CRTC state */ +	void (*save)(struct drm_crtc *crtc); /* suspend? */ +	/* Restore CRTC state */ +	void (*restore)(struct drm_crtc *crtc); /* resume? */ +	bool (*lock)(struct drm_crtc *crtc); +	void (*unlock)(struct drm_crtc *crtc); + +	void (*prepare)(struct drm_crtc *crtc); +	void (*commit)(struct drm_crtc *crtc); + +	/* Provider can fixup or change mode timings before modeset occurs */ +	bool (*mode_fixup)(struct drm_crtc *crtc, +			   struct drm_display_mode *mode, +			   struct drm_display_mode *adjusted_mode); +	/* Actually set the mode */ +	void (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, +			 struct drm_display_mode *adjusted_mode, int x, int y); + +	/* Move the crtc on the current fb to the given position *optional* */ +	void (*mode_set_base)(struct drm_crtc *crtc, int x, int y); + +	/* cursor controls */ +	int (*cursor_set)(struct drm_crtc *crtc, struct drm_buffer_object *bo, +			  uint32_t width, uint32_t height); +	int (*cursor_move)(struct drm_crtc *crtc, int x, int y); + +	/* Set gamma on the CRTC */ +	void (*gamma_set)(struct drm_crtc *crtc, u16 r, u16 g, u16 b, +			  int regno); +	/* Driver cleanup routine */ +	void (*cleanup)(struct drm_crtc *crtc); +}; + +/** + * drm_crtc - central CRTC control structure + * @enabled: is this CRTC enabled? + * @x: x position on screen + * @y: y position on screen + * @desired_mode: new desired mode + * @desired_x: desired x for desired_mode + * @desired_y: desired y for desired_mode + * @funcs: CRTC control functions + * @driver_private: arbitrary driver data + * + * Each CRTC may have one or more outputs associated with it.  This structure + * allows the CRTC to be controlled. + */ +struct drm_crtc { +	struct drm_device *dev; +	struct list_head head; + +	int id; /* idr assigned */ + +	/* framebuffer the output is currently bound to */ +	struct drm_framebuffer *fb; + +	bool enabled; + +	/* JJJ: are these needed? */ +	bool cursor_in_range; +	bool cursor_shown; + +	struct drm_display_mode mode; + +	int x, y; +	struct drm_display_mode *desired_mode; +	int desired_x, desired_y; +	const struct drm_crtc_funcs *funcs; +	void *driver_private; + +	/* RRCrtcPtr randr_crtc? */ +}; + +extern struct drm_crtc *drm_crtc_create(struct drm_device *dev, +					const struct drm_crtc_funcs *funcs); + +/** + * drm_output_funcs - control outputs on a given device + * @init: setup this output + * @dpms: set power state (see drm_crtc_funcs above) + * @save: save output state + * @restore: restore output state + * @mode_valid: is this mode valid on the given output? + * @mode_fixup: try to fixup proposed mode for this output + * @mode_set: set this mode + * @detect: is this output active? + * @get_modes: get mode list for this output + * @set_property: property for this output may need update + * @cleanup: output is going away, cleanup + * + * Each CRTC may have one or more outputs attached to it.  The functions + * below allow the core DRM code to control outputs, enumerate available modes, + * etc. + */ +struct drm_output_funcs { +	void (*init)(struct drm_output *output); +	void (*dpms)(struct drm_output *output, int mode); +	void (*save)(struct drm_output *output); +	void (*restore)(struct drm_output *output); +	int (*mode_valid)(struct drm_output *output, +			  struct drm_display_mode *mode); +	bool (*mode_fixup)(struct drm_output *output, +			   struct drm_display_mode *mode, +			   struct drm_display_mode *adjusted_mode); +	void (*prepare)(struct drm_output *output); +	void (*commit)(struct drm_output *output); +	void (*mode_set)(struct drm_output *output, +			 struct drm_display_mode *mode, +			 struct drm_display_mode *adjusted_mode); +	enum drm_output_status (*detect)(struct drm_output *output); +	int (*get_modes)(struct drm_output *output); +	/* JJJ: type checking for properties via property value type */ +	bool (*set_property)(struct drm_output *output, struct drm_property *property, +			     uint64_t val); +	void (*cleanup)(struct drm_output *output); +}; + +#define DRM_OUTPUT_MAX_UMODES 16 +#define DRM_OUTPUT_MAX_PROPERTY 16 +#define DRM_OUTPUT_LEN 32 +/** + * drm_output - central DRM output control structure + * @crtc: CRTC this output is currently connected to, NULL if none + * @possible_crtcs: bitmap of CRTCS this output could be attached to + * @possible_clones: bitmap of possible outputs this output could clone + * @interlace_allowed: can this output handle interlaced modes? + * @doublescan_allowed: can this output handle doublescan? + * @available_modes: modes available on this output (from get_modes() + user) + * @initial_x: initial x position for this output + * @initial_y: initial y position for this output + * @status: output connected? + * @subpixel_order: for this output + * @mm_width: displayable width of output in mm + * @mm_height: displayable height of output in mm + * @funcs: output control functions + * @driver_private: private driver data + * + * Each output may be connected to one or more CRTCs, or may be clonable by + * another output if they can share a CRTC.  Each output also has a specific + * position in the broader display (referred to as a 'screen' though it could + * span multiple monitors). + */ +struct drm_output { +	struct drm_device *dev; +	struct list_head head; +	struct drm_crtc *crtc; +	int id; /* idr assigned */ + +	int output_type; +	int output_type_id; +	unsigned long possible_crtcs; +	unsigned long possible_clones; +	bool interlace_allowed; +	bool doublescan_allowed; +	struct list_head modes; /* list of modes on this output */ + +	/* +	  OptionInfoPtr options; +	  XF86ConfMonitorPtr conf_monitor; +	 */ +	int initial_x, initial_y; +	enum drm_output_status status; + +	/* these are modes added by probing with DDC or the BIOS */ +	struct list_head probed_modes; +	 +	/* xf86MonPtr MonInfo; */ +	enum subpixel_order subpixel_order; +	int mm_width, mm_height; +	struct drm_display_info *monitor_info; /* if any */ +  	const struct drm_output_funcs *funcs; +	void *driver_private; +  uint32_t make_shit_work; +	struct list_head user_modes; +	struct drm_property_blob *edid_blob_ptr; +	u32 property_ids[DRM_OUTPUT_MAX_PROPERTY]; +	uint64_t property_values[DRM_OUTPUT_MAX_PROPERTY]; +}; + +/** + * struct drm_mode_set + * + * Represents a single crtc the outputs that it drives with what mode + * and from which framebuffer it scans out from. + */ +struct drm_mode_set +{ +	struct drm_framebuffer *fb; +	struct drm_crtc *crtc; + +	struct drm_output **outputs; +	size_t num_outputs; +}; + +/** + * struct drm_mode_config_funcs - configure CRTCs for a given screen layout + * @resize: adjust CRTCs as necessary for the proposed layout + * + * Currently only a resize hook is available.  DRM will call back into the + * driver with a new screen width and height.  If the driver can't support + * the proposed size, it can return false.  Otherwise it should adjust + * the CRTC<->output mappings as needed and update its view of the screen. + */ +struct drm_mode_config_funcs { +	bool (*resize)(struct drm_device *dev, int width, int height); +}; + +/** + * drm_mode_config - Mode configuration control structure + * + */ +struct drm_mode_config { +	struct mutex mutex; /* protects configuration and IDR */ +	struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, output, modes - just makes life easier */ +	/* this is limited to one for now */ +	int num_fb; +	struct list_head fb_list; +	int num_output; +	struct list_head output_list; + +	/* int compat_output? */ +	int num_crtc; +	struct list_head crtc_list; + +	struct list_head property_list; + +	int min_width, min_height; +	int max_width, max_height; +	/* DamagePtr rotationDamage? */ +	/* DGA stuff? */ +	struct drm_mode_config_funcs *funcs; +	unsigned long fb_base; + +	/* pointers to standard properties */ +	struct list_head property_blob_list; +	struct drm_property *edid_property; +	struct drm_property *dpms_property; +	struct drm_property *connector_type_property; +	struct drm_property *connector_num_property; + +	/* TV properties */ +	struct drm_property *tv_mode_property; +	struct drm_property *tv_left_margin_property; +	struct drm_property *tv_right_margin_property; +	struct drm_property *tv_top_margin_property; +	struct drm_property *tv_bottom_margin_property; + +	/* hotplug */ +	uint32_t hotplug_counter; +}; + +struct drm_output *drm_output_create(struct drm_device *dev, +				     const struct drm_output_funcs *funcs, +				     int type); + +extern char *drm_get_output_name(struct drm_output *output); +extern void drm_output_destroy(struct drm_output *output); +extern void drm_fb_release(struct file *filp); + +extern struct edid *drm_get_edid(struct drm_output *output, +				 struct i2c_adapter *adapter); +extern int drm_add_edid_modes(struct drm_output *output, struct edid *edid); +extern void drm_mode_probed_add(struct drm_output *output, struct drm_display_mode *mode); +extern void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode); +extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, +						   struct drm_display_mode *mode); +extern void drm_mode_debug_printmodeline(struct drm_device *dev, +					 struct drm_display_mode *mode); +extern void drm_mode_config_init(struct drm_device *dev); +extern void drm_mode_config_cleanup(struct drm_device *dev); +extern void drm_mode_set_name(struct drm_display_mode *mode); +extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2); +extern void drm_disable_unused_functions(struct drm_device *dev); + +/* for us by fb module */ +extern int drm_mode_attachmode_crtc(struct drm_device *dev, +				    struct drm_crtc *crtc, +				    struct drm_display_mode *mode); +extern int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode); + +extern struct drm_display_mode *drm_mode_create(struct drm_device *dev); +extern void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode); +extern void drm_mode_list_concat(struct list_head *head, +				 struct list_head *new); +extern void drm_mode_validate_size(struct drm_device *dev, +				   struct list_head *mode_list, +				   int maxX, int maxY, int maxPitch); +extern void drm_mode_prune_invalid(struct drm_device *dev, +				   struct list_head *mode_list, bool verbose); +extern void drm_mode_sort(struct list_head *mode_list); +extern int drm_mode_vrefresh(struct drm_display_mode *mode); +extern void drm_mode_set_crtcinfo(struct drm_display_mode *p, +				  int adjust_flags); +extern void drm_mode_output_list_update(struct drm_output *output); +extern int drm_mode_output_update_edid_property(struct drm_output *output, +						struct edid *edid); +extern int drm_output_property_set_value(struct drm_output *output, +					 struct drm_property *property, +					 uint64_t value); +extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); +extern bool drm_initial_config(struct drm_device *dev, bool cangrow); +extern void drm_framebuffer_set_object(struct drm_device *dev, +				       unsigned long handle); +extern struct drm_framebuffer *drm_framebuffer_create(struct drm_device *dev); +extern void drm_framebuffer_destroy(struct drm_framebuffer *fb); +extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); +extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); +extern bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, +		       int x, int y); +extern int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, bool connected); + +extern int drm_output_attach_property(struct drm_output *output, +				      struct drm_property *property, uint64_t init_val); +extern struct drm_property *drm_property_create(struct drm_device *dev, int flags, +						const char *name, int num_values); +extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); +extern int drm_property_add_enum(struct drm_property *property, int index,  +				 uint64_t value, const char *name); + +/* IOCTLs */ +extern int drm_mode_getresources(struct drm_device *dev, +				 void *data, struct drm_file *file_priv); + +extern int drm_mode_getcrtc(struct drm_device *dev, +			    void *data, struct drm_file *file_priv); +extern int drm_mode_getoutput(struct drm_device *dev, +			      void *data, struct drm_file *file_priv); +extern int drm_mode_setcrtc(struct drm_device *dev, +			    void *data, struct drm_file *file_priv); +extern int drm_mode_cursor_ioctl(struct drm_device *dev, +				void *data, struct drm_file *file_priv); +extern int drm_mode_addfb(struct drm_device *dev, +			  void *data, struct drm_file *file_priv); +extern int drm_mode_rmfb(struct drm_device *dev, +			 void *data, struct drm_file *file_priv); +extern int drm_mode_getfb(struct drm_device *dev, +			  void *data, struct drm_file *file_priv); +extern int drm_mode_addmode_ioctl(struct drm_device *dev, +				  void *data, struct drm_file *file_priv); +extern int drm_mode_rmmode_ioctl(struct drm_device *dev, +				 void *data, struct drm_file *file_priv); +extern int drm_mode_attachmode_ioctl(struct drm_device *dev, +				     void *data, struct drm_file *file_priv); +extern int drm_mode_detachmode_ioctl(struct drm_device *dev, +				     void *data, struct drm_file *file_priv); + +extern int drm_mode_getproperty_ioctl(struct drm_device *dev, +				      void *data, struct drm_file *file_priv); +extern int drm_mode_getblob_ioctl(struct drm_device *dev, +				  void *data, struct drm_file *file_priv); +extern int drm_mode_output_property_set_ioctl(struct drm_device *dev, +					      void *data, struct drm_file *file_priv); +extern int drm_mode_hotplug_ioctl(struct drm_device *dev, +				  void *data, struct drm_file *file_priv); + +#endif /* __DRM_CRTC_H__ */ + diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 3c2794d0..4f5b364e 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -56,7 +56,7 @@ static int drm_version(struct drm_device *dev, void *data,  /** Ioctl table */  static struct drm_ioctl_desc drm_ioctls[] = { -	DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, 0), +	DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_CONTROL_ALLOW),  	DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0),  	DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0),  	DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY), @@ -121,6 +121,22 @@ static struct drm_ioctl_desc drm_ioctls[] = {  	DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), +	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), +	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), +	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETOUTPUT, drm_mode_getoutput, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), +	DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), +	DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), +	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), +	DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), +	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), + +	DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_output_property_set_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), +	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), +	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), +	DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), +	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_ROOT_ONLY | DRM_CONTROL_ALLOW), +	DRM_IOCTL_DEF(DRM_IOCTL_MODE_HOTPLUG, drm_mode_hotplug_ioctl, DRM_CONTROL_ALLOW), +  	DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl,  		      DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),  	DRM_IOCTL_DEF(DRM_IOCTL_MM_TAKEDOWN, drm_mm_takedown_ioctl, @@ -164,31 +180,23 @@ static struct drm_ioctl_desc drm_ioctls[] = {   */  int drm_lastclose(struct drm_device * dev)  { -	struct drm_magic_entry *pt, *next; -	struct drm_map_list *r_list, *list_t;  	struct drm_vma_entry *vma, *vma_temp;  	int i;  	DRM_DEBUG("\n"); +/*	return 0; */  	/*  	 * We can't do much about this function failing.  	 */ -	drm_bo_driver_finish(dev); -  	if (dev->driver->lastclose)  		dev->driver->lastclose(dev);  	DRM_DEBUG("driver lastclose completed\n"); -	if (dev->unique) { -		drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER); -		dev->unique = NULL; -		dev->unique_len = 0; -	} -	if (dev->irq_enabled) -		drm_irq_uninstall(dev); +/*	if (dev->irq_enabled) +		drm_irq_uninstall(dev); */  	/* Free drawable information memory */  	mutex_lock(&dev->struct_mutex); @@ -196,22 +204,11 @@ int drm_lastclose(struct drm_device * dev)  	drm_drawable_free_all(dev);  	del_timer(&dev->timer); -	if (dev->unique) { -		drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER); -		dev->unique = NULL; -		dev->unique_len = 0; -	} - -	if (dev->magicfree.next) { -		list_for_each_entry_safe(pt, next, &dev->magicfree, head) { -			list_del(&pt->head); -			drm_ht_remove_item(&dev->magiclist, &pt->hash_item); -			drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); -		} -		drm_ht_remove(&dev->magiclist); +	if (dev->primary->master) { +		drm_put_master(dev->primary->master); +		dev->primary->master = NULL;  	} - - +	  	/* Clear AGP information */  	if (drm_core_has_AGP(dev) && dev->agp) {  		struct drm_agp_mem *entry, *tempe; @@ -243,12 +240,13 @@ int drm_lastclose(struct drm_device * dev)  		drm_ctl_free(vma, sizeof(*vma), DRM_MEM_VMAS);  	} +	/*  	list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) {  		if (!(r_list->map->flags & _DRM_DRIVER)) {  			drm_rmmap_locked(dev, r_list->map);  			r_list = NULL;  		} -	} +	}*/  	if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist) {  		for (i = 0; i < dev->queue_count; i++) { @@ -270,11 +268,6 @@ int drm_lastclose(struct drm_device * dev)  	if (drm_core_check_feature(dev, DRIVER_HAVE_DMA))  		drm_dma_takedown(dev); -	if (dev->lock.hw_lock) { -		dev->sigdata.lock = dev->lock.hw_lock = NULL;	/* SHM removed */ -		dev->lock.file_priv = NULL; -		wake_up_interruptible(&dev->lock.lock_queue); -	}  	dev->dev_mapping = NULL;  	mutex_unlock(&dev->struct_mutex); @@ -401,12 +394,14 @@ static void drm_cleanup(struct drm_device * dev)  		DRM_DEBUG("mtrr_del=%d\n", retval);  	} +	if (dev->driver->unload) +		dev->driver->unload(dev); +         +	drm_ht_remove(&dev->map_hash);  	if (drm_core_has_AGP(dev) && dev->agp) {  		drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);  		dev->agp = NULL;  	} -	if (dev->driver->unload) -		dev->driver->unload(dev);  	if (!drm_fb_loaded)  		pci_disable_device(dev->pdev); @@ -416,35 +411,35 @@ static void drm_cleanup(struct drm_device * dev)  	drm_mm_takedown(&dev->offset_manager);  	drm_ht_remove(&dev->object_hash); -	drm_put_head(&dev->primary); +	drm_put_minor(&dev->primary); +	drm_put_minor(&dev->control);  	if (drm_put_dev(dev))  		DRM_ERROR("Cannot unload module\n");  } -void drm_exit(struct drm_driver *driver) +int drm_minors_cleanup(int id, void *ptr, void *data)  { -	int i; -	struct drm_device *dev = NULL; -	struct drm_head *head; +	struct drm_minor *minor = ptr; +	struct drm_device *dev; +	struct drm_driver *driver = data; +	if (id < 127 || id > 192) +		return 0; + +	dev = minor->dev; +	if (minor->dev->driver != driver) +		return 0; + +	if (dev) +		pci_dev_put(dev->pdev); +	drm_cleanup(dev); +	return 1; +} +void drm_exit(struct drm_driver *driver) +{  	DRM_DEBUG("\n");  	if (drm_fb_loaded) { -		for (i = 0; i < drm_cards_limit; i++) { -			head = drm_heads[i]; -			if (!head) -				continue; -			if (!head->dev) -				continue; -			if (head->dev->driver != driver) -				continue; -			dev = head->dev; -			if (dev) { -				/* release the pci driver */ -				if (dev->pdev) -					pci_dev_put(dev->pdev); -				drm_cleanup(dev); -			} -		} +		idr_for_each(&drm_minors_idr, &drm_minors_cleanup, driver);  	} else  		pci_unregister_driver(&driver->pci_driver);  #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) @@ -467,6 +462,7 @@ static int __init drm_core_init(void)  	unsigned long avail_memctl_mem;  	unsigned long max_memctl_mem; +	idr_init(&drm_minors_idr);  	si_meminfo(&si);  	/* @@ -488,11 +484,6 @@ static int __init drm_core_init(void)  	drm_init_memctl(avail_memctl_mem/2, avail_memctl_mem*3/4, si.mem_unit);  	ret = -ENOMEM; -	drm_cards_limit = -	    (drm_cards_limit < DRM_MAX_MINOR + 1 ? drm_cards_limit : DRM_MAX_MINOR + 1); -	drm_heads = drm_calloc(drm_cards_limit, sizeof(*drm_heads), DRM_MEM_STUB); -	if (!drm_heads) -		goto err_p1;  	if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops))  		goto err_p1; @@ -521,7 +512,8 @@ err_p3:  	drm_sysfs_destroy();  err_p2:  	unregister_chrdev(DRM_MAJOR, "drm"); -	drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB); + +	idr_destroy(&drm_minors_idr);  err_p1:  	return ret;  } @@ -533,7 +525,7 @@ static void __exit drm_core_exit(void)  	unregister_chrdev(DRM_MAJOR, "drm"); -	drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB); +	idr_destroy(&drm_minors_idr);  }  module_init(drm_core_init); @@ -593,7 +585,7 @@ EXPORT_SYMBOL(drm_ioctl);  long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  {  	struct drm_file *file_priv = filp->private_data; -	struct drm_device *dev = file_priv->head->dev; +	struct drm_device *dev = file_priv->minor->dev;  	struct drm_ioctl_desc *ioctl;  	drm_ioctl_t *func;  	unsigned int nr = DRM_IOCTL_NR(cmd); @@ -605,7 +597,7 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  	++file_priv->ioctl_count;  	DRM_DEBUG("pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%lx, auth=%d\n", -		  current->pid, cmd, nr, (long)old_encode_dev(file_priv->head->device), +		  current->pid, cmd, nr, (long)old_encode_dev(file_priv->minor->device),  		  file_priv->authenticated);  	if ((nr >= DRM_CORE_IOCTL_COUNT) && @@ -620,6 +612,7 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  		retcode = -EINVAL;  		goto err_i1;  	} +	    #if 0  	/*  	 * This check is disabled, because driver private ioctl->cmd @@ -650,7 +643,8 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  		retcode = -EINVAL;  	} else if (((ioctl->flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)) ||  		   ((ioctl->flags & DRM_AUTH) && !file_priv->authenticated) || -		   ((ioctl->flags & DRM_MASTER) && !file_priv->master)) { +		   ((ioctl->flags & DRM_MASTER) && !file_priv->master) || +		   ((!(ioctl->flags & DRM_CONTROL_ALLOW)) && (file_priv->minor->type == DRM_MINOR_CONTROL)) ) {  		retcode = -EACCES;  	} else {  		retcode = func(dev, kdata, file_priv); diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c new file mode 100644 index 00000000..41aa8f5e --- /dev/null +++ b/linux-core/drm_edid.c @@ -0,0 +1,485 @@ +/* + * Copyright (c) 2007 Intel Corporation + *   Jesse Barnes <jesse.barnes@intel.com> + * + * DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid) originally from + * FB layer. + *   Copyright (C) 2006 Dennis Munsie <dmunsie@cecropia.com> + */ +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> +#include "drmP.h" +#include "drm_edid.h" + +/* Valid EDID header has these bytes */ +static u8 edid_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; + +/** + * edid_valid - sanity check EDID data + * @edid: EDID data + * + * Sanity check the EDID block by looking at the header, the version number + * and the checksum.  Return 0 if the EDID doesn't check out, or 1 if it's + * valid. + */ +static bool edid_valid(struct edid *edid) +{ +	int i; +	u8 csum = 0; +	u8 *raw_edid = (u8 *)edid; + +	if (memcmp(edid->header, edid_header, sizeof(edid_header))) +		goto bad; +	if (edid->version != 1) +		goto bad; +	if (edid->revision <= 0 || edid->revision > 3) +		goto bad; + +	for (i = 0; i < EDID_LENGTH; i++) +		csum += raw_edid[i]; +	if (csum) +		goto bad; + +	return 1; + +bad: +	return 0; +} + +/** + * drm_mode_std - convert standard mode info (width, height, refresh) into mode + * @t: standard timing params + * + * Take the standard timing params (in this case width, aspect, and refresh) + * and convert them into a real mode using CVT. + * + * Punts for now, but should eventually use the FB layer's CVT based mode + * generation code. + */ +struct drm_display_mode *drm_mode_std(struct drm_device *dev, +				      struct std_timing *t) +{ +//	struct fb_videomode mode; + +//	fb_find_mode_cvt(&mode, 0, 0); +	/* JJJ:  convert to drm_display_mode */ +	struct drm_display_mode *mode; +	int hsize = t->hsize * 8 + 248, vsize; + +	mode = drm_mode_create(dev); +	if (!mode) +		return NULL; + +	if (t->aspect_ratio == 0) +		vsize = (hsize * 10) / 16; +	else if (t->aspect_ratio == 1) +		vsize = (hsize * 3) / 4; +	else if (t->aspect_ratio == 2) +		vsize = (hsize * 4) / 5; +	else +		vsize = (hsize * 9) / 16; + +	drm_mode_set_name(mode); + +	return mode; +} + +/** + * drm_mode_detailed - create a new mode from an EDID detailed timing section + * @timing: EDID detailed timing info + * @preferred: is this a preferred mode? + * + * An EDID detailed timing block contains enough info for us to create and + * return a new struct drm_display_mode.  The @preferred flag will be set + * if this is the display's preferred timing, and we'll use it to indicate + * to the other layers that this mode is desired. + */ +struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, +					   struct detailed_timing *timing) +{ +	struct drm_display_mode *mode; +	struct detailed_pixel_timing *pt = &timing->data.pixel_data; + +	if (pt->stereo) { +		printk(KERN_WARNING "stereo mode not supported\n"); +		return NULL; +	} +	if (!pt->separate_sync) { +		printk(KERN_WARNING "integrated sync not supported\n"); +		return NULL; +	} + +	mode = drm_mode_create(dev); +	if (!mode) +		return NULL; + +	mode->type = DRM_MODE_TYPE_DRIVER; +	mode->clock = timing->pixel_clock * 10; + +	mode->hdisplay = (pt->hactive_hi << 8) | pt->hactive_lo; +	mode->hsync_start = mode->hdisplay + ((pt->hsync_offset_hi << 8) | +					      pt->hsync_offset_lo); +	mode->hsync_end = mode->hsync_start + +		((pt->hsync_pulse_width_hi << 8) | +		 pt->hsync_pulse_width_lo); +	mode->htotal = mode->hdisplay + ((pt->hblank_hi << 8) | pt->hblank_lo); + +	mode->vdisplay = (pt->vactive_hi << 8) | pt->vactive_lo; +	mode->vsync_start = mode->vdisplay + ((pt->vsync_offset_hi << 8) | +					      pt->vsync_offset_lo); +	mode->vsync_end = mode->vsync_start + +		((pt->vsync_pulse_width_hi << 8) | +		 pt->vsync_pulse_width_lo); +	mode->vtotal = mode->vdisplay + ((pt->vblank_hi << 8) | pt->vblank_lo); + +	drm_mode_set_name(mode); + +	if (pt->interlaced) +		mode->flags |= V_INTERLACE; + +	mode->flags |= pt->hsync_positive ? V_PHSYNC : V_NHSYNC; +	mode->flags |= pt->vsync_positive ? V_PVSYNC : V_NVSYNC; + +	return mode; +} + +/* + * Detailed mode info for the EDID "established modes" data to use. + */ +static struct drm_display_mode edid_est_modes[] = { +	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, +		   968, 1056, 0, 600, 601, 605, 628, 0, +		   V_PHSYNC | V_PVSYNC) }, /* 800x600@60Hz */ +	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824, +		   896, 1024, 0, 600, 601, 603,  625, 0, +		   V_PHSYNC | V_PVSYNC) }, /* 800x600@56Hz */ +	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656, +		   720, 840, 0, 480, 481, 484, 500, 0, +		   V_NHSYNC | V_NVSYNC) }, /* 640x480@75Hz */ +	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664, +		   704,  832, 0, 480, 489, 491, 520, 0, +		   V_NHSYNC | V_NVSYNC) }, /* 640x480@72Hz */ +	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704, +		   768,  864, 0, 480, 483, 486, 525, 0, +		   V_NHSYNC | V_NVSYNC) }, /* 640x480@67Hz */ +	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656, +		   752, 800, 0, 480, 490, 492, 525, 0, +		   V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */ +	{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738, +		   846, 900, 0, 400, 421, 423,  449, 0, +		   V_NHSYNC | V_NVSYNC) }, /* 720x400@88Hz */ +	{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738, +		   846,  900, 0, 400, 412, 414, 449, 0, +		   V_NHSYNC | V_PVSYNC) }, /* 720x400@70Hz */ +	{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296, +		   1440, 1688, 0, 1024, 1025, 1028, 1066, 0, +		   V_PHSYNC | V_PVSYNC) }, /* 1280x1024@75Hz */ +	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040, +		   1136, 1312, 0,  768, 769, 772, 800, 0, +		   V_PHSYNC | V_PVSYNC) }, /* 1024x768@75Hz */ +	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048, +		   1184, 1328, 0,  768, 771, 777, 806, 0, +		   V_NHSYNC | V_NVSYNC) }, /* 1024x768@70Hz */ +	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048, +		   1184, 1344, 0,  768, 771, 777, 806, 0, +		   V_NHSYNC | V_NVSYNC) }, /* 1024x768@60Hz */ +	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032, +		   1208, 1264, 0, 768, 768, 776, 817, 0, +		   V_PHSYNC | V_PVSYNC | V_INTERLACE) }, /* 1024x768@43Hz */ +	{ DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864, +		   928, 1152, 0, 624, 625, 628, 667, 0, +		   V_NHSYNC | V_NVSYNC) }, /* 832x624@75Hz */ +	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816, +		   896, 1056, 0, 600, 601, 604,  625, 0, +		   V_PHSYNC | V_PVSYNC) }, /* 800x600@75Hz */ +	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856, +		   976, 1040, 0, 600, 637, 643, 666, 0, +		   V_PHSYNC | V_PVSYNC) }, /* 800x600@72Hz */ +	{ DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216, +		   1344, 1600, 0,  864, 865, 868, 900, 0, +		   V_PHSYNC | V_PVSYNC) }, /* 1152x864@75Hz */ +}; + +#define EDID_EST_TIMINGS 16 +#define EDID_STD_TIMINGS 8 +#define EDID_DETAILED_TIMINGS 4 + +/** + * add_established_modes - get est. modes from EDID and add them + * @edid: EDID block to scan + * + * Each EDID block contains a bitmap of the supported "established modes" list + * (defined above).  Tease them out and add them to the global modes list. + */ +static int add_established_modes(struct drm_output *output, struct edid *edid) +{ +	struct drm_device *dev = output->dev; +	unsigned long est_bits = edid->established_timings.t1 | +		(edid->established_timings.t2 << 8) | +		((edid->established_timings.mfg_rsvd & 0x80) << 9); +	int i, modes = 0; + +	for (i = 0; i <= EDID_EST_TIMINGS; i++) +		if (est_bits & (1<<i)) { +			struct drm_display_mode *newmode; +			newmode = drm_mode_duplicate(dev, &edid_est_modes[i]); +			drm_mode_probed_add(output, newmode); +			modes++; +		} + +	return modes; +} + +/** + * add_standard_modes - get std. modes from EDID and add them + * @edid: EDID block to scan + * + * Standard modes can be calculated using the CVT standard.  Grab them from + * @edid, calculate them, and add them to the list. + */ +static int add_standard_modes(struct drm_output *output, struct edid *edid) +{ +	struct drm_device *dev = output->dev; +	int i, modes = 0; + +	for (i = 0; i < EDID_STD_TIMINGS; i++) { +		struct std_timing *t = &edid->standard_timings[i]; +		struct drm_display_mode *newmode; + +		/* If std timings bytes are 1, 1 it's empty */ +		if (t->hsize == 1 && (t->aspect_ratio | t->vfreq) == 1) +			continue; + +		newmode = drm_mode_std(dev, &edid->standard_timings[i]); +		drm_mode_probed_add(output, newmode); +		modes++; +	} + +	return modes; +} + +/** + * add_detailed_modes - get detailed mode info from EDID data + * @edid: EDID block to scan + * + * Some of the detailed timing sections may contain mode information.  Grab + * it and add it to the list. + */ +static int add_detailed_info(struct drm_output *output, struct edid *edid) +{ +	struct drm_device *dev = output->dev; +	int i, j, modes = 0; + +	for (i = 0; i < EDID_DETAILED_TIMINGS; i++) { +		struct detailed_timing *timing = &edid->detailed_timings[i]; +		struct detailed_non_pixel *data = &timing->data.other_data; +		struct drm_display_mode *newmode; + +		/* EDID up to and including 1.2 may put monitor info here */ +		if (edid->version == 1 && edid->revision < 3) +			continue; + +		/* Detailed mode timing */ +		if (timing->pixel_clock) { +			newmode = drm_mode_detailed(dev, timing); +			/* First detailed mode is preferred */ +			if (i == 0 && edid->preferred_timing) +				newmode->type |= DRM_MODE_TYPE_PREFERRED; +			drm_mode_probed_add(output, newmode); +				      +			modes++; +			continue; +		} + +		/* Other timing or info */ +		switch (data->type) { +		case EDID_DETAIL_MONITOR_SERIAL: +			break; +		case EDID_DETAIL_MONITOR_STRING: +			break; +		case EDID_DETAIL_MONITOR_RANGE: +			/* Get monitor range data */ +			break; +		case EDID_DETAIL_MONITOR_NAME: +			break; +		case EDID_DETAIL_MONITOR_CPDATA: +			break; +		case EDID_DETAIL_STD_MODES: +			/* Five modes per detailed section */ +			for (j = 0; j < 5; i++) { +				struct std_timing *std; +				struct drm_display_mode *newmode; + +				std = &data->data.timings[j]; +				newmode = drm_mode_std(dev, std); +				drm_mode_probed_add(output, newmode); +				modes++; +			} +			break; +		default: +			break; +		} +	} + +	return modes; +} + +#define DDC_ADDR 0x50 + +static unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter) +{ +	unsigned char start = 0x0; +	unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL); +	struct i2c_msg msgs[] = { +		{ +			.addr	= DDC_ADDR, +			.flags	= 0, +			.len	= 1, +			.buf	= &start, +		}, { +			.addr	= DDC_ADDR, +			.flags	= I2C_M_RD, +			.len	= EDID_LENGTH, +			.buf	= buf, +		} +	}; + +	if (!buf) { +		dev_warn(&adapter->dev, "unable to allocate memory for EDID " +			 "block.\n"); +		return NULL; +	} + +	if (i2c_transfer(adapter, msgs, 2) == 2) +		return buf; + +	dev_info(&adapter->dev, "unable to read EDID block.\n"); +	kfree(buf); +	return NULL; +} + +static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) +{ +	struct i2c_algo_bit_data *algo_data = adapter->algo_data; +	unsigned char *edid = NULL; +	int i, j; + +	/* +	 * Startup the bus: +	 *   Set clock line high (but give it time to come up) +	 *   Then set clock & data low +	 */ +	algo_data->setscl(algo_data->data, 1); +	udelay(550); /* startup delay */ +	algo_data->setscl(algo_data->data, 0); +	algo_data->setsda(algo_data->data, 0); + +	for (i = 0; i < 3; i++) { +		/* For some old monitors we need the +		 * following process to initialize/stop DDC +		 */ +		algo_data->setsda(algo_data->data, 0); +		msleep(13); + +		algo_data->setscl(algo_data->data, 1); +		for (j = 0; j < 5; j++) { +			msleep(10); +			if (algo_data->getscl(algo_data->data)) +				break; +		} +		if (j == 5) +			continue; + +		algo_data->setsda(algo_data->data, 0); +		msleep(15); +		algo_data->setscl(algo_data->data, 0); +		msleep(15); +		algo_data->setsda(algo_data->data, 1); +		msleep(15); + +		/* Do the real work */ +		edid = drm_do_probe_ddc_edid(adapter); +		algo_data->setsda(algo_data->data, 0); +		algo_data->setscl(algo_data->data, 0); +		msleep(15); + +		algo_data->setscl(algo_data->data, 1); +		for (j = 0; j < 10; j++) { +			msleep(10); +			if (algo_data->getscl(algo_data->data)) +				break; +		} + +		algo_data->setsda(algo_data->data, 1); +		msleep(15); +		algo_data->setscl(algo_data->data, 0); +		if (edid) +			break; +	} +	/* Release the DDC lines when done or the Apple Cinema HD display +	 * will switch off +	 */ +	algo_data->setsda(algo_data->data, 0); +	algo_data->setscl(algo_data->data, 0); +	algo_data->setscl(algo_data->data, 1); + +	return edid; +} + +/** + * drm_get_edid - get EDID data, if available + * @output: output we're probing + * @adapter: i2c adapter to use for DDC + * + * Poke the given output's i2c channel to grab EDID data if possible. + *  + * Return edid data or NULL if we couldn't find any. + */ +struct edid *drm_get_edid(struct drm_output *output, +			  struct i2c_adapter *adapter) +{ +	struct edid *edid; + +	edid = (struct edid *)drm_ddc_read(adapter); +	if (!edid) { +		dev_warn(&output->dev->pdev->dev, "%s: no EDID data\n", +			 drm_get_output_name(output)); +		return NULL; +	} +	if (!edid_valid(edid)) { +		dev_warn(&output->dev->pdev->dev, "%s: EDID invalid.\n", +			 drm_get_output_name(output)); +		kfree(edid); +		return NULL; +	} +	return edid; +} +EXPORT_SYMBOL(drm_get_edid); + +/** + * drm_add_edid_modes - add modes from EDID data, if available + * @output: output we're probing + * @edid: edid data + * + * Add the specified modes to the output's mode list. + * + * Return number of modes added or 0 if we couldn't find any. + */ +int drm_add_edid_modes(struct drm_output *output, struct edid *edid) +{ +	int num_modes = 0; + +	if (edid == NULL) { +		return 0; +	} +	if (!edid_valid(edid)) { +		dev_warn(&output->dev->pdev->dev, "%s: EDID invalid.\n", +			 drm_get_output_name(output)); +		return 0; +	} +	num_modes += add_established_modes(output, edid); +	num_modes += add_standard_modes(output, edid); +	num_modes += add_detailed_info(output, edid); +	return num_modes; +} +EXPORT_SYMBOL(drm_add_edid_modes); diff --git a/linux-core/drm_edid.h b/linux-core/drm_edid.h new file mode 100644 index 00000000..0d2eeaa1 --- /dev/null +++ b/linux-core/drm_edid.h @@ -0,0 +1,176 @@ +#ifndef __DRM_EDID_H__ +#define __DRM_EDID_H__ + +#include <linux/types.h> + +#define EDID_LENGTH 128 +#define DDC_ADDR 0x50 + +#ifdef BIG_ENDIAN +#error "EDID structure is little endian, need big endian versions" +#endif + +struct est_timings { +	u8 t1; +	u8 t2; +	u8 mfg_rsvd; +} __attribute__((packed)); + +struct std_timing { +	u8 hsize; /* need to multiply by 8 then add 248 */ +	u8 vfreq:6; /* need to add 60 */ +	u8 aspect_ratio:2; /* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */ +} __attribute__((packed)); + +/* If detailed data is pixel timing */ +struct detailed_pixel_timing { +	u8 hactive_lo; +	u8 hblank_lo; +	u8 hblank_hi:4; +	u8 hactive_hi:4; +	u8 vactive_lo; +	u8 vblank_lo; +	u8 vblank_hi:4; +	u8 vactive_hi:4; +	u8 hsync_offset_lo; +	u8 hsync_pulse_width_lo; +	u8 vsync_pulse_width_lo:4; +	u8 vsync_offset_lo:4; +	u8 hsync_pulse_width_hi:2; +	u8 hsync_offset_hi:2; +	u8 vsync_pulse_width_hi:2; +	u8 vsync_offset_hi:2; +	u8 width_mm_lo; +	u8 height_mm_lo; +	u8 height_mm_hi:4; +	u8 width_mm_hi:4; +	u8 hborder; +	u8 vborder; +	u8 unknown0:1; +	u8 vsync_positive:1; +	u8 hsync_positive:1; +	u8 separate_sync:2; +	u8 stereo:1; +	u8 unknown6:1; +	u8 interlaced:1; +} __attribute__((packed)); + +/* If it's not pixel timing, it'll be one of the below */ +struct detailed_data_string { +	u8 str[13]; +} __attribute__((packed)); + +struct detailed_data_monitor_range { +	u8 min_vfreq; +	u8 max_vfreq; +	u8 min_hfreq_khz; +	u8 max_hfreq_khz; +	u8 pixel_clock_mhz; /* need to multiply by 10 */ +	u16 sec_gtf_toggle; /* A000=use above, 20=use below */ /* FIXME: byte order */ +	u8 hfreq_start_khz; /* need to multiply by 2 */ +	u8 c; /* need to divide by 2 */ +	u16 m; /* FIXME: byte order */ +	u8 k; +	u8 j; /* need to divide by 2 */ +} __attribute__((packed)); + +struct detailed_data_wpindex { +	u8 white_y_lo:2; +	u8 white_x_lo:2; +	u8 pad:4; +	u8 white_x_hi; +	u8 white_y_hi; +	u8 gamma; /* need to divide by 100 then add 1 */ +} __attribute__((packed)); + +struct detailed_data_color_point { +	u8 windex1; +	u8 wpindex1[3]; +	u8 windex2; +	u8 wpindex2[3]; +} __attribute__((packed)); + +struct detailed_non_pixel { +	u8 pad1; +	u8 type; /* ff=serial, fe=string, fd=monitor range, fc=monitor name +		    fb=color point data, fa=standard timing data, +		    f9=undefined, f8=mfg. reserved */ +	u8 pad2; +	union { +		struct detailed_data_string str; +		struct detailed_data_monitor_range range; +		struct detailed_data_wpindex color; +		struct std_timing timings[5]; +	} data; +} __attribute__((packed)); + +#define EDID_DETAIL_STD_MODES 0xfa +#define EDID_DETAIL_MONITOR_CPDATA 0xfb +#define EDID_DETAIL_MONITOR_NAME 0xfc +#define EDID_DETAIL_MONITOR_RANGE 0xfd +#define EDID_DETAIL_MONITOR_STRING 0xfe +#define EDID_DETAIL_MONITOR_SERIAL 0xff + +struct detailed_timing { +	u16 pixel_clock; /* need to multiply by 10 KHz */ /* FIXME: byte order */ +	union { +		struct detailed_pixel_timing pixel_data; +		struct detailed_non_pixel other_data; +	} data; +} __attribute__((packed)); + +struct edid { +	u8 header[8]; +	/* Vendor & product info */ +	u16 mfg_id; /* FIXME: byte order */ +	u16 prod_code; /* FIXME: byte order */ +	u32 serial; /* FIXME: byte order */ +	u8 mfg_week; +	u8 mfg_year; +	/* EDID version */ +	u8 version; +	u8 revision; +	/* Display info: */ +	/*   input definition */ +	u8 serration_vsync:1; +	u8 sync_on_green:1; +	u8 composite_sync:1; +	u8 separate_syncs:1; +	u8 blank_to_black:1; +	u8 video_level:2; +	u8 digital:1; /* bits below must be zero if set */ +	u8 width_cm; +	u8 height_cm; +	u8 gamma; +	/*   feature support */ +	u8 default_gtf:1; +	u8 preferred_timing:1; +	u8 standard_color:1; +	u8 display_type:2; /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */ +	u8 pm_active_off:1; +	u8 pm_suspend:1; +	u8 pm_standby:1; +	/* Color characteristics */ +	u8 red_green_lo; +	u8 black_white_lo; +	u8 red_x; +	u8 red_y; +	u8 green_x; +	u8 green_y; +	u8 blue_x; +	u8 blue_y; +	u8 white_x; +	u8 white_y; +	/* Est. timings and mfg rsvd timings*/ +	struct est_timings established_timings; +	/* Standard timings 1-8*/ +	struct std_timing standard_timings[8]; +	/* Detailing timings 1-4 */ +	struct detailed_timing detailed_timings[4]; +	/* Number of 128 byte ext. blocks */ +	u8 extensions; +	/* Checksum */ +	u8 checksum; +} __attribute__((packed)); + +#endif /* __DRM_EDID_H__ */ diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c new file mode 100644 index 00000000..775fd180 --- /dev/null +++ b/linux-core/drm_fb.c @@ -0,0 +1,435 @@ +/* + * Copyright © 2007 David Airlie + * + * 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: + *     David Airlie + */ +    /* +     *  Modularization +     */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/init.h> + +#include "drmP.h" +#include "drm_crtc.h" + +struct drmfb_par { +	struct drm_device *dev; +	struct drm_crtc *crtc; +}; + +static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green, +			   unsigned blue, unsigned transp, +			   struct fb_info *info) +{ +	struct drmfb_par *par = info->par; +	struct drm_framebuffer *fb = par->crtc->fb; +	struct drm_crtc *crtc = par->crtc; + +	if (regno > 255) +		return 1; + +	if (fb->depth == 8) { +		if (crtc->funcs->gamma_set) { +			crtc->funcs->gamma_set(crtc, red, green, blue, regno); +		} +		return 0; +	} +	 + 	if (regno < 16) { +		switch (fb->depth) { +		case 15: +			fb->pseudo_palette[regno] = ((red & 0xf800) >>  1) | +				((green & 0xf800) >>  6) | +				((blue & 0xf800) >> 11); +			break; +		case 16: +			fb->pseudo_palette[regno] = (red & 0xf800) | +				((green & 0xfc00) >>  5) | +				((blue  & 0xf800) >> 11); +			break; +		case 24: +		case 32: +			fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | +				(green & 0xff00) | +				((blue  & 0xff00) >> 8); +			break; +		} +        } + +	return 0; +} + +static int drmfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ +	struct drmfb_par *par = info->par; +	struct drm_device *dev = par->dev; +	struct drm_framebuffer *fb = par->crtc->fb; +	struct drm_display_mode *drm_mode; +	struct drm_output *output; +	int depth; + +	if (!var->pixclock) +		return -EINVAL; + +	/* Need to resize the fb object !!! */ +	if (var->xres > fb->width || var->yres > fb->height) { +		DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height); +		DRM_ERROR("Need resizing code.\n"); +		return -EINVAL; +	} + +	switch (var->bits_per_pixel) { +	case 16: +		depth = (var->green.length == 6) ? 16 : 15; +		break; +	case 32: +		depth = (var->transp.length > 0) ? 32 : 24; +		break; +	default: +		depth = var->bits_per_pixel; +		break; +	} +		 +	switch (depth) { +	case 8: +		var->red.offset = 0; +		var->green.offset = 0; +		var->blue.offset = 0; +		var->red.length = 8; +		var->green.length = 8; +		var->blue.length = 8; +		var->transp.length = 0; +		var->transp.offset = 0; +		break; +	case 15: +		var->red.offset = 10; +		var->green.offset = 5; +		var->blue.offset = 0; +		var->red.length = 5; +		var->green.length = 5; +		var->blue.length = 5; +		var->transp.length = 1; +		var->transp.offset = 15; +		break; +	case 16: +		var->red.offset = 11; +		var->green.offset = 6; +		var->blue.offset = 0; +		var->red.length = 5; +		var->green.length = 6; +		var->blue.length = 5; +		var->transp.length = 0; +		var->transp.offset = 0; +		break; +	case 24: +		var->red.offset = 16; +		var->green.offset = 8; +		var->blue.offset = 0; +		var->red.length = 8; +		var->green.length = 8; +		var->blue.length = 8; +		var->transp.length = 0; +		var->transp.offset = 0; +		break; +	case 32: +		var->red.offset = 16; +		var->green.offset = 8; +		var->blue.offset = 0; +		var->red.length = 8; +		var->green.length = 8; +		var->blue.length = 8; +		var->transp.length = 8; +		var->transp.offset = 24; +		break; +	default: +		return -EINVAL;	 +	} + +#if 0 +	/* Here we walk the output mode list and look for modes. If we haven't +	 * got it, then bail. Not very nice, so this is disabled. +	 * In the set_par code, we create our mode based on the incoming +	 * parameters. Nicer, but may not be desired by some. +	 */ +	list_for_each_entry(output, &dev->mode_config.output_list, head) { +		if (output->crtc == par->crtc) +			break; +	} +     +	list_for_each_entry(drm_mode, &output->modes, head) { +		if (drm_mode->hdisplay == var->xres && +		    drm_mode->vdisplay == var->yres && +		    drm_mode->clock != 0) +		    break; +	} + +	if (!drm_mode) +		return -EINVAL; +#endif + +	return 0; +} + +/* this will let fbcon do the mode init */ +static int drmfb_set_par(struct fb_info *info) +{ +	struct drmfb_par *par = info->par; +	struct drm_framebuffer *fb = par->crtc->fb; +	struct drm_device *dev = par->dev; +	struct drm_display_mode *drm_mode; +	struct fb_var_screeninfo *var = &info->var; +	struct drm_output *output; + +	switch (var->bits_per_pixel) { +	case 16: +		fb->depth = (var->green.length == 6) ? 16 : 15; +		break; +	case 32: +		fb->depth = (var->transp.length > 0) ? 32 : 24; +		break; +	default: +		fb->depth = var->bits_per_pixel; +		break; +	} + +	fb->bits_per_pixel = var->bits_per_pixel; + +	info->fix.line_length = fb->pitch; +	info->fix.smem_len = info->fix.line_length * fb->height; +	info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + +	info->screen_size = info->fix.smem_len; /* ??? */ + +	/* Should we walk the output's modelist or just create our own ??? +	 * For now, we create and destroy a mode based on the incoming  +	 * parameters. But there's commented out code below which scans  +	 * the output list too. +	 */ +#if 0 +	list_for_each_entry(output, &dev->mode_config.output_list, head) { +		if (output->crtc == par->crtc) +			break; +	} +     +	list_for_each_entry(drm_mode, &output->modes, head) { +		if (drm_mode->hdisplay == var->xres && +		    drm_mode->vdisplay == var->yres && +		    drm_mode->clock != 0) +		    break; +	} +#else +	drm_mode = drm_mode_create(dev); +	drm_mode->hdisplay = var->xres; +	drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin; +	drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len; +	drm_mode->htotal = drm_mode->hsync_end + var->left_margin; +	drm_mode->vdisplay = var->yres; +	drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin; +	drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len; +	drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin; +	drm_mode->clock = PICOS2KHZ(var->pixclock); +	drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); +	drm_mode_set_name(drm_mode); +	drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); +#endif + +	if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) +		return -EINVAL; + +	/* Have to destroy our created mode if we're not searching the mode +	 * list for it. +	 */ +#if 1  +	drm_mode_destroy(dev, drm_mode); +#endif + +	return 0; +} + +static struct fb_ops drmfb_ops = { +	.owner = THIS_MODULE, +	//	.fb_open = drmfb_open, +	//	.fb_read = drmfb_read, +	//	.fb_write = drmfb_write, +	//	.fb_release = drmfb_release, +	//	.fb_ioctl = drmfb_ioctl, +	.fb_check_var = drmfb_check_var, +	.fb_set_par = drmfb_set_par, +	.fb_setcolreg = drmfb_setcolreg, +	.fb_fillrect = cfb_fillrect, +	.fb_copyarea = cfb_copyarea, +	.fb_imageblit = cfb_imageblit, +}; + +int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc) +{ +	struct fb_info *info; +	struct drm_framebuffer *fb = crtc->fb; +	struct drmfb_par *par; +	struct device *device = &dev->pdev->dev;  +	struct drm_display_mode *mode = crtc->desired_mode; +	int ret; + +	info = framebuffer_alloc(sizeof(struct drmfb_par), device); +	if (!info) +		return -ENOMEM; + +	fb->fbdev = info; +		 +	par = info->par; + +	par->dev = dev; +	par->crtc = crtc; + +	info->fbops = &drmfb_ops; + +	strcpy(info->fix.id, "drmfb"); +	info->fix.type = FB_TYPE_PACKED_PIXELS; +	info->fix.visual = FB_VISUAL_TRUECOLOR; +	info->fix.accel = FB_ACCEL_NONE; +	info->fix.type_aux = 0; +	info->fix.mmio_start = 0; +	info->fix.mmio_len = 0; +	info->fix.line_length = fb->pitch; +	info->fix.smem_start = fb->offset + dev->mode_config.fb_base; +	info->fix.smem_len = info->fix.line_length * fb->height; + +	info->flags = FBINFO_DEFAULT; + +	ret = drm_mem_reg_ioremap(dev, &fb->bo->mem, &fb->virtual_base); +	if (ret) +		DRM_ERROR("error mapping fb: %d\n", ret); + +	info->screen_base = fb->virtual_base; +	info->screen_size = info->fix.smem_len; /* ??? */ +	info->pseudo_palette = fb->pseudo_palette; +	info->var.xres_virtual = fb->width; +	info->var.yres_virtual = fb->height; +	info->var.bits_per_pixel = fb->bits_per_pixel; +	info->var.xoffset = 0; +	info->var.yoffset = 0; +	info->var.activate = FB_ACTIVATE_NOW; +	info->var.height = -1; +	info->var.width = -1; +	info->var.vmode = FB_VMODE_NONINTERLACED; + +	info->var.xres = mode->hdisplay; +	info->var.right_margin = mode->hsync_start - mode->hdisplay; +	info->var.hsync_len = mode->hsync_end - mode->hsync_start; +	info->var.left_margin = mode->htotal - mode->hsync_end; +	info->var.yres = mode->vdisplay; +	info->var.lower_margin = mode->vsync_start - mode->vdisplay; +	info->var.vsync_len = mode->vsync_end - mode->vsync_start; +	info->var.upper_margin = mode->vtotal - mode->vsync_end; +	info->var.pixclock = 10000000 / mode->htotal * 1000 / +				mode->vtotal * 100; +	/* avoid overflow */ +	info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; + +	DRM_DEBUG("fb depth is %d\n", fb->depth); +	switch(fb->depth) { +	case 8: +		info->var.red.offset = 0; +		info->var.green.offset = 0; +		info->var.blue.offset = 0; +		info->var.red.length = 8; /* 8bit DAC */ +		info->var.green.length = 8; +		info->var.blue.length = 8; +		info->var.transp.offset = 0; +		info->var.transp.length = 0; +		break; +	case 15: +		info->var.red.offset = 10; +		info->var.green.offset = 5; +		info->var.blue.offset = 0; +		info->var.red.length = info->var.green.length = +			info->var.blue.length = 5; +		info->var.transp.offset = 15; +		info->var.transp.length = 1; +		break; +	case 16: +		info->var.red.offset = 11; +		info->var.green.offset = 5; +		info->var.blue.offset = 0; +		info->var.red.length = 5; +		info->var.green.length = 6; +		info->var.blue.length = 5; +		info->var.transp.offset = 0; +		info->var.transp.length = 0; +		break; +	case 24: +		info->var.red.offset = 16; +		info->var.green.offset = 8; +		info->var.blue.offset = 0; +		info->var.red.length = info->var.green.length = +			info->var.blue.length = 8; +		info->var.transp.offset = 0; +		info->var.transp.length = 0; +		break; +	case 32: +		info->var.red.offset = 16; +		info->var.green.offset = 8; +		info->var.blue.offset = 0; +		info->var.red.length = info->var.green.length = +			info->var.blue.length = 8; +		info->var.transp.offset = 24; +		info->var.transp.length = 8; +		break; +	default: +		break; +	} + +	if (register_framebuffer(info) < 0) { +		unregister_framebuffer(info); +		return -EINVAL; +	} + +	printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, +	       info->fix.id); +	return 0; +} +EXPORT_SYMBOL(drmfb_probe); + +int drmfb_remove(struct drm_device *dev, struct drm_crtc *crtc) +{ +	struct fb_info *info = fb->fbdev; +	struct drm_framebuffer *fb = crtc->fb; +	 +	if (info) { +		drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base); +		unregister_framebuffer(info); +		framebuffer_release(info); +	} +	return 0; +} +EXPORT_SYMBOL(drmfb_remove); +MODULE_LICENSE("GPL"); diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 247bc0a4..9d80327f 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -494,7 +494,7 @@ static int drm_fence_object_init(struct drm_device *dev, uint32_t fence_class,  int drm_fence_add_user_object(struct drm_file *priv,  			      struct drm_fence_object *fence, int shareable)  { -	struct drm_device *dev = priv->head->dev; +	struct drm_device *dev = priv->minor->dev;  	int ret;  	mutex_lock(&dev->struct_mutex); @@ -590,7 +590,7 @@ void drm_fence_manager_takedown(struct drm_device *dev)  struct drm_fence_object *drm_lookup_fence_object(struct drm_file *priv,  						 uint32_t handle)  { -	struct drm_device *dev = priv->head->dev; +	struct drm_device *dev = priv->minor->dev;  	struct drm_user_object *uo;  	struct drm_fence_object *fence; diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 0e1c486c..5a74f424 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -43,10 +43,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp,  static int drm_setup(struct drm_device * dev)  { -	drm_local_map_t *map;  	int i;  	int ret; -	int sareapage;  	if (dev->driver->firstopen) {  		ret = dev->driver->firstopen(dev); @@ -54,14 +52,6 @@ static int drm_setup(struct drm_device * dev)  			return ret;  	} -	dev->magicfree.next = NULL; - -	/* prebuild the SAREA */ -	sareapage = max(SAREA_MAX, PAGE_SIZE); -	i = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, &map); -	if (i != 0) -		return i; -  	atomic_set(&dev->ioctl_count, 0);  	atomic_set(&dev->vma_count, 0);  	dev->buf_use = 0; @@ -76,11 +66,8 @@ static int drm_setup(struct drm_device * dev)  	for (i = 0; i < ARRAY_SIZE(dev->counts); i++)  		atomic_set(&dev->counts[i], 0); -	drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER); -	INIT_LIST_HEAD(&dev->magicfree); -  	dev->sigdata.lock = NULL; -	init_waitqueue_head(&dev->lock.lock_queue); +  	dev->queue_count = 0;  	dev->queue_reserved = 0;  	dev->queue_slots = 0; @@ -128,16 +115,15 @@ static int drm_setup(struct drm_device * dev)  int drm_open(struct inode *inode, struct file *filp)  {  	struct drm_device *dev = NULL; -	int minor = iminor(inode); +	int minor_id = iminor(inode); +	struct drm_minor *minor;  	int retcode = 0; -	if (!((minor >= 0) && (minor < drm_cards_limit))) -		return -ENODEV; - -	if (!drm_heads[minor]) +	minor = idr_find(&drm_minors_idr, minor_id); +	if (!minor)  		return -ENODEV; -	if (!(dev = drm_heads[minor]->dev)) +	if (!(dev = minor->dev))  		return -ENODEV;  	retcode = drm_open_helper(inode, filp, dev); @@ -176,19 +162,18 @@ EXPORT_SYMBOL(drm_open);  int drm_stub_open(struct inode *inode, struct file *filp)  {  	struct drm_device *dev = NULL; -	int minor = iminor(inode); +	struct drm_minor *minor; +	int minor_id = iminor(inode);  	int err = -ENODEV;  	const struct file_operations *old_fops;  	DRM_DEBUG("\n"); -	if (!((minor >= 0) && (minor < drm_cards_limit))) +	minor = idr_find(&drm_minors_idr, minor_id); +	if (!minor)  		return -ENODEV; - -	if (!drm_heads[minor]) -		return -ENODEV; - -	if (!(dev = drm_heads[minor]->dev)) +	 +	if (!(dev = minor->dev))  		return -ENODEV;  	old_fops = filp->f_op; @@ -233,7 +218,7 @@ static int drm_cpu_valid(void)  static int drm_open_helper(struct inode *inode, struct file *filp,  			   struct drm_device * dev)  { -	int minor = iminor(inode); +	int minor_id = iminor(inode);  	struct drm_file *priv;  	int ret;  	int i, j; @@ -243,7 +228,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,  	if (!drm_cpu_valid())  		return -EINVAL; -	DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor); +	DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor_id);  	priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES);  	if (!priv) @@ -254,8 +239,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,  	priv->filp = filp;  	priv->uid = current->euid;  	priv->pid = current->pid; -	priv->minor = minor; -	priv->head = drm_heads[minor]; +	priv->minor = idr_find(&drm_minors_idr, minor_id);  	priv->ioctl_count = 0;  	/* for compatibility root is always authenticated */  	priv->authenticated = capable(CAP_SYS_ADMIN); @@ -263,6 +247,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,  	INIT_LIST_HEAD(&priv->lhead);  	INIT_LIST_HEAD(&priv->refd_objects); +	INIT_LIST_HEAD(&priv->fbs);  	for (i = 0; i < _DRM_NO_REF_TYPES; ++i) {  		ret = drm_ht_create(&priv->refd_object_hash[i], @@ -283,10 +268,35 @@ static int drm_open_helper(struct inode *inode, struct file *filp,  			goto out_free;  	} + +	/* if there is no current master make this fd it */  	mutex_lock(&dev->struct_mutex); -	if (list_empty(&dev->filelist)) -		priv->master = 1; +	if (!priv->minor->master) { +		priv->minor->master = drm_get_master(priv->minor); +		if (!priv->minor->master) { +			ret = -ENOMEM; +			goto out_free; +		} +		priv->is_master = 1; +		priv->master = priv->minor->master; + +		mutex_unlock(&dev->struct_mutex); +		if (dev->driver->master_create) { +			ret = dev->driver->master_create(dev, priv->master); +			if (ret) { +				drm_put_master(priv->minor->master); +				priv->minor->master = priv->master = NULL; +				mutex_unlock(&dev->struct_mutex); +				goto out_free; +			} +		} +	} else { +		priv->master = priv->minor->master; +		mutex_unlock(&dev->struct_mutex); +	} + +	mutex_lock(&dev->struct_mutex);  	list_add(&priv->lhead, &dev->filelist);  	mutex_unlock(&dev->struct_mutex); @@ -320,11 +330,11 @@ static int drm_open_helper(struct inode *inode, struct file *filp,  int drm_fasync(int fd, struct file *filp, int on)  {  	struct drm_file *priv = filp->private_data; -	struct drm_device *dev = priv->head->dev; +	struct drm_device *dev = priv->minor->dev;  	int retcode;  	DRM_DEBUG("fd = %d, device = 0x%lx\n", fd, -		  (long)old_encode_dev(priv->head->device)); +		  (long)old_encode_dev(priv->minor->device));  	retcode = fasync_helper(fd, filp, on, &dev->buf_async);  	if (retcode < 0)  		return retcode; @@ -374,7 +384,7 @@ static void drm_object_release(struct file *filp)  int drm_release(struct inode *inode, struct file *filp)  {  	struct drm_file *file_priv = filp->private_data; -	struct drm_device *dev = file_priv->head->dev; +	struct drm_device *dev = file_priv->minor->dev;  	int retcode = 0;  	lock_kernel(); @@ -389,26 +399,26 @@ int drm_release(struct inode *inode, struct file *filp)  	 */  	DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", -		  current->pid, (long)old_encode_dev(file_priv->head->device), +		  current->pid, (long)old_encode_dev(file_priv->minor->device),  		  dev->open_count); -	if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) { +	if (dev->driver->reclaim_buffers_locked && file_priv->master->lock.hw_lock) {  		if (drm_i_have_hw_lock(dev, file_priv)) {  			dev->driver->reclaim_buffers_locked(dev, file_priv);  		} else {  			unsigned long _end=jiffies + 3*DRM_HZ;  			int locked = 0; -			drm_idlelock_take(&dev->lock); +			drm_idlelock_take(&file_priv->master->lock);  			/*  			 * Wait for a while.  			 */  			do{ -				spin_lock(&dev->lock.spinlock); -				locked = dev->lock.idle_has_lock; -				spin_unlock(&dev->lock.spinlock); +				spin_lock(&file_priv->master->lock.spinlock); +				locked = file_priv->master->lock.idle_has_lock; +				spin_unlock(&file_priv->master->lock.spinlock);  				if (locked)  					break;  				schedule(); @@ -421,24 +431,24 @@ int drm_release(struct inode *inode, struct file *filp)  			}  			dev->driver->reclaim_buffers_locked(dev, file_priv); -			drm_idlelock_release(&dev->lock); +			drm_idlelock_release(&file_priv->master->lock);  		}  	} -	if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) { +	if (dev->driver->reclaim_buffers_idlelocked && file_priv->master->lock.hw_lock) { -		drm_idlelock_take(&dev->lock); +		drm_idlelock_take(&file_priv->master->lock);  		dev->driver->reclaim_buffers_idlelocked(dev, file_priv); -		drm_idlelock_release(&dev->lock); +		drm_idlelock_release(&file_priv->master->lock);  	}  	if (drm_i_have_hw_lock(dev, file_priv)) {  		DRM_DEBUG("File %p released, freeing lock for context %d\n", -			  filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); +			  filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); -		drm_lock_free(&dev->lock, -			      _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); +		drm_lock_free(&file_priv->master->lock, +			      _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));  	} @@ -471,6 +481,15 @@ int drm_release(struct inode *inode, struct file *filp)  	}  	mutex_unlock(&dev->ctxlist_mutex); +	drm_fb_release(filp); + +	file_priv->master = NULL; + +	if (file_priv->is_master) { +	       drm_put_master(file_priv->minor->master); +	       file_priv->minor->master = NULL; +	} +  	mutex_lock(&dev->struct_mutex);  	drm_object_release(filp);  	if (file_priv->remove_auth_on_close == 1) { @@ -480,6 +499,8 @@ int drm_release(struct inode *inode, struct file *filp)  			temp->authenticated = 0;  	}  	list_del(&file_priv->lhead); + +  	mutex_unlock(&dev->struct_mutex);  	if (dev->driver->postclose) @@ -493,9 +514,9 @@ int drm_release(struct inode *inode, struct file *filp)  	atomic_inc(&dev->counts[_DRM_STAT_CLOSES]);  	spin_lock(&dev->count_lock);  	if (!--dev->open_count) { -		if (atomic_read(&dev->ioctl_count) || dev->blocked) { -			DRM_ERROR("Device busy: %d %d\n", -				  atomic_read(&dev->ioctl_count), dev->blocked); +		if (atomic_read(&dev->ioctl_count)) { +			DRM_ERROR("Device busy: %d\n", +				  atomic_read(&dev->ioctl_count));  			spin_unlock(&dev->count_lock);  			unlock_kernel();  			return -EBUSY; diff --git a/linux-core/drm_ioctl.c b/linux-core/drm_ioctl.c index 3df163db..e35126a3 100644 --- a/linux-core/drm_ioctl.c +++ b/linux-core/drm_ioctl.c @@ -53,12 +53,13 @@ int drm_getunique(struct drm_device *dev, void *data,  		  struct drm_file *file_priv)  {  	struct drm_unique *u = data; +	struct drm_master *master = file_priv->master; -	if (u->unique_len >= dev->unique_len) { -		if (copy_to_user(u->unique, dev->unique, dev->unique_len)) +	if (u->unique_len >= master->unique_len) { +		if (copy_to_user(u->unique, master->unique, master->unique_len))  			return -EFAULT;  	} -	u->unique_len = dev->unique_len; +	u->unique_len = master->unique_len;  	return 0;  } @@ -81,36 +82,37 @@ int drm_setunique(struct drm_device *dev, void *data,  		  struct drm_file *file_priv)  {  	struct drm_unique *u = data; +	struct drm_master *master = file_priv->master;  	int domain, bus, slot, func, ret; -	if (dev->unique_len || dev->unique) +	if (master->unique_len || master->unique)  		return -EBUSY;  	if (!u->unique_len || u->unique_len > 1024)  		return -EINVAL; -	dev->unique_len = u->unique_len; -	dev->unique = drm_alloc(u->unique_len + 1, DRM_MEM_DRIVER); -	if (!dev->unique) +	master->unique_len = u->unique_len; +	master->unique = drm_alloc(u->unique_len + 1, DRM_MEM_DRIVER); +	if (!master->unique)  		return -ENOMEM; -	if (copy_from_user(dev->unique, u->unique, dev->unique_len)) +	if (copy_from_user(master->unique, u->unique, master->unique_len))  		return -EFAULT; -	dev->unique[dev->unique_len] = '\0'; +	master->unique[master->unique_len] = '\0';  	dev->devname =  	    drm_alloc(strlen(dev->driver->pci_driver.name) + -		      strlen(dev->unique) + 2, DRM_MEM_DRIVER); +		      strlen(master->unique) + 2, DRM_MEM_DRIVER);  	if (!dev->devname)  		return -ENOMEM;  	sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, -		dev->unique); +		master->unique);  	/* Return error if the busid submitted doesn't match the device's actual  	 * busid.  	 */ -	ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func); +	ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);  	if (ret != 3)  		return -EINVAL;  	domain = bus >> 8; @@ -125,33 +127,35 @@ int drm_setunique(struct drm_device *dev, void *data,  	return 0;  } -static int drm_set_busid(struct drm_device * dev) +static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)  { +	struct drm_master *master = file_priv->master;  	int len; -	if (dev->unique != NULL) + +	if (master->unique != NULL)  		return -EBUSY; -	dev->unique_len = 40; -	dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER); -	if (dev->unique == NULL) +	master->unique_len = 40; +	master->unique = drm_alloc(master->unique_len + 1, DRM_MEM_DRIVER); +	if (master->unique == NULL)  		return -ENOMEM; -	len = snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d", +	len = snprintf(master->unique, master->unique_len, "pci:%04x:%02x:%02x.%d",  		       drm_get_pci_domain(dev),  		       dev->pdev->bus->number,  		       PCI_SLOT(dev->pdev->devfn),  		       PCI_FUNC(dev->pdev->devfn)); -	if (len > dev->unique_len) +	if (len > master->unique_len)  		DRM_ERROR("buffer overflow");  	dev->devname = -	    drm_alloc(strlen(dev->driver->pci_driver.name) + dev->unique_len + +	    drm_alloc(strlen(dev->driver->pci_driver.name) + master->unique_len +  		      2, DRM_MEM_DRIVER);  	if (dev->devname == NULL)  		return -ENOMEM;  	sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, -		dev->unique); +		master->unique);  	return 0;  } @@ -275,7 +279,7 @@ int drm_getstats(struct drm_device *dev, void *data,  	for (i = 0; i < dev->counters; i++) {  		if (dev->types[i] == _DRM_STAT_LOCK)  			stats->data[i].value = -			    (dev->lock.hw_lock ? dev->lock.hw_lock->lock : 0); +			    (file_priv->master->lock.hw_lock ? file_priv->master->lock.hw_lock->lock : 0);  		else  			stats->data[i].value = atomic_read(&dev->counts[i]);  		stats->data[i].type = dev->types[i]; @@ -317,7 +321,7 @@ int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_pri  			/*  			 * Version 1.1 includes tying of DRM to specific device  			 */ -			drm_set_busid(dev); +			drm_set_busid(dev, file_priv);  		}  	} diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index e4940bb7..cb279bcd 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -197,7 +197,7 @@ int drm_irq_install(struct drm_device * dev)  	if (dev->irq_enabled) {  		mutex_unlock(&dev->struct_mutex); -		return -EBUSY; +		return 0;  	}  	dev->irq_enabled = 1;  	mutex_unlock(&dev->struct_mutex); @@ -655,18 +655,18 @@ static void drm_locked_tasklet_func(unsigned long data)  	spin_lock_irqsave(&dev->tasklet_lock, irqflags);  	if (!dev->locked_tasklet_func || -	    !drm_lock_take(&dev->lock, +	    !drm_lock_take(&dev->primary->master->lock,  			   DRM_KERNEL_CONTEXT)) {  		spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);  		return;  	} -	dev->lock.lock_time = jiffies; +	dev->primary->master->lock.lock_time = jiffies;  	atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);  	dev->locked_tasklet_func(dev); -	drm_lock_free(&dev->lock, +	drm_lock_free(&dev->primary->master->lock,  		      DRM_KERNEL_CONTEXT);  	dev->locked_tasklet_func = NULL; diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index b8e4a5d9..08e063d8 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -52,6 +52,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)  {  	DECLARE_WAITQUEUE(entry, current);  	struct drm_lock *lock = data; +	struct drm_master *master = file_priv->master;  	int ret = 0;  	++file_priv->lock_count; @@ -64,26 +65,26 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)  	DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",  		  lock->context, current->pid, -		  dev->lock.hw_lock->lock, lock->flags); +		  master->lock.hw_lock->lock, lock->flags);  	if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE))  		if (lock->context < 0)  			return -EINVAL; -	add_wait_queue(&dev->lock.lock_queue, &entry); -	spin_lock(&dev->lock.spinlock); -	dev->lock.user_waiters++; -	spin_unlock(&dev->lock.spinlock); +	add_wait_queue(&master->lock.lock_queue, &entry); +	spin_lock(&master->lock.spinlock); +	master->lock.user_waiters++; +	spin_unlock(&master->lock.spinlock);  	for (;;) {  		__set_current_state(TASK_INTERRUPTIBLE); -		if (!dev->lock.hw_lock) { +		if (!master->lock.hw_lock) {  			/* Device has been unregistered */  			ret = -EINTR;  			break;  		} -		if (drm_lock_take(&dev->lock, lock->context)) { -			dev->lock.file_priv = file_priv; -			dev->lock.lock_time = jiffies; +		if (drm_lock_take(&master->lock, lock->context)) { +			master->lock.file_priv = file_priv; +			master->lock.lock_time = jiffies;  			atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);  			break;	/* Got lock */  		} @@ -95,11 +96,11 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)  			break;  		}  	} -	spin_lock(&dev->lock.spinlock); -	dev->lock.user_waiters--; -	spin_unlock(&dev->lock.spinlock); +	spin_lock(&master->lock.spinlock); +	master->lock.user_waiters--; +	spin_unlock(&master->lock.spinlock);  	__set_current_state(TASK_RUNNING); -	remove_wait_queue(&dev->lock.lock_queue, &entry); +	remove_wait_queue(&master->lock.lock_queue, &entry);  	DRM_DEBUG("%d %s\n", lock->context,  		  ret ? "interrupted" : "has lock"); @@ -111,7 +112,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)  	sigaddset(&dev->sigmask, SIGTTIN);  	sigaddset(&dev->sigmask, SIGTTOU);  	dev->sigdata.context = lock->context; -	dev->sigdata.lock = dev->lock.hw_lock; +	dev->sigdata.lock = master->lock.hw_lock;  	block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);  	if (dev->driver->dma_ready && (lock->flags & _DRM_LOCK_READY)) @@ -149,6 +150,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)  int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)  {  	struct drm_lock *lock = data; +	struct drm_master *master = file_priv->master;  	unsigned long irqflags;  	if (lock->context == DRM_KERNEL_CONTEXT) { @@ -175,7 +177,7 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)  	if (dev->driver->kernel_context_switch_unlock)  		dev->driver->kernel_context_switch_unlock(dev);  	else { -		if (drm_lock_free(&dev->lock,lock->context)) { +		if (drm_lock_free(&master->lock,lock->context)) {  			/* FIXME: Should really bail out here. */  		}  	} @@ -384,10 +386,10 @@ EXPORT_SYMBOL(drm_idlelock_release);  int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv)  { - -	return (file_priv->lock_count && dev->lock.hw_lock && -		_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && -		dev->lock.file_priv == file_priv); +	struct drm_master *master = file_priv->master; +	return (file_priv->lock_count && master->lock.hw_lock && +		_DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) && +		master->lock.file_priv == file_priv);  }  EXPORT_SYMBOL(drm_i_have_hw_lock); diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index 59110293..28726a65 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -294,3 +294,18 @@ void drm_mm_takedown(struct drm_mm * mm)  }  EXPORT_SYMBOL(drm_mm_takedown); + +void drm_mm_print(struct drm_mm *mm, const char *name) +{ +	struct list_head *list; +	const struct list_head *mm_stack = &mm->ml_entry; +	struct drm_mm_node *entry; + +	DRM_DEBUG("Memory usage for '%s'\n", name ? name : "unknown"); +	list_for_each(list, mm_stack) { +		entry = list_entry(list, struct drm_mm_node, ml_entry); +		DRM_DEBUG("\t0x%08lx %li %s pages\n", entry->start, entry->size, +			entry->free ? "free" : "used"); +	} +} +EXPORT_SYMBOL(drm_mm_print); diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c new file mode 100644 index 00000000..3763ca69 --- /dev/null +++ b/linux-core/drm_modes.c @@ -0,0 +1,560 @@ +/* + * Copyright © 1997-2003 by The XFree86 Project, Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ +/* + * Copyright © 2007 Dave Airlie + */ + +#include <linux/list.h> +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" + +/** + * drm_mode_debug_printmodeline - debug print a mode + * @dev: DRM device + * @mode: mode to print + * + * LOCKING: + * None. + * + * Describe @mode using DRM_DEBUG. + */ +void drm_mode_debug_printmodeline(struct drm_device *dev, +				  struct drm_display_mode *mode) +{ +	DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", +		  mode->mode_id, mode->name, mode->vrefresh, mode->clock, +		  mode->hdisplay, mode->hsync_start, +		  mode->hsync_end, mode->htotal, +		  mode->vdisplay, mode->vsync_start, +		  mode->vsync_end, mode->vtotal, mode->type, mode->flags); +} +EXPORT_SYMBOL(drm_mode_debug_printmodeline); + +/** + * drm_mode_set_name - set the name on a mode + * @mode: name will be set in this mode + * + * LOCKING: + * None. + * + * Set the name of @mode to a standard format. + */ +void drm_mode_set_name(struct drm_display_mode *mode) +{ +	snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d", mode->hdisplay, +		 mode->vdisplay); +} +EXPORT_SYMBOL(drm_mode_set_name); + +/** + * drm_mode_list_concat - move modes from one list to another + * @head: source list + * @new: dst list + * + * LOCKING: + * Caller must ensure both lists are locked. + * + * Move all the modes from @head to @new. + */ +void drm_mode_list_concat(struct list_head *head, struct list_head *new) +{ + +	struct list_head *entry, *tmp; + +	list_for_each_safe(entry, tmp, head) { +		list_move_tail(entry, new); +	} +} + +/** + * drm_mode_width - get the width of a mode + * @mode: mode + * + * LOCKING: + * None. + * + * Return @mode's width (hdisplay) value. + * + * FIXME: is this needed? + * + * RETURNS: + * @mode->hdisplay + */ +int drm_mode_width(struct drm_display_mode *mode) +{ +	return mode->hdisplay; + +} +EXPORT_SYMBOL(drm_mode_width); + +/** + * drm_mode_height - get the height of a mode + * @mode: mode + * + * LOCKING: + * None. + * + * Return @mode's height (vdisplay) value. + * + * FIXME: is this needed? + * + * RETURNS: + * @mode->vdisplay + */ +int drm_mode_height(struct drm_display_mode *mode) +{ +	return mode->vdisplay; +} +EXPORT_SYMBOL(drm_mode_height); + +/** + * drm_mode_vrefresh - get the vrefresh of a mode + * @mode: mode + * + * LOCKING: + * None. + * + * Return @mode's vrefresh rate or calculate it if necessary. + * + * FIXME: why is this needed?  shouldn't vrefresh be set already? + * + * RETURNS: + * Vertical refresh rate of @mode x 1000. For precision reasons. + */ +int drm_mode_vrefresh(struct drm_display_mode *mode) +{ +	int refresh = 0; +	unsigned int calc_val; + +	if (mode->vrefresh > 0) +		refresh = mode->vrefresh; +	else if (mode->htotal > 0 && mode->vtotal > 0) { +		/* work out vrefresh the value will be x1000 */ +		calc_val = (mode->clock * 1000); + +		calc_val /= mode->htotal; +		calc_val *= 1000; +		calc_val /= mode->vtotal; + +		refresh = calc_val; +		if (mode->flags & V_INTERLACE) +			refresh *= 2; +		if (mode->flags & V_DBLSCAN) +			refresh /= 2; +		if (mode->vscan > 1) +			refresh /= mode->vscan; +	} +	return refresh; +} +EXPORT_SYMBOL(drm_mode_vrefresh); +	 +/** + * drm_mode_set_crtcinfo - set CRTC modesetting parameters + * @p: mode + * @adjust_flags: unused? (FIXME) + * + * LOCKING: + * None. + * + * Setup the CRTC modesetting parameters for @p, adjusting if necessary. + */ +void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) +{ +	if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN)) +		return; + +	p->crtc_hdisplay = p->hdisplay; +	p->crtc_hsync_start = p->hsync_start; +	p->crtc_hsync_end = p->hsync_end; +	p->crtc_htotal = p->htotal; +	p->crtc_hskew = p->hskew; +	p->crtc_vdisplay = p->vdisplay; +	p->crtc_vsync_start = p->vsync_start; +	p->crtc_vsync_end = p->vsync_end; +	p->crtc_vtotal = p->vtotal; + +	if (p->flags & V_INTERLACE) { +		if (adjust_flags & CRTC_INTERLACE_HALVE_V) { +			p->crtc_vdisplay /= 2; +			p->crtc_vsync_start /= 2; +			p->crtc_vsync_end /= 2; +			p->crtc_vtotal /= 2; +		} + +		p->crtc_vtotal |= 1; +	} + +	if (p->flags & V_DBLSCAN) { +		p->crtc_vdisplay *= 2; +		p->crtc_vsync_start *= 2; +		p->crtc_vsync_end *= 2; +		p->crtc_vtotal *= 2; +	} + +	if (p->vscan > 1) { +		p->crtc_vdisplay *= p->vscan; +		p->crtc_vsync_start *= p->vscan; +		p->crtc_vsync_end *= p->vscan; +		p->crtc_vtotal *= p->vscan; +	} + +	p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay); +	p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal); +	p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay); +	p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal); + +	p->crtc_hadjusted = false; +	p->crtc_vadjusted = false; +} +EXPORT_SYMBOL(drm_mode_set_crtcinfo); + + +/** + * drm_mode_duplicate - allocate and duplicate an existing mode + * @m: mode to duplicate + * + * LOCKING: + * None. + * + * Just allocate a new mode, copy the existing mode into it, and return + * a pointer to it.  Used to create new instances of established modes. + */ +struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, +					    struct drm_display_mode *mode) +{ +	struct drm_display_mode *nmode; +	int new_id; + +	nmode = drm_mode_create(dev); +	if (!nmode) +		return NULL; + +	new_id = nmode->mode_id; +	*nmode = *mode; +	nmode->mode_id = new_id; +	INIT_LIST_HEAD(&nmode->head); +	return nmode; +} +EXPORT_SYMBOL(drm_mode_duplicate); + +/** + * drm_mode_equal - test modes for equality + * @mode1: first mode + * @mode2: second mode + * + * LOCKING: + * None. + * + * Check to see if @mode1 and @mode2 are equivalent. + * + * RETURNS: + * True if the modes are equal, false otherwise. + */ +bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2) +{ +	if (mode1->clock == mode2->clock && +	    mode1->hdisplay == mode2->hdisplay && +	    mode1->hsync_start == mode2->hsync_start && +	    mode1->hsync_end == mode2->hsync_end && +	    mode1->htotal == mode2->htotal && +	    mode1->hskew == mode2->hskew && +	    mode1->vdisplay == mode2->vdisplay && +	    mode1->vsync_start == mode2->vsync_start && +	    mode1->vsync_end == mode2->vsync_end && +	    mode1->vtotal == mode2->vtotal && +	    mode1->vscan == mode2->vscan && +	    mode1->flags == mode2->flags) +		return true; +	 +	return false; +} +EXPORT_SYMBOL(drm_mode_equal); + +/** + * drm_mode_validate_size - make sure modes adhere to size constraints + * @dev: DRM device + * @mode_list: list of modes to check + * @maxX: maximum width + * @maxY: maximum height + * @maxPitch: max pitch + * + * LOCKING: + * Caller must hold a lock protecting @mode_list. + * + * The DRM device (@dev) has size and pitch limits.  Here we validate the + * modes we probed for @dev against those limits and set their status as + * necessary. + */ +void drm_mode_validate_size(struct drm_device *dev, +			    struct list_head *mode_list, +			    int maxX, int maxY, int maxPitch) +{ +	struct drm_display_mode *mode; + +	list_for_each_entry(mode, mode_list, head) { +		if (maxPitch > 0 && mode->hdisplay > maxPitch) +			mode->status = MODE_BAD_WIDTH; +		 +		if (maxX > 0 && mode->hdisplay > maxX) +			mode->status = MODE_VIRTUAL_X; + +		if (maxY > 0 && mode->vdisplay > maxY) +			mode->status = MODE_VIRTUAL_Y; +	} +} +EXPORT_SYMBOL(drm_mode_validate_size); + +/** + * drm_mode_validate_clocks - validate modes against clock limits + * @dev: DRM device + * @mode_list: list of modes to check + * @min: minimum clock rate array + * @max: maximum clock rate array + * @n_ranges: number of clock ranges (size of arrays) + * + * LOCKING: + * Caller must hold a lock protecting @mode_list. + * + * Some code may need to check a mode list against the clock limits of the + * device in question.  This function walks the mode list, testing to make + * sure each mode falls within a given range (defined by @min and @max + * arrays) and sets @mode->status as needed. + */ +void drm_mode_validate_clocks(struct drm_device *dev, +			      struct list_head *mode_list, +			      int *min, int *max, int n_ranges) +{ +	struct drm_display_mode *mode; +	int i; + +	list_for_each_entry(mode, mode_list, head) { +		bool good = false; +		for (i = 0; i < n_ranges; i++) { +			if (mode->clock >= min[i] && mode->clock <= max[i]) { +				good = true; +				break; +			} +		} +		if (!good) +			mode->status = MODE_CLOCK_RANGE; +	} +} +EXPORT_SYMBOL(drm_mode_validate_clocks); + +/** + * drm_mode_prune_invalid - remove invalid modes from mode list + * @dev: DRM device + * @mode_list: list of modes to check + * @verbose: be verbose about it + * + * LOCKING: + * Caller must hold a lock protecting @mode_list. + * + * Once mode list generation is complete, a caller can use this routine to + * remove invalid modes from a mode list.  If any of the modes have a + * status other than %MODE_OK, they are removed from @mode_list and freed. + */ +void drm_mode_prune_invalid(struct drm_device *dev, +			    struct list_head *mode_list, bool verbose) +{ +	struct drm_display_mode *mode, *t; + +	list_for_each_entry_safe(mode, t, mode_list, head) { +		if (mode->status != MODE_OK) { +			list_del(&mode->head); +			if (verbose) { +				drm_mode_debug_printmodeline(dev, mode); +				DRM_DEBUG("Not using %s mode %d\n", mode->name, mode->status); +			} +			kfree(mode); +		} +	} +} + +/** + * drm_mode_compare - compare modes for favorability + * @lh_a: list_head for first mode + * @lh_b: list_head for second mode + * + * LOCKING: + * None. + * + * Compare two modes, given by @lh_a and @lh_b, returning a value indicating + * which is better. + * + * RETURNS: + * Negative if @lh_a is better than @lh_b, zero if they're equivalent, or + * positive if @lh_b is better than @lh_a. + */ +static int drm_mode_compare(struct list_head *lh_a, struct list_head *lh_b) +{ +	struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head); +	struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head); +	int diff; + +	diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) - +		((a->type & DRM_MODE_TYPE_PREFERRED) != 0); +	if (diff) +		return diff; +	diff = b->hdisplay * b->vdisplay - a->hdisplay * a->vdisplay; +	if (diff) +		return diff; +	diff = b->clock - a->clock; +	return diff; +} + +/* FIXME: what we don't have a list sort function? */ +/* list sort from Mark J Roberts (mjr@znex.org) */ +void list_sort(struct list_head *head, int (*cmp)(struct list_head *a, struct list_head *b)) +{ +	struct list_head *p, *q, *e, *list, *tail, *oldhead; +	int insize, nmerges, psize, qsize, i; +	 +	list = head->next; +	list_del(head); +	insize = 1; +	for (;;) { +		p = oldhead = list; +		list = tail = NULL; +		nmerges = 0; +		 +		while (p) { +			nmerges++; +			q = p; +			psize = 0; +			for (i = 0; i < insize; i++) { +				psize++; +				q = q->next == oldhead ? NULL : q->next; +				if (!q) +					break; +			} +			 +			qsize = insize; +			while (psize > 0 || (qsize > 0 && q)) { +				if (!psize) { +					e = q; +					q = q->next; +					qsize--; +					if (q == oldhead) +						q = NULL; +				} else if (!qsize || !q) { +					e = p; +					p = p->next; +					psize--; +					if (p == oldhead) +						p = NULL; +				} else if (cmp(p, q) <= 0) { +					e = p; +					p = p->next; +					psize--; +					if (p == oldhead) +						p = NULL; +				} else { +					e = q; +					q = q->next; +					qsize--; +					if (q == oldhead) +						q = NULL; +				} +				if (tail) +					tail->next = e; +				else +					list = e; +				e->prev = tail; +				tail = e; +			} +			p = q; +		} +		 +		tail->next = list; +		list->prev = tail; +		 +		if (nmerges <= 1) +			break; +		 +		insize *= 2; +	} +	 +	head->next = list; +	head->prev = list->prev; +	list->prev->next = head; +	list->prev = head; +} + +/** + * drm_mode_sort - sort mode list + * @mode_list: list to sort + * + * LOCKING: + * Caller must hold a lock protecting @mode_list. + * + * Sort @mode_list by favorability, putting good modes first. + */ +void drm_mode_sort(struct list_head *mode_list) +{ +	list_sort(mode_list, drm_mode_compare); +} + + +/** + * drm_mode_output_list_update - update the mode list for the output + * @output: the output to update + * + * LOCKING: + * Caller must hold a lock protecting @mode_list. + * + * This moves the modes from the @output probed_modes list + * to the actual mode list. It compares the probed mode against the current + * list and only adds different modes. All modes unverified after this point + * will be removed by the prune invalid modes. + */ +void drm_mode_output_list_update(struct drm_output *output) +{ +	struct drm_display_mode *mode; +	struct drm_display_mode *pmode, *pt; +	int found_it; +	list_for_each_entry_safe(pmode, pt, &output->probed_modes, +				 head) { +		found_it = 0; +		/* go through current modes checking for the new probed mode */ +		list_for_each_entry(mode, &output->modes, head) { +			if (drm_mode_equal(pmode, mode)) { +				found_it = 1; +				/* if equal delete the probed mode */ +				mode->status = pmode->status; +				list_del(&pmode->head); +				kfree(pmode); +				break; +			} +		} + +		if (!found_it) { +			list_move_tail(&pmode->head, &output->modes); +		} +	} +} diff --git a/linux-core/drm_object.c b/linux-core/drm_object.c index 7d2e3a2b..2994b716 100644 --- a/linux-core/drm_object.c +++ b/linux-core/drm_object.c @@ -33,7 +33,7 @@  int drm_add_user_object(struct drm_file *priv, struct drm_user_object *item,  			int shareable)  { -	struct drm_device *dev = priv->head->dev; +	struct drm_device *dev = priv->minor->dev;  	int ret;  	DRM_ASSERT_LOCKED(&dev->struct_mutex); @@ -58,7 +58,7 @@ EXPORT_SYMBOL(drm_add_user_object);  struct drm_user_object *drm_lookup_user_object(struct drm_file *priv, uint32_t key)  { -	struct drm_device *dev = priv->head->dev; +	struct drm_device *dev = priv->minor->dev;  	struct drm_hash_item *hash;  	int ret;  	struct drm_user_object *item; @@ -85,7 +85,7 @@ EXPORT_SYMBOL(drm_lookup_user_object);  static void drm_deref_user_object(struct drm_file *priv, struct drm_user_object *item)  { -	struct drm_device *dev = priv->head->dev; +	struct drm_device *dev = priv->minor->dev;  	int ret;  	if (atomic_dec_and_test(&item->refcount)) { @@ -121,7 +121,7 @@ int drm_add_ref_object(struct drm_file *priv, struct drm_user_object *referenced  	struct drm_ref_object *item;  	struct drm_open_hash *ht = &priv->refd_object_hash[ref_action]; -	DRM_ASSERT_LOCKED(&priv->head->dev->struct_mutex); +	DRM_ASSERT_LOCKED(&priv->minor->dev->struct_mutex);  	if (!referenced_object->shareable && priv != referenced_object->owner) {  		DRM_ERROR("Not allowed to reference this object\n");  		return -EINVAL; @@ -178,7 +178,7 @@ struct drm_ref_object *drm_lookup_ref_object(struct drm_file *priv,  	struct drm_hash_item *hash;  	int ret; -	DRM_ASSERT_LOCKED(&priv->head->dev->struct_mutex); +	DRM_ASSERT_LOCKED(&priv->minor->dev->struct_mutex);  	ret = drm_ht_find_item(&priv->refd_object_hash[ref_action],  			       (unsigned long)referenced_object, &hash);  	if (ret) @@ -212,7 +212,7 @@ void drm_remove_ref_object(struct drm_file *priv, struct drm_ref_object *item)  	struct drm_open_hash *ht = &priv->refd_object_hash[item->unref_action];  	enum drm_ref_type unref_action; -	DRM_ASSERT_LOCKED(&priv->head->dev->struct_mutex); +	DRM_ASSERT_LOCKED(&priv->minor->dev->struct_mutex);  	unref_action = item->unref_action;  	if (atomic_dec_and_test(&item->refcount)) {  		ret = drm_ht_remove_item(ht, &item->hash); @@ -239,7 +239,7 @@ EXPORT_SYMBOL(drm_remove_ref_object);  int drm_user_object_ref(struct drm_file *priv, uint32_t user_token,  			enum drm_object_type type, struct drm_user_object **object)  { -	struct drm_device *dev = priv->head->dev; +	struct drm_device *dev = priv->minor->dev;  	struct drm_user_object *uo;  	struct drm_hash_item *hash;  	int ret; @@ -269,7 +269,7 @@ out_err:  int drm_user_object_unref(struct drm_file *priv, uint32_t user_token,  			  enum drm_object_type type)  { -	struct drm_device *dev = priv->head->dev; +	struct drm_device *dev = priv->minor->dev;  	struct drm_user_object *uo;  	struct drm_ref_object *ro;  	int ret; diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index e43e8dfd..7b585c3e 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -156,7 +156,6 @@ struct drm_fence_object {  };  #define _DRM_FENCE_CLASSES 8 -#define _DRM_FENCE_TYPE_EXE 0x00  struct drm_fence_class_manager {  	struct list_head ring; @@ -637,12 +636,12 @@ struct drm_bo_driver {  /*   * buffer objects (drm_bo.c)   */ -  extern int drm_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);  extern int drm_bo_destroy_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);  extern int drm_bo_map_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);  extern int drm_bo_unmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);  extern int drm_bo_reference_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_bo_set_pin(struct drm_device *dev, struct drm_buffer_object *bo, int pin);  extern int drm_bo_unreference_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);  extern int drm_bo_wait_idle_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);  extern int drm_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -778,6 +777,10 @@ extern void drm_regs_init(struct drm_reg_manager *manager,  					      const void *),  			  void (*reg_destroy)(struct drm_reg *)); +extern int drm_mem_reg_ioremap(struct drm_device *dev, struct drm_bo_mem_reg * mem, +			       void **virtual); +extern void drm_mem_reg_iounmap(struct drm_device *dev, struct drm_bo_mem_reg * mem, +				void *virtual);  /*   * drm_bo_lock.c   * Simple replacement for the hardware lock on buffer manager init and clean. diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index 3012c5b0..e10501f2 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -90,34 +90,35 @@ static struct drm_proc_list {   * "/proc/dri/%minor%/", and each entry in proc_list as   * "/proc/dri/%minor%/%name%".   */ -int drm_proc_init(struct drm_device * dev, int minor, -		  struct proc_dir_entry *root, struct proc_dir_entry **dev_root) +int drm_proc_init(struct drm_minor *minor, int minor_id, +		  struct proc_dir_entry *root)  {  	struct proc_dir_entry *ent;  	int i, j;  	char name[64]; -	sprintf(name, "%d", minor); -	*dev_root = proc_mkdir(name, root); -	if (!*dev_root) { +	sprintf(name, "%d", minor_id); +	minor->dev_root = proc_mkdir(name, root); +	if (!minor->dev_root) {  		DRM_ERROR("Cannot create /proc/dri/%s\n", name);  		return -1;  	}  	for (i = 0; i < DRM_PROC_ENTRIES; i++) {  		ent = create_proc_entry(drm_proc_list[i].name, -					S_IFREG | S_IRUGO, *dev_root); +					S_IFREG | S_IRUGO, minor->dev_root);  		if (!ent) {  			DRM_ERROR("Cannot create /proc/dri/%s/%s\n",  				  name, drm_proc_list[i].name);  			for (j = 0; j < i; j++)  				remove_proc_entry(drm_proc_list[i].name, -						  *dev_root); +						  minor->dev_root);  			remove_proc_entry(name, root); +			minor->dev_root = NULL;  			return -1;  		}  		ent->read_proc = drm_proc_list[i].f; -		ent->data = dev; +		ent->data = minor;  	}  	return 0;  } @@ -132,18 +133,17 @@ int drm_proc_init(struct drm_device * dev, int minor,   *   * Remove all proc entries created by proc_init().   */ -int drm_proc_cleanup(int minor, struct proc_dir_entry *root, -		     struct proc_dir_entry *dev_root) +int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root)  {  	int i;  	char name[64]; -	if (!root || !dev_root) +	if (!root || !minor->dev_root)  		return 0;  	for (i = 0; i < DRM_PROC_ENTRIES; i++) -		remove_proc_entry(drm_proc_list[i].name, dev_root); -	sprintf(name, "%d", minor); +		remove_proc_entry(drm_proc_list[i].name, minor->dev_root); +	sprintf(name, "%d", minor->index);  	remove_proc_entry(name, root);  	return 0; @@ -165,7 +165,9 @@ int drm_proc_cleanup(int minor, struct proc_dir_entry *root,  static int drm_name_info(char *buf, char **start, off_t offset, int request,  			 int *eof, void *data)  { -	struct drm_device *dev = (struct drm_device *) data; +	struct drm_minor *minor = (struct drm_minor *) data;  +	struct drm_master *master = minor->master; +	struct drm_device *dev = minor->dev;  	int len = 0;  	if (offset > DRM_PROC_LIMIT) { @@ -176,10 +178,10 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request,  	*start = &buf[offset];  	*eof = 0; -	if (dev->unique) { +	if (master->unique) {  		DRM_PROC_PRINT("%s %s %s\n",  			       dev->driver->pci_driver.name, -			       pci_name(dev->pdev), dev->unique); +			       pci_name(dev->pdev), master->unique);  	} else {  		DRM_PROC_PRINT("%s %s\n", dev->driver->pci_driver.name,  			       pci_name(dev->pdev)); @@ -207,7 +209,8 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request,  static int drm__vm_info(char *buf, char **start, off_t offset, int request,  			int *eof, void *data)  { -	struct drm_device *dev = (struct drm_device *) data; +	struct drm_minor *minor = (struct drm_minor *) data;  +	struct drm_device *dev = minor->dev;  	int len = 0;  	struct drm_map *map;  	struct drm_map_list *r_list; @@ -264,7 +267,8 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request,  static int drm_vm_info(char *buf, char **start, off_t offset, int request,  		       int *eof, void *data)  { -	struct drm_device *dev = (struct drm_device *) data; +	struct drm_minor *minor = (struct drm_minor *) data;  +	struct drm_device *dev = minor->dev;  	int ret;  	mutex_lock(&dev->struct_mutex); @@ -287,7 +291,8 @@ static int drm_vm_info(char *buf, char **start, off_t offset, int request,  static int drm__queues_info(char *buf, char **start, off_t offset,  			    int request, int *eof, void *data)  { -	struct drm_device *dev = (struct drm_device *) data; +	struct drm_minor *minor = (struct drm_minor *) data;  +	struct drm_device *dev = minor->dev;  	int len = 0;  	int i;  	struct drm_queue *q; @@ -337,7 +342,8 @@ static int drm__queues_info(char *buf, char **start, off_t offset,  static int drm_queues_info(char *buf, char **start, off_t offset, int request,  			   int *eof, void *data)  { -	struct drm_device *dev = (struct drm_device *) data; +	struct drm_minor *minor = (struct drm_minor *) data;  +	struct drm_device *dev = minor->dev;  	int ret;  	mutex_lock(&dev->struct_mutex); @@ -360,7 +366,8 @@ static int drm_queues_info(char *buf, char **start, off_t offset, int request,  static int drm__bufs_info(char *buf, char **start, off_t offset, int request,  			  int *eof, void *data)  { -	struct drm_device *dev = (struct drm_device *) data; +	struct drm_minor *minor = (struct drm_minor *) data;  +	struct drm_device *dev = minor->dev;  	int len = 0;  	struct drm_device_dma *dma = dev->dma;  	int i; @@ -409,7 +416,8 @@ static int drm__bufs_info(char *buf, char **start, off_t offset, int request,  static int drm_bufs_info(char *buf, char **start, off_t offset, int request,  			 int *eof, void *data)  { -	struct drm_device *dev = (struct drm_device *) data; +	struct drm_minor *minor = (struct drm_minor *) data;  +	struct drm_device *dev = minor->dev;  	int ret;  	mutex_lock(&dev->struct_mutex); @@ -432,7 +440,8 @@ static int drm_bufs_info(char *buf, char **start, off_t offset, int request,  static int drm__objects_info(char *buf, char **start, off_t offset, int request,  			  int *eof, void *data)  { -	struct drm_device *dev = (struct drm_device *) data; +	struct drm_minor *minor = (struct drm_minor *) data;  +	struct drm_device *dev = minor->dev;  	int len = 0;  	struct drm_buffer_manager *bm = &dev->bm;  	struct drm_fence_manager *fm = &dev->fm; @@ -496,7 +505,8 @@ static int drm__objects_info(char *buf, char **start, off_t offset, int request,  static int drm_objects_info(char *buf, char **start, off_t offset, int request,  			 int *eof, void *data)  { -	struct drm_device *dev = (struct drm_device *) data; +	struct drm_minor *minor = (struct drm_minor *) data;  +	struct drm_device *dev = minor->dev;  	int ret;  	mutex_lock(&dev->struct_mutex); @@ -519,7 +529,8 @@ static int drm_objects_info(char *buf, char **start, off_t offset, int request,  static int drm__clients_info(char *buf, char **start, off_t offset,  			     int request, int *eof, void *data)  { -	struct drm_device *dev = (struct drm_device *) data; +	struct drm_minor *minor = (struct drm_minor *) data;  +	struct drm_device *dev = minor->dev;  	int len = 0;  	struct drm_file *priv; @@ -535,7 +546,7 @@ static int drm__clients_info(char *buf, char **start, off_t offset,  	list_for_each_entry(priv, &dev->filelist, lhead) {  		DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n",  			       priv->authenticated ? 'y' : 'n', -			       priv->minor, +			       priv->minor->index,  			       priv->pid,  			       priv->uid, priv->magic, priv->ioctl_count);  	} @@ -552,7 +563,8 @@ static int drm__clients_info(char *buf, char **start, off_t offset,  static int drm_clients_info(char *buf, char **start, off_t offset,  			    int request, int *eof, void *data)  { -	struct drm_device *dev = (struct drm_device *) data; +	struct drm_minor *minor = (struct drm_minor *) data;  +	struct drm_device *dev = minor->dev;  	int ret;  	mutex_lock(&dev->struct_mutex); @@ -566,7 +578,8 @@ static int drm_clients_info(char *buf, char **start, off_t offset,  static int drm__vma_info(char *buf, char **start, off_t offset, int request,  			 int *eof, void *data)  { -	struct drm_device *dev = (struct drm_device *) data; +	struct drm_minor *minor = (struct drm_minor *) data;  +	struct drm_device *dev = minor->dev;  	int len = 0;  	struct drm_vma_entry *pt;  	struct vm_area_struct *vma; @@ -625,7 +638,8 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request,  static int drm_vma_info(char *buf, char **start, off_t offset, int request,  			int *eof, void *data)  { -	struct drm_device *dev = (struct drm_device *) data; +	struct drm_minor *minor = (struct drm_minor *) data;  +	struct drm_device *dev = minor->dev;  	int ret;  	mutex_lock(&dev->struct_mutex); diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 00a24521..334c8f03 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -37,38 +37,127 @@  #include "drmP.h"  #include "drm_core.h" -unsigned int drm_cards_limit = 16;	/* Enough for one machine */  unsigned int drm_debug = 0;		/* 1 to enable debug output */  EXPORT_SYMBOL(drm_debug);  MODULE_AUTHOR(CORE_AUTHOR);  MODULE_DESCRIPTION(CORE_DESC);  MODULE_LICENSE("GPL and additional rights"); -MODULE_PARM_DESC(cards_limit, "Maximum number of graphics cards");  MODULE_PARM_DESC(debug, "Enable debug output"); -module_param_named(cards_limit, drm_cards_limit, int, 0444);  module_param_named(debug, drm_debug, int, 0600); -struct drm_head **drm_heads; +struct idr drm_minors_idr; +  struct class *drm_class;  struct proc_dir_entry *drm_proc_root; +static int drm_minor_get_id(struct drm_device *dev, int type) +{ +	int new_id; +	int ret; +	int base = 0, limit = 63; + +	if (type == DRM_MINOR_CONTROL) { +		base += 64; +		limit = base + 127; +	} else if (type == DRM_MINOR_RENDER) { +		base += 128; +		limit = base + 255; +	}	 + +again: +	if (idr_pre_get(&drm_minors_idr, GFP_KERNEL) == 0) { +		DRM_ERROR("Out of memory expanding drawable idr\n"); +		return -ENOMEM; +	} +	mutex_lock(&dev->struct_mutex); +	ret = idr_get_new_above(&drm_minors_idr, NULL, +				base, &new_id); +	mutex_unlock(&dev->struct_mutex); +	if (ret == -EAGAIN) { +		goto again; +	} else if (ret) { +		return ret; +	} + +	if (new_id >= limit) { +		idr_remove(&drm_minors_idr, new_id); +		return -EINVAL; +	} +	return new_id; +} + +struct drm_master *drm_get_master(struct drm_minor *minor) +{ +	struct drm_master *master; + +	master = drm_calloc(1, sizeof(*master), DRM_MEM_DRIVER); +	if (!master) +		return NULL; + +//	INIT_LIST_HEAD(&master->filelist); +	spin_lock_init(&master->lock.spinlock); +	init_waitqueue_head(&master->lock.lock_queue); +	drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER); +	INIT_LIST_HEAD(&master->magicfree); +	master->minor = minor; + +	list_add_tail(&master->head, &minor->master_list); + +	return master; +} + +void drm_put_master(struct drm_master *master) +{ +	struct drm_magic_entry *pt, *next; +	struct drm_device *dev = master->minor->dev; + +	list_del(&master->head); + +	if (dev->driver->master_destroy) +		dev->driver->master_destroy(dev, master); + +	if (master->unique) { +		drm_free(master->unique, strlen(master->unique) + 1, DRM_MEM_DRIVER); +		master->unique = NULL; +		master->unique_len = 0; +	} + +	list_for_each_entry_safe(pt, next, &master->magicfree, head) { +		list_del(&pt->head); +		drm_ht_remove_item(&master->magiclist, &pt->hash_item); +		drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); +	} + +	drm_ht_remove(&master->magiclist); + +	if (master->lock.hw_lock) { +		if (dev->sigdata.lock == master->lock.hw_lock) +			dev->sigdata.lock = NULL; +		master->lock.hw_lock = NULL;	/* SHM removed */ +		master->lock.file_priv = NULL; +		wake_up_interruptible(&master->lock.lock_queue); +	} + +	drm_free(master, sizeof(*master), DRM_MEM_DRIVER); +} +  static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,  			   const struct pci_device_id *ent,  			   struct drm_driver *driver)  {  	int retcode; -	INIT_LIST_HEAD(&dev->filelist);  	INIT_LIST_HEAD(&dev->ctxlist);  	INIT_LIST_HEAD(&dev->vmalist);  	INIT_LIST_HEAD(&dev->maplist); +	INIT_LIST_HEAD(&dev->filelist);  	spin_lock_init(&dev->count_lock);  	spin_lock_init(&dev->drw_lock);  	spin_lock_init(&dev->tasklet_lock); -	spin_lock_init(&dev->lock.spinlock); +//	spin_lock_init(&dev->lock.spinlock);  	init_timer(&dev->timer);  	mutex_init(&dev->struct_mutex);  	mutex_init(&dev->ctxlist_mutex); @@ -86,9 +175,9 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,  	dev->irq = pdev->irq;  	dev->irq_enabled = 0; -	if (drm_ht_create(&dev->map_hash, DRM_MAP_HASH_ORDER)) { +	if (drm_ht_create(&dev->map_hash, DRM_MAP_HASH_ORDER))  		return -ENOMEM; -	} +  	if (drm_mm_init(&dev->offset_manager, DRM_FILE_PAGE_OFFSET_START,  			DRM_FILE_PAGE_OFFSET_SIZE)) {  		drm_ht_remove(&dev->map_hash); @@ -131,11 +220,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,  		}  	} -	if (dev->driver->load) -		if ((retcode = dev->driver->load(dev, ent->driver_data))) -			goto error_out_unreg; - -  	retcode = drm_ctxbitmap_init(dev);  	if (retcode) {  		DRM_ERROR("Cannot allocate memory for context bitmap.\n"); @@ -161,49 +245,61 @@ error_out_unreg:   * create the proc init entry via proc_init(). This routines assigns   * minor numbers to secondary heads of multi-headed cards   */ -static int drm_get_head(struct drm_device * dev, struct drm_head * head) +static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type)  { -	struct drm_head **heads = drm_heads; +	struct drm_minor *new_minor;  	int ret; -	int minor; +	int minor_id;  	DRM_DEBUG("\n"); -	for (minor = 0; minor < drm_cards_limit; minor++, heads++) { -		if (!*heads) { - -			*head = (struct drm_head) { -				.dev = dev, -				.device = MKDEV(DRM_MAJOR, minor), -				.minor = minor, -			}; -			if ((ret = -			     drm_proc_init(dev, minor, drm_proc_root, -					   &head->dev_root))) { -				printk(KERN_ERR -				       "DRM: Failed to initialize /proc/dri.\n"); -				goto err_g1; -			} - -			ret = drm_sysfs_device_add(dev, head); -			if (ret) { -				printk(KERN_ERR -				       "DRM: Error sysfs_device_add.\n"); -				goto err_g2; -			} -			*heads = head; - -			DRM_DEBUG("new minor assigned %d\n", minor); -			return 0; +	minor_id = drm_minor_get_id(dev, type); +	if (minor_id < 0) +		return minor_id; + +	new_minor = kzalloc(sizeof(struct drm_minor), GFP_KERNEL); +	if (!new_minor) { +		ret = -ENOMEM; +		goto err_idr; +	} + +	new_minor->type = type; +	new_minor->device = MKDEV(DRM_MAJOR, minor_id); +	new_minor->dev = dev; +	new_minor->index = minor_id; +	INIT_LIST_HEAD(&new_minor->master_list); + +	idr_replace(&drm_minors_idr, new_minor, minor_id); +	 +	if (type == DRM_MINOR_LEGACY) { +		ret = drm_proc_init(new_minor, minor_id, drm_proc_root); +		if (ret) { +			DRM_ERROR("DRM: Failed to initialize /proc/dri.\n"); +			goto err_mem;  		} +	} else +		new_minor->dev_root = NULL; + +	ret = drm_sysfs_device_add(new_minor); +	if (ret) { +		printk(KERN_ERR +		       "DRM: Error sysfs_device_add.\n"); +		goto err_g2;  	} -	DRM_ERROR("out of minors\n"); -	return -ENOMEM; +	*minor = new_minor; +	 +	DRM_DEBUG("new minor assigned %d\n", minor_id); +	return 0; + +  err_g2: -	drm_proc_cleanup(minor, drm_proc_root, head->dev_root); -err_g1: -	*head = (struct drm_head) { -		.dev = NULL}; +	if (new_minor->type == DRM_MINOR_LEGACY) +		drm_proc_cleanup(new_minor, drm_proc_root); +err_mem: +	kfree(new_minor); +err_idr: +	idr_remove(&drm_minors_idr, minor_id); +	*minor = NULL;  	return ret;  } @@ -246,22 +342,33 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,  		printk(KERN_ERR "DRM: fill_in_dev failed\n");  		goto err_g3;  	} -	if ((ret = drm_get_head(dev, &dev->primary))) + +	if ((ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL)))  		goto err_g3; +	if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY))) +		goto err_g4; + +	if (dev->driver->load) +		if ((ret = dev->driver->load(dev, ent->driver_data))) +			goto err_g5; +  	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",  		 driver->name, driver->major, driver->minor, driver->patchlevel, -		 driver->date, dev->primary.minor); +		 driver->date, dev->primary->index);  	return 0; - - err_g3: +err_g5: +	drm_put_minor(&dev->primary); +err_g4: +	drm_put_minor(&dev->control); +err_g3:  	if (!drm_fb_loaded)  		pci_disable_device(pdev); - err_g2: +err_g2:  	if (!drm_fb_loaded)  		pci_release_regions(pdev); - err_g1: +err_g1:  	if (!drm_fb_loaded)  		pci_set_drvdata(pdev, NULL); @@ -286,11 +393,6 @@ int drm_put_dev(struct drm_device * dev)  {  	DRM_DEBUG("release primary %s\n", dev->driver->pci_driver.name); -	if (dev->unique) { -		drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER); -		dev->unique = NULL; -		dev->unique_len = 0; -	}  	if (dev->devname) {  		drm_free(dev->devname, strlen(dev->devname) + 1,  			 DRM_MEM_DRIVER); @@ -310,17 +412,18 @@ int drm_put_dev(struct drm_device * dev)   * last minor released.   *   */ -int drm_put_head(struct drm_head * head) +int drm_put_minor(struct drm_minor **minor_p)  { -	int minor = head->minor; - -	DRM_DEBUG("release secondary minor %d\n", minor); +	struct drm_minor *minor = *minor_p; +	DRM_DEBUG("release secondary minor %d\n", minor->index); -	drm_proc_cleanup(minor, drm_proc_root, head->dev_root); -	drm_sysfs_device_remove(head->dev); +	if (minor->type == DRM_MINOR_LEGACY) +		drm_proc_cleanup(minor, drm_proc_root); +	drm_sysfs_device_remove(minor); -	*head = (struct drm_head) {.dev = NULL}; +	idr_remove(&drm_minors_idr, minor->index); -	drm_heads[minor] = NULL; +	kfree(minor); +	*minor_p = NULL;  	return 0;  } diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 3aaac11b..f03e5d4e 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -19,7 +19,7 @@  #include "drm_core.h"  #include "drmP.h" -#define to_drm_device(d) container_of(d, struct drm_device, dev) +#define to_drm_minor(d) container_of(d, struct drm_minor, kdev)  /**   * drm_sysfs_suspend - DRM class suspend hook @@ -31,12 +31,14 @@   */  static int drm_sysfs_suspend(struct device *dev, pm_message_t state)  { -	struct drm_device *drm_dev = to_drm_device(dev); +	struct drm_minor *drm_minor = to_drm_minor(dev); +	struct drm_device *drm_dev = drm_minor->dev;  	printk(KERN_ERR "%s\n", __FUNCTION__); -	if (drm_dev->driver->suspend) -		return drm_dev->driver->suspend(drm_dev); +	if (drm_minor->type == DRM_MINOR_CONTROL) +		if (drm_dev->driver->suspend) +			return drm_dev->driver->suspend(drm_dev);  	return 0;  } @@ -50,10 +52,12 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state)   */  static int drm_sysfs_resume(struct device *dev)  { -	struct drm_device *drm_dev = to_drm_device(dev); +	struct drm_minor *drm_minor = to_drm_minor(dev); +	struct drm_device *drm_dev = drm_minor->dev; -	if (drm_dev->driver->resume) -		return drm_dev->driver->resume(drm_dev); +	if (drm_minor->type == DRM_MINOR_CONTROL) +		if (drm_dev->driver->resume) +			return drm_dev->driver->resume(drm_dev);  	return 0;  } @@ -122,10 +126,11 @@ void drm_sysfs_destroy(void)  static ssize_t show_dri(struct device *device, struct device_attribute *attr,  			char *buf)  { -	struct drm_device *dev = to_drm_device(device); -	if (dev->driver->dri_library_name) -		return dev->driver->dri_library_name(dev, buf); -	return snprintf(buf, PAGE_SIZE, "%s\n", dev->driver->pci_driver.name); +	struct drm_minor *drm_minor = to_drm_minor(device); +	struct drm_device *drm_dev = drm_minor->dev; +	if (drm_dev->driver->dri_library_name) +		return drm_dev->driver->dri_library_name(drm_dev, buf); +	return snprintf(buf, PAGE_SIZE, "%s\n", drm_dev->driver->pci_driver.name);  }  static struct device_attribute device_attrs[] = { @@ -154,25 +159,33 @@ static void drm_sysfs_device_release(struct device *dev)   * as the parent for the Linux device, and make sure it has a file containing   * the driver we're using (for userspace compatibility).   */ -int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head) +int drm_sysfs_device_add(struct drm_minor *minor)  {  	int err;  	int i, j; - -	dev->dev.parent = &dev->pdev->dev; -	dev->dev.class = drm_class; -	dev->dev.release = drm_sysfs_device_release; -	dev->dev.devt = head->device; -	snprintf(dev->dev.bus_id, BUS_ID_SIZE, "card%d", head->minor); - -	err = device_register(&dev->dev); +	char *minor_str; + +	minor->kdev.parent = &minor->dev->pdev->dev; +	minor->kdev.class = drm_class; +	minor->kdev.release = drm_sysfs_device_release; +	minor->kdev.devt = minor->device; +	if (minor->type == DRM_MINOR_CONTROL) +		minor_str = "controlD%d"; +	else if (minor->type == DRM_MINOR_RENDER) +		minor_str = "renderD%d"; +	else +		minor_str = "card%d"; +	 +	snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->index); + +	err = device_register(&minor->kdev);  	if (err) {  		DRM_ERROR("device add failed: %d\n", err);  		goto err_out;  	}  	for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { -		err = device_create_file(&dev->dev, &device_attrs[i]); +		err = device_create_file(&minor->kdev, &device_attrs[i]);  		if (err)  			goto err_out_files;  	} @@ -182,8 +195,8 @@ int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head)  err_out_files:  	if (i > 0)  		for (j = 0; j < i; j++) -			device_remove_file(&dev->dev, &device_attrs[i]); -	device_unregister(&dev->dev); +			device_remove_file(&minor->kdev, &device_attrs[i]); +	device_unregister(&minor->kdev);  err_out:  	return err; @@ -196,11 +209,11 @@ err_out:   * This call unregisters and cleans up a class device that was created with a   * call to drm_sysfs_device_add()   */ -void drm_sysfs_device_remove(struct drm_device *dev) +void drm_sysfs_device_remove(struct drm_minor *minor)  {  	int i;  	for (i = 0; i < ARRAY_SIZE(device_attrs); i++) -		device_remove_file(&dev->dev, &device_attrs[i]); -	device_unregister(&dev->dev); +		device_remove_file(&minor->kdev, &device_attrs[i]); +	device_unregister(&minor->kdev);  } diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index c481a530..15e1c0f5 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -86,7 +86,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,  						unsigned long address)  {  	struct drm_file *priv = vma->vm_file->private_data; -	struct drm_device *dev = priv->head->dev; +	struct drm_device *dev = priv->minor->dev;  	struct drm_map *map = NULL;  	struct drm_map_list *r_list;  	struct drm_hash_item *hash; @@ -204,7 +204,7 @@ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma,  static void drm_vm_shm_close(struct vm_area_struct *vma)  {  	struct drm_file *priv = vma->vm_file->private_data; -	struct drm_device *dev = priv->head->dev; +	struct drm_device *dev = priv->minor->dev;  	struct drm_vma_entry *pt, *temp;  	struct drm_map *map;  	struct drm_map_list *r_list; @@ -286,7 +286,7 @@ static __inline__ struct page *drm_do_vm_dma_nopage(struct vm_area_struct *vma,  						    unsigned long address)  {  	struct drm_file *priv = vma->vm_file->private_data; -	struct drm_device *dev = priv->head->dev; +	struct drm_device *dev = priv->minor->dev;  	struct drm_device_dma *dma = dev->dma;  	unsigned long offset;  	unsigned long page_nr; @@ -323,7 +323,7 @@ static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma,  {  	struct drm_map *map = (struct drm_map *) vma->vm_private_data;  	struct drm_file *priv = vma->vm_file->private_data; -	struct drm_device *dev = priv->head->dev; +	struct drm_device *dev = priv->minor->dev;  	struct drm_sg_mem *entry = dev->sg;  	unsigned long offset;  	unsigned long map_offset; @@ -419,7 +419,7 @@ static struct vm_operations_struct drm_vm_sg_ops = {  static void drm_vm_open_locked(struct vm_area_struct *vma)  {  	struct drm_file *priv = vma->vm_file->private_data; -	struct drm_device *dev = priv->head->dev; +	struct drm_device *dev = priv->minor->dev;  	struct drm_vma_entry *vma_entry;  	DRM_DEBUG("0x%08lx,0x%08lx\n", @@ -437,7 +437,7 @@ static void drm_vm_open_locked(struct vm_area_struct *vma)  static void drm_vm_open(struct vm_area_struct *vma)  {  	struct drm_file *priv = vma->vm_file->private_data; -	struct drm_device *dev = priv->head->dev; +	struct drm_device *dev = priv->minor->dev;  	mutex_lock(&dev->struct_mutex);  	drm_vm_open_locked(vma); @@ -455,7 +455,7 @@ static void drm_vm_open(struct vm_area_struct *vma)  static void drm_vm_close(struct vm_area_struct *vma)  {  	struct drm_file *priv = vma->vm_file->private_data; -	struct drm_device *dev = priv->head->dev; +	struct drm_device *dev = priv->minor->dev;  	struct drm_vma_entry *pt, *temp;  	DRM_DEBUG("0x%08lx,0x%08lx\n", @@ -491,7 +491,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)  	struct drm_device_dma *dma;  	unsigned long length = vma->vm_end - vma->vm_start; -	dev = priv->head->dev; +	dev = priv->minor->dev;  	dma = dev->dma;  	DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",  		  vma->vm_start, vma->vm_end, vma->vm_pgoff); @@ -556,7 +556,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs);  static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)  {  	struct drm_file *priv = filp->private_data; -	struct drm_device *dev = priv->head->dev; +	struct drm_device *dev = priv->minor->dev;  	struct drm_map *map = NULL;  	unsigned long offset = 0;  	struct drm_hash_item *hash; @@ -677,7 +677,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)  int drm_mmap(struct file *filp, struct vm_area_struct *vma)  {  	struct drm_file *priv = filp->private_data; -	struct drm_device *dev = priv->head->dev; +	struct drm_device *dev = priv->minor->dev;  	int ret;  	mutex_lock(&dev->struct_mutex); diff --git a/linux-core/i810_dma.c b/linux-core/i810_dma.c index 3c9ca3b2..f2bf5d9d 100644 --- a/linux-core/i810_dma.c +++ b/linux-core/i810_dma.c @@ -113,7 +113,7 @@ static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)  	drm_i810_buf_priv_t *buf_priv;  	lock_kernel(); -	dev = priv->head->dev; +	dev = priv->minor->dev;  	dev_priv = dev->dev_private;  	buf = dev_priv->mmap_buffer;  	buf_priv = buf->dev_private; @@ -141,7 +141,7 @@ static const struct file_operations i810_buffer_fops = {  static int i810_map_buffer(struct drm_buf * buf, struct drm_file *file_priv)  { -	struct drm_device *dev = file_priv->head->dev; +	struct drm_device *dev = file_priv->minor->dev;  	drm_i810_buf_priv_t *buf_priv = buf->dev_private;  	drm_i810_private_t *dev_priv = dev->dev_private;  	const struct file_operations *old_fops; diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c index 08067476..ba586888 100644 --- a/linux-core/i915_buffer.c +++ b/linux-core/i915_buffer.c @@ -89,7 +89,7 @@ int i915_init_mem_type(struct drm_device *dev, uint32_t type,  		man->drm_bus_maptype = _DRM_AGP;  		man->gpu_offset = 0;  		break; -	case DRM_BO_MEM_PRIV0: +	case DRM_BO_MEM_VRAM:  		if (!(drm_core_has_AGP(dev) && dev->agp)) {  			DRM_ERROR("AGP is not enabled for memory type %u\n",  				  (unsigned)type); @@ -103,6 +103,9 @@ int i915_init_mem_type(struct drm_device *dev, uint32_t type,  		man->drm_bus_maptype = _DRM_AGP;  		man->gpu_offset = 0;  		break; +	case DRM_BO_MEM_PRIV0: /* for OS preallocated space */ +		DRM_ERROR("PRIV0 not used yet.\n"); +		break;  	default:  		DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);  		return -EINVAL; @@ -139,7 +142,7 @@ static void i915_emit_copy_blit(struct drm_device * dev,  {  	uint32_t cur_pages;  	uint32_t stride = PAGE_SIZE; -	drm_i915_private_t *dev_priv = dev->dev_private; +	struct drm_i915_private *dev_priv = dev->dev_private;  	RING_LOCALS;  	if (!dev_priv) @@ -267,10 +270,12 @@ static inline void clflush(volatile void *__p)  static inline void drm_cache_flush_addr(void *virt)  { +#ifdef cpu_has_clflush  	int i;  	for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size)  		clflush(virt+i); +#endif  }  static inline void drm_cache_flush_page(struct page *p) @@ -288,6 +293,9 @@ void i915_flush_ttm(struct drm_ttm *ttm)  	DRM_MEMORYBARRIER();  #ifdef CONFIG_X86_32 +#ifndef cpu_has_clflush +#define cpu_has_clflush 0 +#endif  	/* Hopefully nobody has built an x86-64 processor without clflush */  	if (!cpu_has_clflush) {  		wbinvd(); diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 9d8b4685..64c805f5 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -30,6 +30,7 @@  #include "drmP.h"  #include "drm.h"  #include "i915_drm.h" +#include "intel_drv.h"  #include "i915_drv.h"  #include "drm_pciids.h" @@ -44,8 +45,8 @@ extern struct drm_fence_driver i915_fence_driver;  #ifdef I915_HAVE_BUFFER -static uint32_t i915_mem_prios[] = {DRM_BO_MEM_PRIV0, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL}; -static uint32_t i915_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_PRIV0, DRM_BO_MEM_LOCAL}; +static uint32_t i915_mem_prios[] = {DRM_BO_MEM_VRAM, DRM_BO_MEM_PRIV0, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL}; +static uint32_t i915_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_PRIV0, DRM_BO_MEM_VRAM, DRM_BO_MEM_LOCAL};  static struct drm_bo_driver i915_bo_driver = {  	.mem_type_prio = i915_mem_prios, @@ -556,9 +557,8 @@ static struct drm_driver driver = {  	    DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,  	.load = i915_driver_load,  	.unload = i915_driver_unload, -	.firstopen = i915_driver_firstopen, -	.lastclose = i915_driver_lastclose, -	.preclose = i915_driver_preclose, +/*	.lastclose = i915_driver_lastclose, +	.preclose = i915_driver_preclose, */  	.suspend = i915_suspend,  	.resume = i915_resume,  	.device_is_agp = i915_driver_device_is_agp, @@ -572,6 +572,11 @@ static struct drm_driver driver = {  	.reclaim_buffers = drm_core_reclaim_buffers,  	.get_map_ofs = drm_core_get_map_ofs,  	.get_reg_ofs = drm_core_get_reg_ofs, +	.fb_probe = intelfb_probe, +	.fb_remove = intelfb_remove, +	.fb_resize = intelfb_resize, +	.master_create = i915_master_create, +	.master_destroy = i915_master_destroy,  	.ioctls = i915_ioctls,  	.fops = {  		.owner = THIS_MODULE, diff --git a/linux-core/i915_init.c b/linux-core/i915_init.c new file mode 120000 index 00000000..473ddf7b --- /dev/null +++ b/linux-core/i915_init.c @@ -0,0 +1 @@ +../shared-core/i915_init.c
\ No newline at end of file diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c new file mode 100644 index 00000000..a9fb50a3 --- /dev/null +++ b/linux-core/intel_crt.c @@ -0,0 +1,274 @@ +/* + * Copyright © 2006-2007 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: + *	Eric Anholt <eric@anholt.net> + */ + +#include <linux/i2c.h> +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "intel_drv.h" +#include "i915_drm.h" +#include "i915_drv.h" + +static void intel_crt_dpms(struct drm_output *output, int mode) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	u32 temp; +	 +	temp = I915_READ(ADPA); +	temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); +	temp &= ~ADPA_DAC_ENABLE; +	 +	switch(mode) { +	case DPMSModeOn: +		temp |= ADPA_DAC_ENABLE; +		break; +	case DPMSModeStandby: +		temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; +		break; +	case DPMSModeSuspend: +		temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; +		break; +	case DPMSModeOff: +		temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; +		break; +	} +	 +	I915_WRITE(ADPA, temp); +} + +static void intel_crt_save(struct drm_output *output) +{ +	 +} + +static void intel_crt_restore(struct drm_output *output) +{ + +} + +static int intel_crt_mode_valid(struct drm_output *output, +				struct drm_display_mode *mode) +{ +	if (mode->flags & V_DBLSCAN) +		return MODE_NO_DBLESCAN; + +	if (mode->clock > 400000 || mode->clock < 25000) +		return MODE_CLOCK_RANGE; + +	return MODE_OK; +} + +static bool intel_crt_mode_fixup(struct drm_output *output, +				 struct drm_display_mode *mode, +				 struct drm_display_mode *adjusted_mode) +{ +	return true; +} + +static void intel_crt_mode_set(struct drm_output *output, +			       struct drm_display_mode *mode, +			       struct drm_display_mode *adjusted_mode) +{ +	struct drm_device *dev = output->dev; +	struct drm_crtc *crtc = output->crtc; +	struct intel_crtc *intel_crtc = crtc->driver_private; +	struct drm_i915_private *dev_priv = dev->dev_private; +	int dpll_md_reg; +	u32 adpa, dpll_md; + +	if (intel_crtc->pipe == 0)  +		dpll_md_reg = DPLL_A_MD; +	else +		dpll_md_reg = DPLL_B_MD; + +	/* +	 * Disable separate mode multiplier used when cloning SDVO to CRT +	 * XXX this needs to be adjusted when we really are cloning +	 */ +	if (IS_I965G(dev)) { +		dpll_md = I915_READ(dpll_md_reg); +		I915_WRITE(dpll_md_reg, +			   dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK); +	} +	 +	adpa = 0; +	if (adjusted_mode->flags & V_PHSYNC) +		adpa |= ADPA_HSYNC_ACTIVE_HIGH; +	if (adjusted_mode->flags & V_PVSYNC) +		adpa |= ADPA_VSYNC_ACTIVE_HIGH; +	 +	if (intel_crtc->pipe == 0) +		adpa |= ADPA_PIPE_A_SELECT; +	else +		adpa |= ADPA_PIPE_B_SELECT; +	 +	I915_WRITE(ADPA, adpa); +} + +/** + * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence. + * + * Only for I945G/GM. + * + * \return TRUE if CRT is connected. + * \return FALSE if CRT is disconnected. + */ +static bool intel_crt_detect_hotplug(struct drm_output *output) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	u32 temp; +#if 1 +	unsigned long timeout = jiffies + msecs_to_jiffies(1000); + +	temp = I915_READ(PORT_HOTPLUG_EN); + +	I915_WRITE(PORT_HOTPLUG_EN, +		   temp | CRT_HOTPLUG_FORCE_DETECT | (1 << 5)); + +	do { +		if (!(I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT)) +			break; +		msleep(1); +	} while (time_after(timeout, jiffies)); + +	if ((I915_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) == +	    CRT_HOTPLUG_MONITOR_COLOR) +		return true; + +	return false; +#else +	temp = I915_READ(PORT_HOTPLUG_STAT); +	DRM_DEBUG("HST 0x%08x\n", temp); + +	if (temp & (1 << 8) && temp & (1 << 9)) +		return true; + +	return false; +#endif +} + +static bool intel_crt_detect_ddc(struct drm_output *output) +{ +	struct intel_output *intel_output = output->driver_private; + +	/* CRT should always be at 0, but check anyway */ +	if (intel_output->type != INTEL_OUTPUT_ANALOG) +		return false; +	 +	return intel_ddc_probe(output); +} + +static enum drm_output_status intel_crt_detect(struct drm_output *output) +{ +	struct drm_device *dev = output->dev; +	 +	if (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev)) { +		if (intel_crt_detect_hotplug(output)) +			return output_status_connected; +		else +			return output_status_disconnected; +	} + +	if (intel_crt_detect_ddc(output)) +		return output_status_connected; + +	/* TODO use load detect */ +	return output_status_unknown; +} + +static void intel_crt_destroy(struct drm_output *output) +{ +	struct intel_output *intel_output = output->driver_private; + +	intel_i2c_destroy(intel_output->ddc_bus); +	kfree(output->driver_private); +} + +static int intel_crt_get_modes(struct drm_output *output) +{ +	return intel_ddc_get_modes(output); +} + +static bool intel_crt_set_property(struct drm_output *output, +				  struct drm_property *property, +				  uint64_t value) +{ +	struct drm_device *dev = output->dev; + +	if (property == dev->mode_config.dpms_property) +		intel_crt_dpms(output, (uint32_t)(value & 0xf)); + +	return true; +} + +/* + * Routines for controlling stuff on the analog port + */ +static const struct drm_output_funcs intel_crt_output_funcs = { +	.dpms = intel_crt_dpms, +	.save = intel_crt_save, +	.restore = intel_crt_restore, +	.mode_valid = intel_crt_mode_valid, +	.mode_fixup = intel_crt_mode_fixup, +	.prepare = intel_output_prepare, +	.mode_set = intel_crt_mode_set, +	.commit = intel_output_commit, +	.detect = intel_crt_detect, +	.get_modes = intel_crt_get_modes, +	.cleanup = intel_crt_destroy, +	.set_property = intel_crt_set_property, +}; + +void intel_crt_init(struct drm_device *dev) +{ +	struct drm_output *output; +	struct intel_output *intel_output; + +	output = drm_output_create(dev, &intel_crt_output_funcs, +				   DRM_MODE_OUTPUT_DAC); + +	intel_output = kmalloc(sizeof(struct intel_output), GFP_KERNEL); +	if (!intel_output) { +		drm_output_destroy(output); +		return; +	} +	/* Set up the DDC bus. */ +	intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A"); +	if (!intel_output->ddc_bus) { +		dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " +			   "failed.\n"); +		return; +	} + +	intel_output->type = INTEL_OUTPUT_ANALOG; +	output->driver_private = intel_output; +	output->interlace_allowed = 0; +	output->doublescan_allowed = 0; + +	drm_output_attach_property(output, dev->mode_config.connector_type_property, ConnectorVGA); +} diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c new file mode 100644 index 00000000..6a9d9808 --- /dev/null +++ b/linux-core/intel_display.c @@ -0,0 +1,1356 @@ +/* + * Copyright © 2006-2007 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: + *	Eric Anholt <eric@anholt.net> + */ + +#include <linux/i2c.h> +#include "drmP.h" +#include "intel_drv.h" +#include "i915_drm.h" +#include "i915_drv.h" + +bool intel_pipe_has_type (struct drm_crtc *crtc, int type); + +typedef struct { +    /* given values */     +    int n; +    int m1, m2; +    int p1, p2; +    /* derived values */ +    int	dot; +    int	vco; +    int	m; +    int	p; +} intel_clock_t; + +typedef struct { +    int	min, max; +} intel_range_t; + +typedef struct { +    int	dot_limit; +    int	p2_slow, p2_fast; +} intel_p2_t; + +#define INTEL_P2_NUM		      2 + +typedef struct { +    intel_range_t   dot, vco, n, m, m1, m2, p, p1; +    intel_p2_t	    p2; +} intel_limit_t; + +#define I8XX_DOT_MIN		  25000 +#define I8XX_DOT_MAX		 350000 +#define I8XX_VCO_MIN		 930000 +#define I8XX_VCO_MAX		1400000 +#define I8XX_N_MIN		      3 +#define I8XX_N_MAX		     16 +#define I8XX_M_MIN		     96 +#define I8XX_M_MAX		    140 +#define I8XX_M1_MIN		     18 +#define I8XX_M1_MAX		     26 +#define I8XX_M2_MIN		      6 +#define I8XX_M2_MAX		     16 +#define I8XX_P_MIN		      4 +#define I8XX_P_MAX		    128 +#define I8XX_P1_MIN		      2 +#define I8XX_P1_MAX		     33 +#define I8XX_P1_LVDS_MIN	      1 +#define I8XX_P1_LVDS_MAX	      6 +#define I8XX_P2_SLOW		      4 +#define I8XX_P2_FAST		      2 +#define I8XX_P2_LVDS_SLOW	      14 +#define I8XX_P2_LVDS_FAST	      14 /* No fast option */ +#define I8XX_P2_SLOW_LIMIT	 165000 + +#define I9XX_DOT_MIN		  20000 +#define I9XX_DOT_MAX		 400000 +#define I9XX_VCO_MIN		1400000 +#define I9XX_VCO_MAX		2800000 +#define I9XX_N_MIN		      3 +#define I9XX_N_MAX		      8 +#define I9XX_M_MIN		     70 +#define I9XX_M_MAX		    120 +#define I9XX_M1_MIN		     10 +#define I9XX_M1_MAX		     20 +#define I9XX_M2_MIN		      5 +#define I9XX_M2_MAX		      9 +#define I9XX_P_SDVO_DAC_MIN	      5 +#define I9XX_P_SDVO_DAC_MAX	     80 +#define I9XX_P_LVDS_MIN		      7 +#define I9XX_P_LVDS_MAX		     98 +#define I9XX_P1_MIN		      1 +#define I9XX_P1_MAX		      8 +#define I9XX_P2_SDVO_DAC_SLOW		     10 +#define I9XX_P2_SDVO_DAC_FAST		      5 +#define I9XX_P2_SDVO_DAC_SLOW_LIMIT	 200000 +#define I9XX_P2_LVDS_SLOW		     14 +#define I9XX_P2_LVDS_FAST		      7 +#define I9XX_P2_LVDS_SLOW_LIMIT		 112000 + +#define INTEL_LIMIT_I8XX_DVO_DAC    0 +#define INTEL_LIMIT_I8XX_LVDS	    1 +#define INTEL_LIMIT_I9XX_SDVO_DAC   2 +#define INTEL_LIMIT_I9XX_LVDS	    3 + +static const intel_limit_t intel_limits[] = { +    { /* INTEL_LIMIT_I8XX_DVO_DAC */ +        .dot = { .min = I8XX_DOT_MIN,		.max = I8XX_DOT_MAX }, +        .vco = { .min = I8XX_VCO_MIN,		.max = I8XX_VCO_MAX }, +        .n   = { .min = I8XX_N_MIN,		.max = I8XX_N_MAX }, +        .m   = { .min = I8XX_M_MIN,		.max = I8XX_M_MAX }, +        .m1  = { .min = I8XX_M1_MIN,		.max = I8XX_M1_MAX }, +        .m2  = { .min = I8XX_M2_MIN,		.max = I8XX_M2_MAX }, +        .p   = { .min = I8XX_P_MIN,		.max = I8XX_P_MAX }, +        .p1  = { .min = I8XX_P1_MIN,		.max = I8XX_P1_MAX }, +	.p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT, +		 .p2_slow = I8XX_P2_SLOW,	.p2_fast = I8XX_P2_FAST }, +    }, +    { /* INTEL_LIMIT_I8XX_LVDS */ +        .dot = { .min = I8XX_DOT_MIN,		.max = I8XX_DOT_MAX }, +        .vco = { .min = I8XX_VCO_MIN,		.max = I8XX_VCO_MAX }, +        .n   = { .min = I8XX_N_MIN,		.max = I8XX_N_MAX }, +        .m   = { .min = I8XX_M_MIN,		.max = I8XX_M_MAX }, +        .m1  = { .min = I8XX_M1_MIN,		.max = I8XX_M1_MAX }, +        .m2  = { .min = I8XX_M2_MIN,		.max = I8XX_M2_MAX }, +        .p   = { .min = I8XX_P_MIN,		.max = I8XX_P_MAX }, +        .p1  = { .min = I8XX_P1_LVDS_MIN,	.max = I8XX_P1_LVDS_MAX }, +	.p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT, +		 .p2_slow = I8XX_P2_LVDS_SLOW,	.p2_fast = I8XX_P2_LVDS_FAST }, +    }, +    { /* INTEL_LIMIT_I9XX_SDVO_DAC */ +        .dot = { .min = I9XX_DOT_MIN,		.max = I9XX_DOT_MAX }, +        .vco = { .min = I9XX_VCO_MIN,		.max = I9XX_VCO_MAX }, +        .n   = { .min = I9XX_N_MIN,		.max = I9XX_N_MAX }, +        .m   = { .min = I9XX_M_MIN,		.max = I9XX_M_MAX }, +        .m1  = { .min = I9XX_M1_MIN,		.max = I9XX_M1_MAX }, +        .m2  = { .min = I9XX_M2_MIN,		.max = I9XX_M2_MAX }, +        .p   = { .min = I9XX_P_SDVO_DAC_MIN,	.max = I9XX_P_SDVO_DAC_MAX }, +        .p1  = { .min = I9XX_P1_MIN,		.max = I9XX_P1_MAX }, +	.p2  = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT, +		 .p2_slow = I9XX_P2_SDVO_DAC_SLOW,	.p2_fast = I9XX_P2_SDVO_DAC_FAST }, +    }, +    { /* INTEL_LIMIT_I9XX_LVDS */ +        .dot = { .min = I9XX_DOT_MIN,		.max = I9XX_DOT_MAX }, +        .vco = { .min = I9XX_VCO_MIN,		.max = I9XX_VCO_MAX }, +        .n   = { .min = I9XX_N_MIN,		.max = I9XX_N_MAX }, +        .m   = { .min = I9XX_M_MIN,		.max = I9XX_M_MAX }, +        .m1  = { .min = I9XX_M1_MIN,		.max = I9XX_M1_MAX }, +        .m2  = { .min = I9XX_M2_MIN,		.max = I9XX_M2_MAX }, +        .p   = { .min = I9XX_P_LVDS_MIN,	.max = I9XX_P_LVDS_MAX }, +        .p1  = { .min = I9XX_P1_MIN,		.max = I9XX_P1_MAX }, +	/* The single-channel range is 25-112Mhz, and dual-channel +	 * is 80-224Mhz.  Prefer single channel as much as possible. +	 */ +	.p2  = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT, +		 .p2_slow = I9XX_P2_LVDS_SLOW,	.p2_fast = I9XX_P2_LVDS_FAST }, +    }, +}; + +static const intel_limit_t *intel_limit(struct drm_crtc *crtc) +{ +	struct drm_device *dev = crtc->dev; +	const intel_limit_t *limit; +	 +	if (IS_I9XX(dev)) { +		if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) +			limit = &intel_limits[INTEL_LIMIT_I9XX_LVDS]; +		else +			limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC]; +	} else { +		if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) +			limit = &intel_limits[INTEL_LIMIT_I8XX_LVDS]; +		else +			limit = &intel_limits[INTEL_LIMIT_I8XX_DVO_DAC]; +	} +	return limit; +} + +/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ + +static void i8xx_clock(int refclk, intel_clock_t *clock) +{ +	clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); +	clock->p = clock->p1 * clock->p2; +	clock->vco = refclk * clock->m / (clock->n + 2); +	clock->dot = clock->vco / clock->p; +} + +/** Derive the pixel clock for the given refclk and divisors for 9xx chips. */ + +static void i9xx_clock(int refclk, intel_clock_t *clock) +{ +	clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); +	clock->p = clock->p1 * clock->p2; +	clock->vco = refclk * clock->m / (clock->n + 2); +	clock->dot = clock->vco / clock->p; +} + +static void intel_clock(struct drm_device *dev, int refclk, +			intel_clock_t *clock) +{ +	if (IS_I9XX(dev)) +		return i9xx_clock (refclk, clock); +	else +		return i8xx_clock (refclk, clock); +} + +/** + * Returns whether any output on the specified pipe is of the specified type + */ +bool intel_pipe_has_type (struct drm_crtc *crtc, int type) +{ +    struct drm_device *dev = crtc->dev; +    struct drm_mode_config *mode_config = &dev->mode_config; +    struct drm_output *l_entry; + +    list_for_each_entry(l_entry, &mode_config->output_list, head) { +	    if (l_entry->crtc == crtc) { +		    struct intel_output *intel_output = l_entry->driver_private; +		    if (intel_output->type == type) +			    return true; +	    } +    } +    return false; +} + +#define INTELPllInvalid(s)   { /* ErrorF (s) */; return false; } +/** + * Returns whether the given set of divisors are valid for a given refclk with + * the given outputs. + */ + +static bool intel_PLL_is_valid(struct drm_crtc *crtc, intel_clock_t *clock) +{ +	const intel_limit_t *limit = intel_limit (crtc); +	 +	if (clock->p1  < limit->p1.min  || limit->p1.max  < clock->p1) +		INTELPllInvalid ("p1 out of range\n"); +	if (clock->p   < limit->p.min   || limit->p.max   < clock->p) +		INTELPllInvalid ("p out of range\n"); +	if (clock->m2  < limit->m2.min  || limit->m2.max  < clock->m2) +		INTELPllInvalid ("m2 out of range\n"); +	if (clock->m1  < limit->m1.min  || limit->m1.max  < clock->m1) +		INTELPllInvalid ("m1 out of range\n"); +	if (clock->m1 <= clock->m2) +		INTELPllInvalid ("m1 <= m2\n"); +	if (clock->m   < limit->m.min   || limit->m.max   < clock->m) +		INTELPllInvalid ("m out of range\n"); +	if (clock->n   < limit->n.min   || limit->n.max   < clock->n) +		INTELPllInvalid ("n out of range\n"); +	if (clock->vco < limit->vco.min || limit->vco.max < clock->vco) +		INTELPllInvalid ("vco out of range\n"); +	/* XXX: We may need to be checking "Dot clock" depending on the multiplier, +	 * output, etc., rather than just a single range. +	 */ +	if (clock->dot < limit->dot.min || limit->dot.max < clock->dot) +		INTELPllInvalid ("dot out of range\n"); +	 +	return true; +} + +/** + * Returns a set of divisors for the desired target clock with the given + * refclk, or FALSE.  The returned values represent the clock equation: + * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. + */ +static bool intel_find_best_PLL(struct drm_crtc *crtc, int target, +				int refclk, intel_clock_t *best_clock) +{ +	struct drm_device *dev = crtc->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	intel_clock_t clock; +	const intel_limit_t *limit = intel_limit(crtc); +	int err = target; + +	if (IS_I9XX(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && +	    (I915_READ(LVDS) & LVDS_PORT_EN) != 0) { +		/* +		 * For LVDS, if the panel is on, just rely on its current +		 * settings for dual-channel.  We haven't figured out how to +		 * reliably set up different single/dual channel state, if we +		 * even can. +		 */ +		if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == +		    LVDS_CLKB_POWER_UP) +			clock.p2 = limit->p2.p2_fast; +		else +			clock.p2 = limit->p2.p2_slow; +	} else { +		if (target < limit->p2.dot_limit) +			clock.p2 = limit->p2.p2_slow; +		else +			clock.p2 = limit->p2.p2_fast; +	} +	 +	memset (best_clock, 0, sizeof (*best_clock)); +	 +	for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) { +		for (clock.m2 = limit->m2.min; clock.m2 < clock.m1 && +			     clock.m2 <= limit->m2.max; clock.m2++) { +			for (clock.n = limit->n.min; clock.n <= limit->n.max; +			     clock.n++) { +				for (clock.p1 = limit->p1.min; +				     clock.p1 <= limit->p1.max; clock.p1++) { +					int this_err; +					 +					intel_clock(dev, refclk, &clock); +					 +					if (!intel_PLL_is_valid(crtc, &clock)) +						continue; +					 +					this_err = abs(clock.dot - target); +					if (this_err < err) { +						*best_clock = clock; +						err = this_err; +					} +				} +			} +		} +	} + +	return (err != target); +} + +void +intel_set_vblank(struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_crtc *crtc; +	struct intel_crtc *intel_crtc; +	int vbl_pipe = 0; + +	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { +		intel_crtc = crtc->driver_private; + +		if (crtc->enabled) +			vbl_pipe |= (1<<intel_crtc->pipe); +	} + +	dev_priv->vblank_pipe = vbl_pipe; +	i915_enable_interrupt(dev); +} +void +intel_wait_for_vblank(struct drm_device *dev) +{ +	/* Wait for 20ms, i.e. one cycle at 50hz. */ +	udelay(20000); +} + +void +intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) +{ +	struct drm_device *dev = crtc->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_i915_master_private *master_priv; +	struct intel_crtc *intel_crtc = crtc->driver_private; +	int pipe = intel_crtc->pipe; +	unsigned long Start, Offset; +	int dspbase = (pipe == 0 ? DSPABASE : DSPBBASE); +	int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF); + +	Start = crtc->fb->bo->offset; +	Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8); + +	DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y); +	if (IS_I965G(dev)) { +		I915_WRITE(dspbase, Offset); +		I915_READ(dspbase); +		I915_WRITE(dspsurf, Start); +		I915_READ(dspsurf); +	} else { +		I915_WRITE(dspbase, Start + Offset); +		I915_READ(dspbase); +	} +	 + +	if (!dev->primary->master) +		return; + +	master_priv = dev->primary->master->driver_priv; +	if (!master_priv->sarea_priv)  +		return; +		 +	switch (pipe) { +	case 0: +		master_priv->sarea_priv->planeA_x = x; +		master_priv->sarea_priv->planeA_y = y; +		break; +	case 1: +		master_priv->sarea_priv->planeB_x = x; +		master_priv->sarea_priv->planeB_y = y; +		break; +	default: +		DRM_ERROR("Can't update pipe %d in SAREA\n", pipe); +		break; +	} +} + + + +/** + * Sets the power management mode of the pipe and plane. + * + * This code should probably grow support for turning the cursor off and back + * on appropriately at the same time as we're turning the pipe off/on. + */ +static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) +{ +	struct drm_device *dev = crtc->dev; +	struct drm_i915_master_private *master_priv; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_crtc *intel_crtc = crtc->driver_private; +	int pipe = intel_crtc->pipe; +	int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; +	int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; +	int dspbase_reg = (pipe == 0) ? DSPABASE : DSPBBASE; +	int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; +	u32 temp; +	bool enabled; + +	/* XXX: When our outputs are all unaware of DPMS modes other than off +	 * and on, we should map those modes to DPMSModeOff in the CRTC. +	 */ +	switch (mode) { +	case DPMSModeOn: +	case DPMSModeStandby: +	case DPMSModeSuspend: +		/* Enable the DPLL */ +		temp = I915_READ(dpll_reg); +		if ((temp & DPLL_VCO_ENABLE) == 0) { +			I915_WRITE(dpll_reg, temp); +			I915_READ(dpll_reg); +			/* Wait for the clocks to stabilize. */ +			udelay(150); +			I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); +			I915_READ(dpll_reg); +			/* Wait for the clocks to stabilize. */ +			udelay(150); +			I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); +			I915_READ(dpll_reg); +			/* Wait for the clocks to stabilize. */ +			udelay(150); +		} +		 +		/* Enable the pipe */ +		temp = I915_READ(pipeconf_reg); +		if ((temp & PIPEACONF_ENABLE) == 0) +			I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE); +		 +		/* Enable the plane */ +		temp = I915_READ(dspcntr_reg); +		if ((temp & DISPLAY_PLANE_ENABLE) == 0) { +			I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE); +			/* Flush the plane changes */ +			I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); +		} +		 +		intel_crtc_load_lut(crtc); +		 +		/* Give the overlay scaler a chance to enable if it's on this pipe */ +		//intel_crtc_dpms_video(crtc, TRUE); TODO +	break; +	case DPMSModeOff: +		/* Give the overlay scaler a chance to disable if it's on this pipe */ +		//intel_crtc_dpms_video(crtc, FALSE); TODO +		 +		/* Disable the VGA plane that we never use */ +		I915_WRITE(VGACNTRL, VGA_DISP_DISABLE); +		 +		/* Disable display plane */ +		temp = I915_READ(dspcntr_reg); +		if ((temp & DISPLAY_PLANE_ENABLE) != 0) { +			I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); +			/* Flush the plane changes */ +			I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); +			I915_READ(dspbase_reg); +		} +		 +		if (!IS_I9XX(dev)) { +			/* Wait for vblank for the disable to take effect */ +			intel_wait_for_vblank(dev); +		} +		 +		/* Next, disable display pipes */ +		temp = I915_READ(pipeconf_reg); +		if ((temp & PIPEACONF_ENABLE) != 0) { +			I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); +			I915_READ(pipeconf_reg); +		} +		 +		/* Wait for vblank for the disable to take effect. */ +		intel_wait_for_vblank(dev); +		 +		temp = I915_READ(dpll_reg); +		if ((temp & DPLL_VCO_ENABLE) != 0) { +			I915_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE); +			I915_READ(dpll_reg); +		} +		 +		/* Wait for the clocks to turn off. */ +		udelay(150); +		break; +	} + +	if (!dev->primary->master) +		return;	 + +	master_priv = dev->primary->master->driver_priv; +	if (!master_priv->sarea_priv) +		return; + +	enabled = crtc->enabled && mode != DPMSModeOff; +	 +	switch (pipe) { +	case 0: +		master_priv->sarea_priv->planeA_w = enabled ? crtc->mode.hdisplay : 0; +		master_priv->sarea_priv->planeA_h = enabled ? crtc->mode.vdisplay : 0; +		break; +	case 1: +		master_priv->sarea_priv->planeB_w = enabled ? crtc->mode.hdisplay : 0; +		master_priv->sarea_priv->planeB_h = enabled ? crtc->mode.vdisplay : 0; +		break; +	default: +		DRM_ERROR("Can't update pipe %d in SAREA\n", pipe); +		break; +	} +} + +static bool intel_crtc_lock(struct drm_crtc *crtc) +{ +   /* Sync the engine before mode switch */ +//   i830WaitSync(crtc->scrn); + +#if 0 // TODO def XF86DRI +    return I830DRILock(crtc->scrn); +#else +    return FALSE; +#endif +} + +static void intel_crtc_unlock (struct drm_crtc *crtc) +{ +#if 0 // TODO def XF86DRI +    I830DRIUnlock (crtc->scrn); +#endif +} + +static void intel_crtc_prepare (struct drm_crtc *crtc) +{ +	crtc->funcs->dpms(crtc, DPMSModeOff); +} + +static void intel_crtc_commit (struct drm_crtc *crtc) +{ +	crtc->funcs->dpms(crtc, DPMSModeOn); +} + +void intel_output_prepare (struct drm_output *output) +{ +	/* lvds has its own version of prepare see intel_lvds_prepare */ +	output->funcs->dpms(output, DPMSModeOff); +} + +void intel_output_commit (struct drm_output *output) +{ +	/* lvds has its own version of commit see intel_lvds_commit */ +	output->funcs->dpms(output, DPMSModeOn); +} + +static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, +				  struct drm_display_mode *mode, +				  struct drm_display_mode *adjusted_mode) +{ +	return true; +} + + +/** Returns the core display clock speed for i830 - i945 */ +static int intel_get_core_clock_speed(struct drm_device *dev) +{ + +	/* Core clock values taken from the published datasheets. +	 * The 830 may go up to 166 Mhz, which we should check. +	 */ +	if (IS_I945G(dev)) +		return 400000; +	else if (IS_I915G(dev)) +		return 333000; +	else if (IS_I945GM(dev) || IS_845G(dev)) +		return 200000; +	else if (IS_I915GM(dev)) { +		u16 gcfgc = 0; + +		pci_read_config_word(dev->pdev, I915_GCFGC, &gcfgc); +		 +		if (gcfgc & I915_LOW_FREQUENCY_ENABLE) +			return 133000; +		else { +			switch (gcfgc & I915_DISPLAY_CLOCK_MASK) { +			case I915_DISPLAY_CLOCK_333_MHZ: +				return 333000; +			default: +			case I915_DISPLAY_CLOCK_190_200_MHZ: +				return 190000; +			} +		} +	} else if (IS_I865G(dev)) +		return 266000; +	else if (IS_I855(dev)) { +#if 0 +		PCITAG bridge = pciTag(0, 0, 0); /* This is always the host bridge */ +		u16 hpllcc = pciReadWord(bridge, I855_HPLLCC); +		 +#endif +		u16 hpllcc = 0; +		/* Assume that the hardware is in the high speed state.  This +		 * should be the default. +		 */ +		switch (hpllcc & I855_CLOCK_CONTROL_MASK) { +		case I855_CLOCK_133_200: +		case I855_CLOCK_100_200: +			return 200000; +		case I855_CLOCK_166_250: +			return 250000; +		case I855_CLOCK_100_133: +			return 133000; +		} +	} else /* 852, 830 */ +		return 133000; +	 +	return 0; /* Silence gcc warning */ +} + + +/** + * Return the pipe currently connected to the panel fitter, + * or -1 if the panel fitter is not present or not in use + */ +static int intel_panel_fitter_pipe (struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	u32  pfit_control; +     +	/* i830 doesn't have a panel fitter */ +	if (IS_I830(dev)) +		return -1; +     +	pfit_control = I915_READ(PFIT_CONTROL); +     +	/* See if the panel fitter is in use */ +	if ((pfit_control & PFIT_ENABLE) == 0) +		return -1; +	 +	/* 965 can place panel fitter on either pipe */ +	if (IS_I965G(dev)) +		return (pfit_control >> 29) & 0x3; +	 +	/* older chips can only use pipe 1 */ +	return 1; +} + +static void intel_crtc_mode_set(struct drm_crtc *crtc, +				struct drm_display_mode *mode, +				struct drm_display_mode *adjusted_mode, +				int x, int y) +{ +	struct drm_device *dev = crtc->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_crtc *intel_crtc = crtc->driver_private; +	int pipe = intel_crtc->pipe; +	int fp_reg = (pipe == 0) ? FPA0 : FPB0; +	int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; +	int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD; +	int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; +	int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; +	int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; +	int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; +	int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; +	int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; +	int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; +	int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; +	int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE; +	int dspstride_reg = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE; +	int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS; +	int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC; +	int refclk; +	intel_clock_t clock; +	u32 dpll = 0, fp = 0, dspcntr, pipeconf; +	bool ok, is_sdvo = false, is_dvo = false; +	bool is_crt = false, is_lvds = false, is_tv = false; +	struct drm_mode_config *mode_config = &dev->mode_config; +	struct drm_output *output; + +	list_for_each_entry(output, &mode_config->output_list, head) { +		struct intel_output *intel_output = output->driver_private; + +		if (output->crtc != crtc) +			continue; + +		switch (intel_output->type) { +		case INTEL_OUTPUT_LVDS: +			is_lvds = TRUE; +			break; +		case INTEL_OUTPUT_SDVO: +			is_sdvo = TRUE; +			break; +		case INTEL_OUTPUT_DVO: +			is_dvo = TRUE; +			break; +		case INTEL_OUTPUT_TVOUT: +			is_tv = TRUE; +			break; +		case INTEL_OUTPUT_ANALOG: +			is_crt = TRUE; +			break; +		} +	} +	 +	if (IS_I9XX(dev)) { +		refclk = 96000; +	} else { +		refclk = 48000; +	} + +	ok = intel_find_best_PLL(crtc, adjusted_mode->clock, refclk, &clock); +	if (!ok) { +		DRM_ERROR("Couldn't find PLL settings for mode!\n"); +		return; +	} + +	fp = clock.n << 16 | clock.m1 << 8 | clock.m2; +	 +	dpll = DPLL_VGA_MODE_DIS; +	if (IS_I9XX(dev)) { +		if (is_lvds) +			dpll |= DPLLB_MODE_LVDS; +		else +			dpll |= DPLLB_MODE_DAC_SERIAL; +		if (is_sdvo) { +			dpll |= DPLL_DVO_HIGH_SPEED; +			if (IS_I945G(dev) || IS_I945GM(dev)) { +				int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; +				dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; +			} +		} +		 +		/* compute bitmask from p1 value */ +		dpll |= (1 << (clock.p1 - 1)) << 16; +		switch (clock.p2) { +		case 5: +			dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; +			break; +		case 7: +			dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7; +			break; +		case 10: +			dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10; +			break; +		case 14: +			dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; +			break; +		} +		if (IS_I965G(dev)) +			dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); +	} else { +		if (is_lvds) { +			dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; +		} else { +			if (clock.p1 == 2) +				dpll |= PLL_P1_DIVIDE_BY_TWO; +			else +				dpll |= (clock.p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT; +			if (clock.p2 == 4) +				dpll |= PLL_P2_DIVIDE_BY_4; +		} +	} +	 +	if (is_tv) { +		/* XXX: just matching BIOS for now */ +/*	dpll |= PLL_REF_INPUT_TVCLKINBC; */ +		dpll |= 3; +	} +#if 0 +	else if (is_lvds) +		dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; +#endif +	else +		dpll |= PLL_REF_INPUT_DREFCLK; +	 +	/* setup pipeconf */ +	pipeconf = I915_READ(pipeconf_reg); + +	/* Set up the display plane register */ +	dspcntr = DISPPLANE_GAMMA_ENABLE; + +	switch (crtc->fb->bits_per_pixel) { +	case 8: +		dspcntr |= DISPPLANE_8BPP; +		break; +	case 16: +		if (crtc->fb->depth == 15) +			dspcntr |= DISPPLANE_15_16BPP; +		else +			dspcntr |= DISPPLANE_16BPP; +		break; +	case 24: +	case 32: +		dspcntr |= DISPPLANE_32BPP_NO_ALPHA; +		break; +	default: +		DRM_ERROR("Unknown color depth\n"); +		return; +	} +	 + +	if (pipe == 0) +		dspcntr |= DISPPLANE_SEL_PIPE_A; +	else +		dspcntr |= DISPPLANE_SEL_PIPE_B; +	 +	if (pipe == 0 && !IS_I965G(dev)) { +		/* Enable pixel doubling when the dot clock is > 90% of the (display) +		 * core speed. +		 * +		 * XXX: No double-wide on 915GM pipe B. Is that the only reason for the +		 * pipe == 0 check? +		 */ +		if (mode->clock > intel_get_core_clock_speed(dev) * 9 / 10) +			pipeconf |= PIPEACONF_DOUBLE_WIDE; +		else +			pipeconf &= ~PIPEACONF_DOUBLE_WIDE; +	} + +	dspcntr |= DISPLAY_PLANE_ENABLE; +	pipeconf |= PIPEACONF_ENABLE; +	dpll |= DPLL_VCO_ENABLE; + +	 +	/* Disable the panel fitter if it was on our pipe */ +	if (intel_panel_fitter_pipe(dev) == pipe) +		I915_WRITE(PFIT_CONTROL, 0); + +	DRM_DEBUG("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); +	drm_mode_debug_printmodeline(dev, mode); +	 +#if 0 +	if (!xf86ModesEqual(mode, adjusted_mode)) { +		xf86DrvMsg(pScrn->scrnIndex, X_INFO, +			   "Adjusted mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); +		xf86PrintModeline(pScrn->scrnIndex, mode); +	} +	i830PrintPll("chosen", &clock); +#endif + +	if (dpll & DPLL_VCO_ENABLE) { +		I915_WRITE(fp_reg, fp); +		I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE); +		I915_READ(dpll_reg); +		udelay(150); +	} +	 +	/* The LVDS pin pair needs to be on before the DPLLs are enabled. +	 * This is an exception to the general rule that mode_set doesn't turn +	 * things on. +	 */ +	if (is_lvds) { +		u32 lvds = I915_READ(LVDS); +		 +		lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT; +		/* Set the B0-B3 data pairs corresponding to whether we're going to +		 * set the DPLLs for dual-channel mode or not. +		 */ +		if (clock.p2 == 7) +			lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; +		else +			lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); +		 +		/* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) +		 * appropriately here, but we need to look more thoroughly into how +		 * panels behave in the two modes. +		 */ +		 +		I915_WRITE(LVDS, lvds); +		I915_READ(LVDS); +	} +	 +	I915_WRITE(fp_reg, fp); +	I915_WRITE(dpll_reg, dpll); +	I915_READ(dpll_reg); +	/* Wait for the clocks to stabilize. */ +	udelay(150); +	 +	if (IS_I965G(dev)) { +		int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; +		I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | +			   ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); +	} else { +		/* write it again -- the BIOS does, after all */ +		I915_WRITE(dpll_reg, dpll); +	} +	I915_READ(dpll_reg); +	/* Wait for the clocks to stabilize. */ +	udelay(150); +	 +	I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) | +		   ((adjusted_mode->crtc_htotal - 1) << 16)); +	I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | +		   ((adjusted_mode->crtc_hblank_end - 1) << 16)); +	I915_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | +		   ((adjusted_mode->crtc_hsync_end - 1) << 16)); +	I915_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | +		   ((adjusted_mode->crtc_vtotal - 1) << 16)); +	I915_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | +		   ((adjusted_mode->crtc_vblank_end - 1) << 16)); +	I915_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | +		   ((adjusted_mode->crtc_vsync_end - 1) << 16)); +	I915_WRITE(dspstride_reg, crtc->fb->pitch); +	/* pipesrc and dspsize control the size that is scaled from, which should +	 * always be the user's requested size. +	 */ +	I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); +	I915_WRITE(dsppos_reg, 0); +	I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); +	I915_WRITE(pipeconf_reg, pipeconf); +	I915_READ(pipeconf_reg); +	 +	intel_wait_for_vblank(dev); +	 +	I915_WRITE(dspcntr_reg, dspcntr); +	 +	/* Flush the plane changes */ +	intel_pipe_set_base(crtc, x, y); +	 +	intel_set_vblank(dev); + +	intel_wait_for_vblank(dev);     +} + +/** Loads the palette/gamma unit for the CRTC with the prepared values */ +void intel_crtc_load_lut(struct drm_crtc *crtc) +{ +	struct drm_device *dev = crtc->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_crtc *intel_crtc = crtc->driver_private; +	int palreg = (intel_crtc->pipe == 0) ? PALETTE_A : PALETTE_B; +	int i; + +	/* The clocks have to be on to load the palette. */ +	if (!crtc->enabled) +		return; + +	for (i = 0; i < 256; i++) { +		I915_WRITE(palreg + 4 * i, +			   (intel_crtc->lut_r[i] << 16) | +			   (intel_crtc->lut_g[i] << 8) | +			   intel_crtc->lut_b[i]); +	} +} + +#define CURSOR_A_CONTROL        0x70080 +#define CURSOR_A_BASE           0x70084 +#define CURSOR_A_POSITION       0x70088 + +#define CURSOR_B_CONTROL        0x700C0 +#define CURSOR_B_BASE           0x700C4 +#define CURSOR_B_POSITION       0x700C8 + +#define CURSOR_MODE_DISABLE     0x00 +#define CURSOR_MODE_64_32B_AX   0x07 +#define CURSOR_MODE_64_ARGB_AX  ((1 << 5) | CURSOR_MODE_64_32B_AX) +#define MCURSOR_GAMMA_ENABLE    (1 << 26) + +#define CURSOR_POS_MASK         0x007FF +#define CURSOR_POS_SIGN         0x8000 +#define CURSOR_X_SHIFT          0 +#define CURSOR_Y_SHIFT          16 + +static int intel_crtc_cursor_set(struct drm_crtc *crtc, +				 struct drm_buffer_object *bo, +				 uint32_t width, uint32_t height) +{ +	struct drm_device *dev = crtc->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_crtc *intel_crtc = crtc->driver_private; +	int pipe = intel_crtc->pipe; +	uint32_t control = (pipe == 0) ? CURSOR_A_CONTROL : CURSOR_B_CONTROL; +	uint32_t base = (pipe == 0) ? CURSOR_A_BASE : CURSOR_B_BASE; +	uint32_t temp; +	size_t adder; + +	DRM_DEBUG("\n"); + +	/* if we want to turn of the cursor ignore width and height */ +	if (!bo) { +		DRM_DEBUG("cursor off\n"); +		/* turn of the cursor */ +		temp = 0; +		temp |= CURSOR_MODE_DISABLE; + +		I915_WRITE(control, temp); +		I915_WRITE(base, 0); +		return 0; +	} + +	/* Currently we only support 64x64 cursors */ +	if (width != 64 || height != 64) { +		DRM_ERROR("we currently only support 64x64 cursors\n"); +		return -EINVAL; +	} + +	if ((bo->mem.flags & DRM_BO_MASK_MEM) != DRM_BO_FLAG_MEM_VRAM) { +		DRM_ERROR("buffer needs to be in VRAM\n"); +		return -ENOMEM; +	} + +	if (bo->mem.size < width * height * 4) { +		DRM_ERROR("buffer is to small\n"); +		return -ENOMEM; +	} + +	adder = dev_priv->stolen_base + bo->offset; +	intel_crtc->cursor_adder = adder; +	temp = 0; +	/* set the pipe for the cursor */ +	temp |= (pipe << 28); +	temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; + +	DRM_DEBUG("cusror base %x\n", adder); + +	I915_WRITE(control, temp); +	I915_WRITE(base, adder); + +	return 0; +} + +static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) +{ +	struct drm_device *dev = crtc->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_crtc *intel_crtc = crtc->driver_private; +	int pipe = intel_crtc->pipe; +	uint32_t temp = 0; +	uint32_t adder; + +	if (x < 0) { +		temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT); +		x = -x; +	} +	if (y < 0) { +		temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT); +		y = -y; +	} + +	temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT); +	temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); + +	adder = intel_crtc->cursor_adder; +	I915_WRITE((pipe == 0) ? CURSOR_A_POSITION : CURSOR_B_POSITION, temp); +	I915_WRITE((pipe == 0) ? CURSOR_A_BASE : CURSOR_B_BASE, adder); + +	return 0; +} + +/** Sets the color ramps on behalf of RandR */ +static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, +				 u16 blue, int regno) +{ +	struct intel_crtc *intel_crtc = crtc->driver_private; +	 +	intel_crtc->lut_r[regno] = red >> 8; +	intel_crtc->lut_g[regno] = green >> 8; +	intel_crtc->lut_b[regno] = blue >> 8; +} + +/* Returns the clock of the currently programmed mode of the given pipe. */ +static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_crtc *intel_crtc = crtc->driver_private; +	int pipe = intel_crtc->pipe; +	u32 dpll = I915_READ((pipe == 0) ? DPLL_A : DPLL_B); +	u32 fp; +	intel_clock_t clock; + +	if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) +		fp = I915_READ((pipe == 0) ? FPA0 : FPB0); +	else +		fp = I915_READ((pipe == 0) ? FPA1 : FPB1); + +	clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; +	clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; +	clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT; +	if (IS_I9XX(dev)) { +		clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >> +			       DPLL_FPA01_P1_POST_DIV_SHIFT); + +		switch (dpll & DPLL_MODE_MASK) { +		case DPLLB_MODE_DAC_SERIAL: +			clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? +				5 : 10; +			break; +		case DPLLB_MODE_LVDS: +			clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ? +				7 : 14; +			break; +		default: +			DRM_DEBUG("Unknown DPLL mode %08x in programmed " +				  "mode\n", (int)(dpll & DPLL_MODE_MASK)); +			return 0; +		} + +		/* XXX: Handle the 100Mhz refclk */ +		i9xx_clock(96000, &clock); +	} else { +		bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN); + +		if (is_lvds) { +			clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> +				       DPLL_FPA01_P1_POST_DIV_SHIFT); +			clock.p2 = 14; + +			if ((dpll & PLL_REF_INPUT_MASK) == +			    PLLB_REF_INPUT_SPREADSPECTRUMIN) { +				/* XXX: might not be 66MHz */ +				i8xx_clock(66000, &clock); +			} else +				i8xx_clock(48000, &clock);		 +		} else { +			if (dpll & PLL_P1_DIVIDE_BY_TWO) +				clock.p1 = 2; +			else { +				clock.p1 = ((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830) >> +					    DPLL_FPA01_P1_POST_DIV_SHIFT) + 2; +			} +			if (dpll & PLL_P2_DIVIDE_BY_4) +				clock.p2 = 4; +			else +				clock.p2 = 2; + +			i8xx_clock(48000, &clock); +		} +	} + +	/* XXX: It would be nice to validate the clocks, but we can't reuse +	 * i830PllIsValid() because it relies on the xf86_config output +	 * configuration being accurate, which it isn't necessarily. +	 */ + +	return clock.dot; +} + +/** Returns the currently programmed mode of the given pipe. */ +struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, +					     struct drm_crtc *crtc) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_crtc *intel_crtc = crtc->driver_private; +	int pipe = intel_crtc->pipe; +	struct drm_display_mode *mode; +	int htot = I915_READ((pipe == 0) ? HTOTAL_A : HTOTAL_B); +	int hsync = I915_READ((pipe == 0) ? HSYNC_A : HSYNC_B); +	int vtot = I915_READ((pipe == 0) ? VTOTAL_A : VTOTAL_B); +	int vsync = I915_READ((pipe == 0) ? VSYNC_A : VSYNC_B); + +	mode = kzalloc(sizeof(*mode), GFP_KERNEL); +	if (!mode) +		return NULL; + +	mode->clock = intel_crtc_clock_get(dev, crtc); +	mode->hdisplay = (htot & 0xffff) + 1; +	mode->htotal = ((htot & 0xffff0000) >> 16) + 1; +	mode->hsync_start = (hsync & 0xffff) + 1; +	mode->hsync_end = ((hsync & 0xffff0000) >> 16) + 1; +	mode->vdisplay = (vtot & 0xffff) + 1; +	mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1; +	mode->vsync_start = (vsync & 0xffff) + 1; +	mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1; + +	drm_mode_set_name(mode); +	drm_mode_set_crtcinfo(mode, 0); + +	return mode; +} + +static const struct drm_crtc_funcs intel_crtc_funcs = { +	.dpms = intel_crtc_dpms, +	.lock = intel_crtc_lock, +	.unlock = intel_crtc_unlock, +	.mode_fixup = intel_crtc_mode_fixup, +	.mode_set = intel_crtc_mode_set, +	.mode_set_base = intel_pipe_set_base, +	.cursor_set = intel_crtc_cursor_set, +	.cursor_move = intel_crtc_cursor_move, +	.gamma_set = intel_crtc_gamma_set, +	.prepare = intel_crtc_prepare, +	.commit = intel_crtc_commit, +}; + + +void intel_crtc_init(struct drm_device *dev, int pipe) +{ +	struct drm_crtc *crtc; +	struct intel_crtc *intel_crtc; +	int i; + +	crtc = drm_crtc_create(dev, &intel_crtc_funcs); +	if (crtc == NULL) +		return; + +	intel_crtc = kzalloc(sizeof(struct intel_crtc), GFP_KERNEL); +	if (intel_crtc == NULL) { +		kfree(crtc); +		return; +	} + +	intel_crtc->pipe = pipe; +	for (i = 0; i < 256; i++) { +		intel_crtc->lut_r[i] = i; +		intel_crtc->lut_g[i] = i; +		intel_crtc->lut_b[i] = i; +	} + +	intel_crtc->cursor_adder = 0; + +	crtc->driver_private = intel_crtc; +} + +struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe) +{ +	struct drm_crtc *crtc = NULL; + +	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { +		struct intel_crtc *intel_crtc = crtc->driver_private; +		if (intel_crtc->pipe == pipe) +			break; +	} +	return crtc; +} + +int intel_output_clones(struct drm_device *dev, int type_mask) +{ +	int index_mask = 0; +	struct drm_output *output; +	int entry = 0; + +        list_for_each_entry(output, &dev->mode_config.output_list, head) { +		struct intel_output *intel_output = output->driver_private; +		if (type_mask & (1 << intel_output->type)) +			index_mask |= (1 << entry); +		entry++; +	} +	return index_mask; +} + + +static void intel_setup_outputs(struct drm_device *dev) +{ +	struct drm_output *output; + +	intel_crt_init(dev); + +	/* Set up integrated LVDS */ +	if (IS_MOBILE(dev) && !IS_I830(dev)) +		intel_lvds_init(dev); + +	if (IS_I9XX(dev)) { +		intel_sdvo_init(dev, SDVOB); +		intel_sdvo_init(dev, SDVOC); +	} + +	list_for_each_entry(output, &dev->mode_config.output_list, head) { +		struct intel_output *intel_output = output->driver_private; +		int crtc_mask = 0, clone_mask = 0; +		 +		/* valid crtcs */ +		switch(intel_output->type) { +		case INTEL_OUTPUT_DVO: +		case INTEL_OUTPUT_SDVO: +			crtc_mask = ((1 << 0)| +				     (1 << 1)); +			clone_mask = ((1 << INTEL_OUTPUT_ANALOG) | +				      (1 << INTEL_OUTPUT_DVO) | +				      (1 << INTEL_OUTPUT_SDVO)); +			break; +		case INTEL_OUTPUT_ANALOG: +			crtc_mask = ((1 << 0)| +				     (1 << 1)); +			clone_mask = ((1 << INTEL_OUTPUT_ANALOG) | +				      (1 << INTEL_OUTPUT_DVO) | +				      (1 << INTEL_OUTPUT_SDVO)); +			break; +		case INTEL_OUTPUT_LVDS: +			crtc_mask = (1 << 1); +			clone_mask = (1 << INTEL_OUTPUT_LVDS); +			break; +		case INTEL_OUTPUT_TVOUT: +			crtc_mask = ((1 << 0) | +				     (1 << 1)); +			clone_mask = (1 << INTEL_OUTPUT_TVOUT); +			break; +		} +		output->possible_crtcs = crtc_mask; +		output->possible_clones = intel_output_clones(dev, clone_mask); +	} +} + +void intel_modeset_init(struct drm_device *dev) +{ +	int num_pipe; +	int i; + +	drm_mode_config_init(dev); + +	dev->mode_config.min_width = 0; +	dev->mode_config.min_height = 0; + +	dev->mode_config.max_width = 4096; +	dev->mode_config.max_height = 4096; + +	/* set memory base */ +	if (IS_I9XX(dev)) +		dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2); +	else +		dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0); + +	if (IS_MOBILE(dev) || IS_I9XX(dev)) +		num_pipe = 2; +	else +		num_pipe = 1; +	DRM_DEBUG("%d display pipe%s available.\n", +		  num_pipe, num_pipe > 1 ? "s" : ""); + +	for (i = 0; i < num_pipe; i++) { +		intel_crtc_init(dev, i); +	} + +	intel_setup_outputs(dev); + +	//drm_initial_config(dev, false); +} + +void intel_modeset_cleanup(struct drm_device *dev) +{ +	drm_mode_config_cleanup(dev); +} diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h new file mode 100644 index 00000000..72ba01da --- /dev/null +++ b/linux-core/intel_drv.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2006 Dave Airlie <airlied@linux.ie> + * Copyright (c) 2007 Intel Corporation + *   Jesse Barnes <jesse.barnes@intel.com> + */ +#ifndef __INTEL_DRV_H__ +#define __INTEL_DRV_H__ + +#include <linux/i2c.h> +#include <linux/i2c-id.h> +#include <linux/i2c-algo-bit.h> +#include "drm_crtc.h" + +/* + * Display related stuff + */ + +/* store information about an Ixxx DVO */ +/* The i830->i865 use multiple DVOs with multiple i2cs */ +/* the i915, i945 have a single sDVO i2c bus - which is different */ +#define MAX_OUTPUTS 6 + +#define INTEL_I2C_BUS_DVO 1 +#define INTEL_I2C_BUS_SDVO 2 + +/* these are outputs from the chip - integrated only  +   external chips are via DVO or SDVO output */ +#define INTEL_OUTPUT_UNUSED 0 +#define INTEL_OUTPUT_ANALOG 1 +#define INTEL_OUTPUT_DVO 2 +#define INTEL_OUTPUT_SDVO 3 +#define INTEL_OUTPUT_LVDS 4 +#define INTEL_OUTPUT_TVOUT 5 + +#define INTEL_DVO_CHIP_NONE 0 +#define INTEL_DVO_CHIP_LVDS 1 +#define INTEL_DVO_CHIP_TMDS 2 +#define INTEL_DVO_CHIP_TVOUT 4 + +struct intel_i2c_chan { +	struct drm_device *drm_dev; /* for getting at dev. private (mmio etc.) */ +	u32 reg; /* GPIO reg */ +	struct i2c_adapter adapter; +	struct i2c_algo_bit_data algo; +        u8 slave_addr; +}; + +struct intel_output { +	int type; +	struct intel_i2c_chan *i2c_bus; /* for control functions */ +	struct intel_i2c_chan *ddc_bus; /* for DDC only stuff */ +	bool load_detect_temp; +	void *dev_priv; +}; + +struct intel_crtc { +	int pipe; +	int plane; +	uint32_t cursor_adder; +	u8 lut_r[256], lut_g[256], lut_b[256]; +}; + +struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, +					const char *name); +void intel_i2c_destroy(struct intel_i2c_chan *chan); +int intel_ddc_get_modes(struct drm_output *output); +extern bool intel_ddc_probe(struct drm_output *output); + +extern void intel_crt_init(struct drm_device *dev); +extern void intel_sdvo_init(struct drm_device *dev, int output_device); +extern void intel_lvds_init(struct drm_device *dev); + +extern void intel_crtc_load_lut(struct drm_crtc *crtc); +extern void intel_output_prepare (struct drm_output *output); +extern void intel_output_commit (struct drm_output *output); +extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, + 						    struct drm_crtc *crtc); +extern void intel_wait_for_vblank(struct drm_device *dev); +extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); + +extern struct drm_output* intel_sdvo_find(struct drm_device *dev, int sdvoB); +extern int intel_sdvo_supports_hotplug(struct drm_output *output); +extern void intel_sdvo_set_hotplug(struct drm_output *output, int enable); + +extern int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc); +extern int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc); +extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc); + +#endif /* __INTEL_DRV_H__ */ diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c new file mode 100644 index 00000000..6df243b0 --- /dev/null +++ b/linux-core/intel_fb.c @@ -0,0 +1,769 @@ +/* + * Copyright © 2007 David Airlie + * + * 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: + *     David Airlie + */ +    /* +     *  Modularization +     */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/init.h> + +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "i915_drm.h" +#include "i915_drv.h" + +struct intelfb_par { +	struct drm_device *dev; +	struct drm_crtc *crtc; +        struct drm_display_mode *fb_mode; +}; +/* +static int +var_to_refresh(const struct fb_var_screeninfo *var) +{ +	int xtot = var->xres + var->left_margin + var->right_margin + +		   var->hsync_len; +	int ytot = var->yres + var->upper_margin + var->lower_margin + +		   var->vsync_len; + +	return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot; +}*/ + +static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, +			   unsigned blue, unsigned transp, +			   struct fb_info *info) +{ +	struct intelfb_par *par = info->par; +	struct drm_framebuffer *fb = par->crtc->fb; +	struct drm_crtc *crtc = par->crtc; + +	if (regno > 255) +		return 1; + +	if (fb->depth == 8) { +		if (crtc->funcs->gamma_set) +			crtc->funcs->gamma_set(crtc, red, green, blue, regno); +		return 0; +	} + +	if (regno < 16) { +		switch (fb->depth) { +		case 15: +			fb->pseudo_palette[regno] = ((red & 0xf800) >>  1) | +				((green & 0xf800) >>  6) | +				((blue & 0xf800) >> 11); +			break; +		case 16: +			fb->pseudo_palette[regno] = (red & 0xf800) | +				((green & 0xfc00) >>  5) | +				((blue  & 0xf800) >> 11); +			break; +		case 24: +		case 32: +			fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | +				(green & 0xff00) | +				((blue  & 0xff00) >> 8); +			break; +		} +	} + +	return 0; +} + +static int intelfb_check_var(struct fb_var_screeninfo *var, +			     struct fb_info *info) +{ +        struct intelfb_par *par = info->par; +        /*struct drm_device *dev = par->dev;*/ +	struct drm_framebuffer *fb = par->crtc->fb; +        /*struct drm_output *output;*/ +        int depth/*, found = 0*/; + +        if (!var->pixclock) +                return -EINVAL; + +        /* Need to resize the fb object !!! */ +        if (var->xres > fb->width || var->yres > fb->height) { +                DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height); +                DRM_ERROR("Need resizing code.\n"); +                return -EINVAL; +        } + +        switch (var->bits_per_pixel) { +        case 16: +                depth = (var->green.length == 6) ? 16 : 15; +                break; +        case 32: +                depth = (var->transp.length > 0) ? 32 : 24; +                break; +        default: +                depth = var->bits_per_pixel; +                break; +        } +                 +        switch (depth) { +        case 8: +                var->red.offset = 0; +                var->green.offset = 0; +                var->blue.offset = 0; +                var->red.length = 8; +                var->green.length = 8; +                var->blue.length = 8; +                var->transp.length = 0; +                var->transp.offset = 0; +                break; +        case 15: +                var->red.offset = 10; +                var->green.offset = 5; +                var->blue.offset = 0; +                var->red.length = 5; +                var->green.length = 5; +                var->blue.length = 5; +                var->transp.length = 1; +                var->transp.offset = 15; +                break; +        case 16: +                var->red.offset = 11; +                var->green.offset = 6; +                var->blue.offset = 0; +                var->red.length = 5; +                var->green.length = 6; +                var->blue.length = 5; +                var->transp.length = 0; +                var->transp.offset = 0; +                break; +        case 24: +                var->red.offset = 16; +                var->green.offset = 8; +                var->blue.offset = 0; +                var->red.length = 8; +                var->green.length = 8; +                var->blue.length = 8; +                var->transp.length = 0; +                var->transp.offset = 0; +                break; +        case 32: +                var->red.offset = 16; +                var->green.offset = 8; +                var->blue.offset = 0; +                var->red.length = 8; +                var->green.length = 8; +                var->blue.length = 8; +                var->transp.length = 8; +                var->transp.offset = 24; +                break; +        default: +                return -EINVAL;  +        } + +#if 0 +        /* Here we walk the output mode list and look for modes. If we haven't +         * got it, then bail. Not very nice, so this is disabled. +         * In the set_par code, we create our mode based on the incoming +         * parameters. Nicer, but may not be desired by some. +         */ +        list_for_each_entry(output, &dev->mode_config.output_list, head) { +                if (output->crtc == par->crtc) +                        break; +        } +     +        list_for_each_entry(drm_mode, &output->modes, head) { +                if (drm_mode->hdisplay == var->xres && +                    drm_mode->vdisplay == var->yres && +                    (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) && +                    (((PICOS2KHZ(var->pixclock))/1000) <= ((drm_mode->clock/1000)+1))) { +			found = 1; +			break; +		} +	} +  +        if (!found) +                return -EINVAL; +#endif + +	return 0; +} + +bool i915_drmfb_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2, unsigned int pixclock) +{ + +	if (mode1->hdisplay == mode2->hdisplay && +	    mode1->hsync_start == mode2->hsync_start && +	    mode1->hsync_end == mode2->hsync_end && +	    mode1->htotal == mode2->htotal && +	    mode1->hskew == mode2->hskew && +	    mode1->vdisplay == mode2->vdisplay && +	    mode1->vsync_start == mode2->vsync_start && +	    mode1->vsync_end == mode2->vsync_end && +	    mode1->vtotal == mode2->vtotal && +	    mode1->vscan == mode2->vscan && +	    mode1->flags == mode2->flags)  +	{ +		if (mode1->clock == mode2->clock) +			return true; + +		if (KHZ2PICOS(mode2->clock) == pixclock) +			return true; +		return false; +	} +	 +	return false; +} + +/* this will let fbcon do the mode init */ +/* FIXME: take mode config lock? */ +static int intelfb_set_par(struct fb_info *info) +{ +	struct intelfb_par *par = info->par; +	struct drm_framebuffer *fb = par->crtc->fb; +	struct drm_device *dev = par->dev; +        struct drm_display_mode *drm_mode, *search_mode; +        struct drm_output *output; +        struct fb_var_screeninfo *var = &info->var; +	int found = 0; + +	DRM_DEBUG("\n"); + +        switch (var->bits_per_pixel) { +        case 16: +                fb->depth = (var->green.length == 6) ? 16 : 15; +                break; +        case 32: +                fb->depth = (var->transp.length > 0) ? 32 : 24; +                break; +        default: +                fb->depth = var->bits_per_pixel; +                break; +        } + +        fb->bits_per_pixel = var->bits_per_pixel; + +        info->fix.line_length = fb->pitch; +        info->fix.smem_len = info->fix.line_length * fb->height; +        info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + +        info->screen_size = info->fix.smem_len; /* ??? */ + +	/* create a drm mode */ +        drm_mode = drm_mode_create(dev); +        drm_mode->hdisplay = var->xres; +        drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin; +        drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len; +        drm_mode->htotal = drm_mode->hsync_end + var->left_margin; +        drm_mode->vdisplay = var->yres; +        drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin; +        drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len; +        drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin; +        drm_mode->clock = PICOS2KHZ(var->pixclock); +        drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); +	drm_mode->flags = 0; +	drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC; +	drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC; + +        drm_mode_set_name(drm_mode); +	drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); + +        list_for_each_entry(output, &dev->mode_config.output_list, head) { +                if (output->crtc == par->crtc) +                        break; +        } + +	drm_mode_debug_printmodeline(dev, drm_mode);     +        list_for_each_entry(search_mode, &output->modes, head) { +		drm_mode_debug_printmodeline(dev, search_mode); +		if (i915_drmfb_mode_equal(drm_mode, search_mode, var->pixclock)) { +			drm_mode_destroy(dev, drm_mode); +			drm_mode = search_mode; +			found = 1; +			break; +		} +	} +	 +	if (!found) { +		if (par->fb_mode) { +			drm_mode_detachmode_crtc(dev, par->fb_mode); +		} +	 +		par->fb_mode = drm_mode; +		drm_mode_debug_printmodeline(dev, drm_mode); +		/* attach mode */ +		drm_mode_attachmode_crtc(dev, par->crtc, par->fb_mode); +	} + +	if (par->crtc->enabled) { +		if (!drm_mode_equal(&par->crtc->mode, drm_mode)) { +			if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) +				return -EINVAL; +		} else if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) { +			if (!par->crtc->funcs->mode_set_base) { +				if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) +					return -EINVAL; +			} else { +				par->crtc->funcs->mode_set_base(par->crtc, var->xoffset, var->yoffset); +				par->crtc->x = var->xoffset; +				par->crtc->y = var->yoffset; +			} +		} +	} +	return 0; +} + +#if 0 +static void intelfb_copyarea(struct fb_info *info, +			     const struct fb_copyarea *region) +{ +        struct intelfb_par *par = info->par; +	struct drm_device *dev = par->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	u32 src_x1, src_y1, dst_x1, dst_y1, dst_x2, dst_y2, offset; +	u32 cmd, rop_depth_pitch, src_pitch; +	RING_LOCALS; + +	cmd = XY_SRC_COPY_BLT_CMD; +	src_x1 = region->sx; +	src_y1 = region->sy; +	dst_x1 = region->dx; +	dst_y1 = region->dy; +	dst_x2 = region->dx + region->width; +	dst_y2 = region->dy + region->height; +	offset = par->fb->offset; +	rop_depth_pitch = BLT_ROP_GXCOPY | par->fb->pitch; +	src_pitch = par->fb->pitch; + +	switch (par->fb->bits_per_pixel) { +	case 16: +		rop_depth_pitch |= BLT_DEPTH_16_565; +		break; +	case 32: +		rop_depth_pitch |= BLT_DEPTH_32; +		cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB; +		break; +	} + +	BEGIN_LP_RING(8); +	OUT_RING(cmd); +	OUT_RING(rop_depth_pitch); +	OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff)); +	OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff)); +	OUT_RING(offset); +	OUT_RING((src_y1 << 16) | (src_x1 & 0xffff)); +	OUT_RING(src_pitch); +	OUT_RING(offset); +	ADVANCE_LP_RING(); +} + +#define ROUND_UP_TO(x, y)	(((x) + (y) - 1) / (y) * (y)) +#define ROUND_DOWN_TO(x, y)	((x) / (y) * (y)) + +void intelfb_imageblit(struct fb_info *info, const struct fb_image *image) +{ +        struct intelfb_par *par = info->par; +	struct drm_device *dev = par->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	u32 cmd, rop_pitch_depth, tmp; +	int nbytes, ndwords, pad; +	u32 dst_x1, dst_y1, dst_x2, dst_y2, offset, bg, fg; +	int dat, ix, iy, iw; +	int i, j; +	RING_LOCALS; + +	/* size in bytes of a padded scanline */ +	nbytes = ROUND_UP_TO(image->width, 16) / 8; + +	/* Total bytes of padded scanline data to write out. */ +	nbytes *= image->height; + +	/* +	 * Check if the glyph data exceeds the immediate mode limit. +	 * It would take a large font (1K pixels) to hit this limit. +	 */ +	if (nbytes > 128 || image->depth != 1) +		return cfb_imageblit(info, image); + +	/* Src data is packaged a dword (32-bit) at a time. */ +	ndwords = ROUND_UP_TO(nbytes, 4) / 4; + +	/* +	 * Ring has to be padded to a quad word. But because the command starts +	   with 7 bytes, pad only if there is an even number of ndwords +	 */ +	pad = !(ndwords % 2); + +	DRM_DEBUG("imageblit %dx%dx%d to (%d,%d)\n", image->width, +		  image->height, image->depth, image->dx, image->dy); +	DRM_DEBUG("nbytes: %d, ndwords: %d, pad: %d\n", nbytes, ndwords, pad); + +	tmp = (XY_MONO_SRC_COPY_IMM_BLT & 0xff) + ndwords; +	cmd = (XY_MONO_SRC_COPY_IMM_BLT & ~0xff) | tmp; +	offset = par->fb->offset; +	dst_x1 = image->dx; +	dst_y1 = image->dy; +	dst_x2 = image->dx + image->width; +	dst_y2 = image->dy + image->height; +	rop_pitch_depth = BLT_ROP_GXCOPY | par->fb->pitch; + +	switch (par->fb->bits_per_pixel) { +	case 8: +		rop_pitch_depth |= BLT_DEPTH_8; +		fg = image->fg_color; +		bg = image->bg_color; +		break; +	case 16: +		rop_pitch_depth |= BLT_DEPTH_16_565; +		fg = par->fb->pseudo_palette[image->fg_color]; +		bg = par->fb->pseudo_palette[image->bg_color]; +		break; +	case 32: +		rop_pitch_depth |= BLT_DEPTH_32; +		cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB; +		fg = par->fb->pseudo_palette[image->fg_color]; +		bg = par->fb->pseudo_palette[image->bg_color]; +		break; +	default: +		DRM_ERROR("unknown depth %d\n", par->fb->bits_per_pixel); +		break; +	} +	 +	BEGIN_LP_RING(8 + ndwords); +	OUT_RING(cmd); +	OUT_RING(rop_pitch_depth); +	OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff)); +	OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff)); +	OUT_RING(offset); +	OUT_RING(bg); +	OUT_RING(fg); +	ix = iy = 0; +	iw = ROUND_UP_TO(image->width, 8) / 8; +	while (ndwords--) { +		dat = 0; +		for (j = 0; j < 2; ++j) { +			for (i = 0; i < 2; ++i) { +				if (ix != iw || i == 0) +					dat |= image->data[iy*iw + ix++] << (i+j*2)*8; +			} +			if (ix == iw && iy != (image->height - 1)) { +				ix = 0; +				++iy; +			} +		} +		OUT_RING(dat); +	} +	if (pad) +		OUT_RING(MI_NOOP); +	ADVANCE_LP_RING(); +} +#endif +static int intelfb_pan_display(struct fb_var_screeninfo *var, +			       struct fb_info *info) +{ +	struct intelfb_par *par = info->par; +	struct drm_crtc *crtc = par->crtc; + +	DRM_DEBUG("\n"); + +	if (!crtc->funcs->mode_set_base) { +		DRM_ERROR("panning not supported\n"); +		return -EFAULT; +	} + +	/* TODO add check size and pos*/ + +	crtc->funcs->mode_set_base(crtc, var->xoffset, var->yoffset); + +	par->crtc->x = var->xoffset; +	par->crtc->y = var->yoffset; +	info->var.xoffset = var->xoffset; +	info->var.yoffset = var->yoffset; + +	return 0; +} + +static struct fb_ops intelfb_ops = { +	.owner = THIS_MODULE, +	//	.fb_open = intelfb_open, +	//	.fb_read = intelfb_read, +	//	.fb_write = intelfb_write, +	//	.fb_release = intelfb_release, +	//	.fb_ioctl = intelfb_ioctl, +	.fb_check_var = intelfb_check_var, +	.fb_set_par = intelfb_set_par, +	.fb_setcolreg = intelfb_setcolreg, +	.fb_fillrect = cfb_fillrect, +	.fb_copyarea = cfb_copyarea, //intelfb_copyarea, +	.fb_imageblit = cfb_imageblit, //intelfb_imageblit, +	.fb_pan_display = intelfb_pan_display, +}; + +/** + * Curretly it is assumed that the old framebuffer is reused. + * + * LOCKING + * caller should hold the mode config lock. + * + */ +int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) +{ +    struct fb_info *info; +	struct drm_framebuffer *fb; +	struct drm_display_mode *mode = crtc->desired_mode; + +	fb = crtc->fb; +	if (!fb) +		return 1; + +	info = fb->fbdev; +	if (!info) +		return 1; + +	if (!mode) +		return 1; + +	info->var.xres = mode->hdisplay; +	info->var.right_margin = mode->hsync_start - mode->hdisplay; +	info->var.hsync_len = mode->hsync_end - mode->hsync_start; +	info->var.left_margin = mode->htotal - mode->hsync_end; +	info->var.yres = mode->vdisplay; +	info->var.lower_margin = mode->vsync_start - mode->vdisplay; +	info->var.vsync_len = mode->vsync_end - mode->vsync_start; +	info->var.upper_margin = mode->vtotal - mode->vsync_end; +	info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100; +    /* avoid overflow */ +	info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; + +	return 0; +} +EXPORT_SYMBOL(intelfb_resize); + +int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) +{ +	struct fb_info *info; +	struct intelfb_par *par; +	struct device *device = &dev->pdev->dev;  +	struct drm_framebuffer *fb; +	struct drm_display_mode *mode = crtc->desired_mode; +	struct drm_buffer_object *fbo = NULL; +	int ret; + +	info = framebuffer_alloc(sizeof(struct intelfb_par), device); +	if (!info){ +		return -EINVAL; +	} + +	fb = drm_framebuffer_create(dev); +	if (!fb) { +		framebuffer_release(info); +		DRM_ERROR("failed to allocate fb.\n"); +		return -EINVAL; +	} +	crtc->fb = fb; + +	/* To allow resizeing without swapping buffers */ +	fb->width = 2048;/* crtc->desired_mode->hdisplay; */ +	fb->height = 2048;/* crtc->desired_mode->vdisplay; */ + +	fb->bits_per_pixel = 32; +	fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); +	fb->depth = 24; +	ret = drm_buffer_object_create(dev, fb->width * fb->height * 4,  +				       drm_bo_type_kernel, +				       DRM_BO_FLAG_READ | +				       DRM_BO_FLAG_WRITE | +				       DRM_BO_FLAG_MEM_TT | +				       DRM_BO_FLAG_MEM_VRAM | +				       DRM_BO_FLAG_NO_EVICT, +				       DRM_BO_HINT_DONT_FENCE, 0, 0, +				       &fbo); +	if (ret || !fbo) { +		printk(KERN_ERR "failed to allocate framebuffer\n"); +		drm_framebuffer_destroy(fb); +		framebuffer_release(info); +		return -EINVAL; +	} + +	fb->offset = fbo->offset; +	fb->bo = fbo; +	printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width, +		       fb->height, fbo->offset, fbo); + + +	fb->fbdev = info; +		 +	par = info->par; + +	par->dev = dev; +	par->crtc = crtc; + +	info->fbops = &intelfb_ops; + +	strcpy(info->fix.id, "intelfb"); +	info->fix.type = FB_TYPE_PACKED_PIXELS; +	info->fix.visual = FB_VISUAL_TRUECOLOR; +	info->fix.type_aux = 0; +	info->fix.xpanstep = 1; /* doing it in hw */ +	info->fix.ypanstep = 1; /* doing it in hw */ +	info->fix.ywrapstep = 0; +	info->fix.accel = FB_ACCEL_I830; +	info->fix.type_aux = 0; +	info->fix.mmio_start = 0; +	info->fix.mmio_len = 0; +	info->fix.line_length = fb->pitch; +	info->fix.smem_start = fb->offset + dev->mode_config.fb_base; +	info->fix.smem_len = info->fix.line_length * fb->height; + +	info->flags = FBINFO_DEFAULT; + +	ret = drm_mem_reg_ioremap(dev, &fb->bo->mem, &fb->virtual_base); +	if (ret) +		DRM_ERROR("error mapping fb: %d\n", ret); + +	info->screen_base = fb->virtual_base; +	info->screen_size = info->fix.smem_len; /* FIXME */ +	info->pseudo_palette = fb->pseudo_palette; +	info->var.xres_virtual = fb->width; +	info->var.yres_virtual = fb->height; +	info->var.bits_per_pixel = fb->bits_per_pixel; +	info->var.xoffset = 0; +	info->var.yoffset = 0; +	info->var.activate = FB_ACTIVATE_NOW; +	info->var.height = -1; +	info->var.width = -1; + +        info->var.xres = mode->hdisplay; +        info->var.right_margin = mode->hsync_start - mode->hdisplay; +        info->var.hsync_len = mode->hsync_end - mode->hsync_start; +        info->var.left_margin = mode->htotal - mode->hsync_end; +        info->var.yres = mode->vdisplay; +        info->var.lower_margin = mode->vsync_start - mode->vdisplay; +        info->var.vsync_len = mode->vsync_end - mode->vsync_start; +	info->var.upper_margin = mode->vtotal - mode->vsync_end; +	info->var.pixclock = KHZ2PICOS(mode->clock); + +	if (mode->flags & V_PHSYNC) +		info->var.sync |= FB_SYNC_HOR_HIGH_ACT; + +	if (mode->flags & V_PVSYNC) +		info->var.sync |= FB_SYNC_VERT_HIGH_ACT; + +	if (mode->flags & V_INTERLACE) +		info->var.vmode = FB_VMODE_INTERLACED; +	else if (mode->flags & V_DBLSCAN) +		info->var.vmode = FB_VMODE_DOUBLE; +	else +		info->var.vmode = FB_VMODE_NONINTERLACED; + +	info->pixmap.size = 64*1024; +	info->pixmap.buf_align = 8; +	info->pixmap.access_align = 32; +	info->pixmap.flags = FB_PIXMAP_SYSTEM; +	info->pixmap.scan_align = 1; + +	DRM_DEBUG("fb depth is %d\n", fb->depth); +	DRM_DEBUG("   pitch is %d\n", fb->pitch); +	switch(fb->depth) { +	case 8: +                info->var.red.offset = 0; +                info->var.green.offset = 0; +                info->var.blue.offset = 0; +                info->var.red.length = 8; /* 8bit DAC */ +                info->var.green.length = 8; +                info->var.blue.length = 8; +                info->var.transp.offset = 0; +                info->var.transp.length = 0; +                break; + 	case 15: +                info->var.red.offset = 10; +                info->var.green.offset = 5; +                info->var.blue.offset = 0; +                info->var.red.length = info->var.green.length = +                        info->var.blue.length = 5; +                info->var.transp.offset = 15; +                info->var.transp.length = 1; +                break; +	case 16: +                info->var.red.offset = 11; +                info->var.green.offset = 5; +                info->var.blue.offset = 0; +                info->var.red.length = 5; +                info->var.green.length = 6; +                info->var.blue.length = 5; +                info->var.transp.offset = 0; + 		break; +	case 24: +                info->var.red.offset = 16; +                info->var.green.offset = 8; +                info->var.blue.offset = 0; +                info->var.red.length = info->var.green.length = +                        info->var.blue.length = 8; +                info->var.transp.offset = 0; +                info->var.transp.length = 0; +                break; +	case 32: +		info->var.red.offset = 16; +		info->var.green.offset = 8; +		info->var.blue.offset = 0; +		info->var.red.length = info->var.green.length = +			info->var.blue.length = 8; +		info->var.transp.offset = 24; +		info->var.transp.length = 8; +		break; +	default: +		break; +	} + +	if (register_framebuffer(info) < 0) +		return -EINVAL; + +	printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, +	       info->fix.id); +	return 0; +} +EXPORT_SYMBOL(intelfb_probe); + +int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc) +{ +	struct drm_framebuffer *fb = crtc->fb; +	struct fb_info *info = fb->fbdev; +	 +	if (info) { +		unregister_framebuffer(info); +		framebuffer_release(info); +		drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base); +		drm_bo_usage_deref_unlocked(&fb->bo); +		drm_framebuffer_destroy(fb); +	} +	return 0; +} +EXPORT_SYMBOL(intelfb_remove); +MODULE_LICENSE("GPL"); diff --git a/linux-core/intel_i2c.c b/linux-core/intel_i2c.c new file mode 100644 index 00000000..efcbf656 --- /dev/null +++ b/linux-core/intel_i2c.c @@ -0,0 +1,190 @@ +/* + * Copyright © 2006-2007 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: + *	Eric Anholt <eric@anholt.net> + */ +/* + * Copyright (c) 2006 Dave Airlie <airlied@linux.ie> + *   Jesse Barnes <jesse.barnes@intel.com> + */ + +#include <linux/i2c.h> +#include <linux/i2c-id.h> +#include <linux/i2c-algo-bit.h> +#include "drmP.h" +#include "drm.h" +#include "intel_drv.h" +#include "i915_drm.h" +#include "i915_drv.h" + +/* + * Intel GPIO access functions + */ + +#define I2C_RISEFALL_TIME 20 + +static int get_clock(void *data) +{ +	struct intel_i2c_chan *chan = data; +	struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; +	u32 val; + +	val = I915_READ(chan->reg); +	return ((val & GPIO_CLOCK_VAL_IN) != 0); +} + +static int get_data(void *data) +{ +	struct intel_i2c_chan *chan = data; +	struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; +	u32 val; + +	val = I915_READ(chan->reg); +	return ((val & GPIO_DATA_VAL_IN) != 0); +} + +static void set_clock(void *data, int state_high) +{ +	struct intel_i2c_chan *chan = data; +	struct drm_device *dev = chan->drm_dev; +	struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; +	u32 reserved = 0, clock_bits; + +	/* On most chips, these bits must be preserved in software. */ +	if (!IS_I830(dev) && !IS_845G(dev)) +		reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | +						   GPIO_CLOCK_PULLUP_DISABLE); + +	if (state_high) +		clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK; +	else +		clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK | +			GPIO_CLOCK_VAL_MASK; +	I915_WRITE(chan->reg, reserved | clock_bits); +	udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ +} + +static void set_data(void *data, int state_high) +{ +	struct intel_i2c_chan *chan = data; +	struct drm_device *dev = chan->drm_dev; +	struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; +	u32 reserved = 0, data_bits; + +	/* On most chips, these bits must be preserved in software. */ +	if (!IS_I830(dev) && !IS_845G(dev)) +		reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | +						   GPIO_CLOCK_PULLUP_DISABLE); + +	if (state_high) +		data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK; +	else +		data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK | +			GPIO_DATA_VAL_MASK; + +	I915_WRITE(chan->reg, reserved | data_bits); +	udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ +} + +/** + * intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg + * @dev: DRM device + * @output: driver specific output device + * @reg: GPIO reg to use + * @name: name for this bus + * + * Creates and registers a new i2c bus with the Linux i2c layer, for use + * in output probing and control (e.g. DDC or SDVO control functions). + * + * Possible values for @reg include: + *   %GPIOA + *   %GPIOB + *   %GPIOC + *   %GPIOD + *   %GPIOE + *   %GPIOF + *   %GPIOG + *   %GPIOH + * see PRM for details on how these different busses are used. + */ +struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, +					const char *name) +{ +	struct intel_i2c_chan *chan; + +	chan = kzalloc(sizeof(struct intel_i2c_chan), GFP_KERNEL); +	if (!chan) +		goto out_free; + +	chan->drm_dev = dev; +	chan->reg = reg; +	snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name); +	chan->adapter.owner = THIS_MODULE; +#ifndef I2C_HW_B_INTELFB +#define I2C_HW_B_INTELFB I2C_HW_B_I810 +#endif +	chan->adapter.id = I2C_HW_B_INTELFB; +	chan->adapter.algo_data	= &chan->algo; +	chan->adapter.dev.parent = &dev->pdev->dev; +	chan->algo.setsda = set_data; +	chan->algo.setscl = set_clock; +	chan->algo.getsda = get_data; +	chan->algo.getscl = get_clock; +	chan->algo.udelay = 20; +	chan->algo.timeout = usecs_to_jiffies(2200); +	chan->algo.data = chan; + +	i2c_set_adapdata(&chan->adapter, chan); + +	if(i2c_bit_add_bus(&chan->adapter)) +		goto out_free; + +	/* JJJ:  raise SCL and SDA? */ +	set_data(chan, 1); +	set_clock(chan, 1); +	udelay(20); + +	return chan; + +out_free: +	kfree(chan); +	return NULL; +} + +/** + * intel_i2c_destroy - unregister and free i2c bus resources + * @output: channel to free + * + * Unregister the adapter from the i2c layer, then free the structure. + */ +void intel_i2c_destroy(struct intel_i2c_chan *chan) +{ +	if (!chan) +		return; + +	i2c_del_adapter(&chan->adapter); +	kfree(chan); +} + +	 +	 diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c new file mode 100644 index 00000000..80f77af6 --- /dev/null +++ b/linux-core/intel_lvds.c @@ -0,0 +1,509 @@ +/* + * Copyright © 2006-2007 Intel Corporation + * Copyright (c) 2006 Dave Airlie <airlied@linux.ie> + * + * 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: + *	Eric Anholt <eric@anholt.net> + *      Dave Airlie <airlied@linux.ie> + *      Jesse Barnes <jesse.barnes@intel.com> + */ + +#include <linux/i2c.h> +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "drm_edid.h" +#include "intel_drv.h" +#include "i915_drm.h" +#include "i915_drv.h" + +/** + * Sets the backlight level. + * + * \param level backlight level, from 0 to intel_lvds_get_max_backlight(). + */ +static void intel_lvds_set_backlight(struct drm_device *dev, int level) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	u32 blc_pwm_ctl; + +	blc_pwm_ctl = I915_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; +	I915_WRITE(BLC_PWM_CTL, (blc_pwm_ctl | +				 (level << BACKLIGHT_DUTY_CYCLE_SHIFT))); +} + +/** + * Returns the maximum level of the backlight duty cycle field. + */ +static u32 intel_lvds_get_max_backlight(struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +     +	return ((I915_READ(BLC_PWM_CTL) & BACKLIGHT_MODULATION_FREQ_MASK) >> +		BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; +} + +/** + * Sets the power state for the panel. + */ +static void intel_lvds_set_power(struct drm_device *dev, bool on) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	u32 pp_status; + +	if (on) { +		I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | +			   POWER_TARGET_ON); +		do { +			pp_status = I915_READ(PP_STATUS); +		} while ((pp_status & PP_ON) == 0); + +		intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle); +	} else { +		intel_lvds_set_backlight(dev, 0); + +		I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & +			   ~POWER_TARGET_ON); +		do { +			pp_status = I915_READ(PP_STATUS); +		} while (pp_status & PP_ON); +	} +} + +static void intel_lvds_dpms(struct drm_output *output, int mode) +{ +	struct drm_device *dev = output->dev; + +	if (mode == DPMSModeOn) +		intel_lvds_set_power(dev, true); +	else +		intel_lvds_set_power(dev, false); + +	/* XXX: We never power down the LVDS pairs. */ +} + +static void intel_lvds_save(struct drm_output *output) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; + +	dev_priv->savePP_ON = I915_READ(LVDSPP_ON); +	dev_priv->savePP_OFF = I915_READ(LVDSPP_OFF); +	dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL); +	dev_priv->savePP_CYCLE = I915_READ(PP_CYCLE); +	dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); +	dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & +				       BACKLIGHT_DUTY_CYCLE_MASK); + +	/* +	 * If the light is off at server startup, just make it full brightness +	 */ +	if (dev_priv->backlight_duty_cycle == 0) +		dev_priv->backlight_duty_cycle = +			intel_lvds_get_max_backlight(dev); +} + +static void intel_lvds_restore(struct drm_output *output) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; + +	I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); +	I915_WRITE(LVDSPP_ON, dev_priv->savePP_ON); +	I915_WRITE(LVDSPP_OFF, dev_priv->savePP_OFF); +	I915_WRITE(PP_CYCLE, dev_priv->savePP_CYCLE); +	I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL); +	if (dev_priv->savePP_CONTROL & POWER_TARGET_ON) +		intel_lvds_set_power(dev, true); +	else +		intel_lvds_set_power(dev, false); +} + +static int intel_lvds_mode_valid(struct drm_output *output, +				 struct drm_display_mode *mode) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode; + +	if (fixed_mode)	{ +		if (mode->hdisplay > fixed_mode->hdisplay) +			return MODE_PANEL; +		if (mode->vdisplay > fixed_mode->vdisplay) +			return MODE_PANEL; +	} + +	return MODE_OK; +} + +static bool intel_lvds_mode_fixup(struct drm_output *output, +				  struct drm_display_mode *mode, +				  struct drm_display_mode *adjusted_mode) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_crtc *intel_crtc = output->crtc->driver_private; +	struct drm_output *tmp_output; + +	/* Should never happen!! */ +	if (!IS_I965G(dev) && intel_crtc->pipe == 0) { +		printk(KERN_ERR "Can't support LVDS on pipe A\n"); +		return false; +	} + +	/* Should never happen!! */ +	list_for_each_entry(tmp_output, &dev->mode_config.output_list, head) { +		if (tmp_output != output && tmp_output->crtc == output->crtc) { +			printk(KERN_ERR "Can't enable LVDS and another " +			       "output on the same pipe\n"); +			return false; +		} +	} + +	/* +	 * If we have timings from the BIOS for the panel, put them in +	 * to the adjusted mode.  The CRTC will be set up for this mode, +	 * with the panel scaling set up to source from the H/VDisplay +	 * of the original mode. +	 */ +	if (dev_priv->panel_fixed_mode != NULL) { +		adjusted_mode->hdisplay = dev_priv->panel_fixed_mode->hdisplay; +		adjusted_mode->hsync_start = +			dev_priv->panel_fixed_mode->hsync_start; +		adjusted_mode->hsync_end = +			dev_priv->panel_fixed_mode->hsync_end; +		adjusted_mode->htotal = dev_priv->panel_fixed_mode->htotal; +		adjusted_mode->vdisplay = dev_priv->panel_fixed_mode->vdisplay; +		adjusted_mode->vsync_start = +			dev_priv->panel_fixed_mode->vsync_start; +		adjusted_mode->vsync_end = +			dev_priv->panel_fixed_mode->vsync_end; +		adjusted_mode->vtotal = dev_priv->panel_fixed_mode->vtotal; +		adjusted_mode->clock = dev_priv->panel_fixed_mode->clock; +		drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); +	} + +	/* +	 * XXX: It would be nice to support lower refresh rates on the +	 * panels to reduce power consumption, and perhaps match the +	 * user's requested refresh rate. +	 */ + +	return true; +} + +static void intel_lvds_prepare(struct drm_output *output) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; + +	dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); +	dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & +				       BACKLIGHT_DUTY_CYCLE_MASK); + +	intel_lvds_set_power(dev, false); +} + +static void intel_lvds_commit( struct drm_output *output) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; + +	if (dev_priv->backlight_duty_cycle == 0) +		dev_priv->backlight_duty_cycle = +			intel_lvds_get_max_backlight(dev); + +	intel_lvds_set_power(dev, true); +} + +static void intel_lvds_mode_set(struct drm_output *output, +				struct drm_display_mode *mode, +				struct drm_display_mode *adjusted_mode) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_crtc *intel_crtc = output->crtc->driver_private; +	u32 pfit_control; + +	/* +	 * The LVDS pin pair will already have been turned on in the +	 * intel_crtc_mode_set since it has a large impact on the DPLL +	 * settings. +	 */ + +	/* +	 * Enable automatic panel scaling so that non-native modes fill the +	 * screen.  Should be enabled before the pipe is enabled, according to +	 * register description and PRM. +	 */ +	if (mode->hdisplay != adjusted_mode->hdisplay || +	    mode->vdisplay != adjusted_mode->vdisplay) +		pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE | +				HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR | +				HORIZ_INTERP_BILINEAR); +	else +		pfit_control = 0; + +	if (!IS_I965G(dev)) { +		if (dev_priv->panel_wants_dither) +			pfit_control |= PANEL_8TO6_DITHER_ENABLE; +	} +	else +		pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT; + +	I915_WRITE(PFIT_CONTROL, pfit_control); +} + +/** + * Detect the LVDS connection. + * + * This always returns OUTPUT_STATUS_CONNECTED.  This output should only have + * been set up if the LVDS was actually connected anyway. + */ +static enum drm_output_status intel_lvds_detect(struct drm_output *output) +{ +	return output_status_connected; +} + +/** + * Return the list of DDC modes if available, or the BIOS fixed mode otherwise. + */ +static int intel_lvds_get_modes(struct drm_output *output) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	int ret = 0; + +	ret = intel_ddc_get_modes(output); + +	if (ret) +		return ret; + +	/* Didn't get an EDID */ +	if (!output->monitor_info) { +		struct drm_display_info *dspinfo; +		dspinfo = kzalloc(sizeof(*output->monitor_info), GFP_KERNEL); +		if (!dspinfo) +			goto out; + +		/* Set wide sync ranges so we get all modes +		 * handed to valid_mode for checking +		 */ +		dspinfo->min_vfreq = 0; +		dspinfo->max_vfreq = 200; +		dspinfo->min_hfreq = 0; +		dspinfo->max_hfreq = 200; +		output->monitor_info = dspinfo; +	} + +out: +	if (dev_priv->panel_fixed_mode != NULL) { +		struct drm_display_mode *mode = +			drm_mode_duplicate(dev, dev_priv->panel_fixed_mode); +		drm_mode_probed_add(output, mode); +		return 1; +	} + +	return 0; +} + +/** + * intel_lvds_destroy - unregister and free LVDS structures + * @output: output to free + * + * Unregister the DDC bus for this output then free the driver private + * structure. + */ +static void intel_lvds_destroy(struct drm_output *output) +{ +	struct intel_output *intel_output = output->driver_private; + +	intel_i2c_destroy(intel_output->ddc_bus); +	kfree(output->driver_private); +} + +static const struct drm_output_funcs intel_lvds_output_funcs = { +	.dpms = intel_lvds_dpms, +	.save = intel_lvds_save, +	.restore = intel_lvds_restore, +	.mode_valid = intel_lvds_mode_valid, +	.mode_fixup = intel_lvds_mode_fixup, +	.prepare = intel_lvds_prepare, +	.mode_set = intel_lvds_mode_set, +	.commit = intel_lvds_commit, +	.detect = intel_lvds_detect, +	.get_modes = intel_lvds_get_modes, +	.cleanup = intel_lvds_destroy +}; + +/** + * intel_lvds_init - setup LVDS outputs on this device + * @dev: drm device + * + * Create the output, register the LVDS DDC bus, and try to figure out what + * modes we can display on the LVDS panel (if present). + */ +void intel_lvds_init(struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_output *output; +	struct intel_output *intel_output; +	struct drm_display_mode *scan; /* *modes, *bios_mode; */ +	struct drm_crtc *crtc; +	u32 lvds; +	int pipe; + +	output = drm_output_create(dev, &intel_lvds_output_funcs, +				   DRM_MODE_OUTPUT_LVDS); +	if (!output) +		return; + +	intel_output = kmalloc(sizeof(struct intel_output), GFP_KERNEL); +	if (!intel_output) { +		drm_output_destroy(output); +		return; +	} + +	intel_output->type = INTEL_OUTPUT_LVDS; +	output->driver_private = intel_output; +	output->subpixel_order = SubPixelHorizontalRGB; +	output->interlace_allowed = FALSE; +	output->doublescan_allowed = FALSE; + +	/* Set up the DDC bus. */ +	intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C"); +	if (!intel_output->ddc_bus) { +		dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " +			   "failed.\n"); +		return; +	} + +	/* +	 * Attempt to get the fixed panel mode from DDC.  Assume that the +	 * preferred mode is the right one. +	 */ +	intel_ddc_get_modes(output); + +	list_for_each_entry(scan, &output->probed_modes, head) { +		if (scan->type & DRM_MODE_TYPE_PREFERRED) { +			dev_priv->panel_fixed_mode =  +				drm_mode_duplicate(dev, scan); +			goto out; /* FIXME: check for quirks */ +		} +	} + +	/* +	 * If we didn't get EDID, try checking if the panel is already turned +	 * on.  If so, assume that whatever is currently programmed is the +	 * correct mode. +	 */ +	lvds = I915_READ(LVDS); +	pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; +	crtc = intel_get_crtc_from_pipe(dev, pipe); +		 +	if (crtc && (lvds & LVDS_PORT_EN)) { +		dev_priv->panel_fixed_mode = intel_crtc_mode_get(dev, crtc); +		if (dev_priv->panel_fixed_mode) { +			dev_priv->panel_fixed_mode->type |= +				DRM_MODE_TYPE_PREFERRED; +			goto out; /* FIXME: check for quirks */ +		} +	} + +	/* If we still don't have a mode after all that, give up. */ +	if (!dev_priv->panel_fixed_mode) +		goto failed; + +	/* FIXME: probe the BIOS for modes and check for LVDS quirks */ +#if 0 +	/* Get the LVDS fixed mode out of the BIOS.  We should support LVDS +	 * with the BIOS being unavailable or broken, but lack the +	 * configuration options for now. +	 */ +	bios_mode = intel_bios_get_panel_mode(pScrn); +	if (bios_mode != NULL) { +		if (dev_priv->panel_fixed_mode != NULL) { +			if (dev_priv->debug_modes && +			    !xf86ModesEqual(dev_priv->panel_fixed_mode, +					    bios_mode)) +			{ +				xf86DrvMsg(pScrn->scrnIndex, X_WARNING, +					   "BIOS panel mode data doesn't match probed data, " +					   "continuing with probed.\n"); +				xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS mode:\n"); +				xf86PrintModeline(pScrn->scrnIndex, bios_mode); +				xf86DrvMsg(pScrn->scrnIndex, X_INFO, "probed mode:\n"); +				xf86PrintModeline(pScrn->scrnIndex, dev_priv->panel_fixed_mode); +				xfree(bios_mode->name); +				xfree(bios_mode); +			} +		}  else { +			dev_priv->panel_fixed_mode = bios_mode; +		} +	} else { +		xf86DrvMsg(pScrn->scrnIndex, X_WARNING, +			   "Couldn't detect panel mode.  Disabling panel\n"); +		goto disable_exit; +	} + +	/* +	 * Blacklist machines with BIOSes that list an LVDS panel without +	 * actually having one. +	 */ +	if (dev_priv->PciInfo->chipType == PCI_CHIP_I945_GM) { +		/* aopen mini pc */ +		if (dev_priv->PciInfo->subsysVendor == 0xa0a0) +			goto disable_exit; + +		if ((dev_priv->PciInfo->subsysVendor == 0x8086) && +		    (dev_priv->PciInfo->subsysCard == 0x7270)) { +			/* It's a Mac Mini or Macbook Pro. +			 * +			 * Apple hardware is out to get us.  The macbook pro +			 * has a real LVDS panel, but the mac mini does not, +			 * and they have the same device IDs.  We'll +			 * distinguish by panel size, on the assumption +			 * that Apple isn't about to make any machines with an +			 * 800x600 display. +			 */ + +			if (dev_priv->panel_fixed_mode != NULL && +			    dev_priv->panel_fixed_mode->HDisplay == 800 && +			    dev_priv->panel_fixed_mode->VDisplay == 600) +			{ +				xf86DrvMsg(pScrn->scrnIndex, X_INFO, +					   "Suspected Mac Mini, ignoring the LVDS\n"); +				goto disable_exit; +			} +		} +	} + +#endif + +out: +	drm_output_attach_property(output, dev->mode_config.connector_type_property, ConnectorLVDS); +	return; + +failed: +        DRM_DEBUG("No LVDS modes found, disabling.\n"); +	drm_output_destroy(output); /* calls intel_lvds_destroy above */ +} diff --git a/linux-core/intel_modes.c b/linux-core/intel_modes.c new file mode 100644 index 00000000..f8bf496c --- /dev/null +++ b/linux-core/intel_modes.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> + * Copyright (c) 2007 Intel Corporation + *   Jesse Barnes <jesse.barnes@intel.com> + */ + +#include <linux/i2c.h> +#include <linux/fb.h> +#include "drmP.h" +#include "intel_drv.h" + +/** + * intel_ddc_probe + * + */ +bool intel_ddc_probe(struct drm_output *output) +{ +	struct intel_output *intel_output = output->driver_private; +	u8 out_buf[] = { 0x0, 0x0}; +	u8 buf[2]; +	int ret; +	struct i2c_msg msgs[] = { +		{ +			.addr = 0x50, +			.flags = 0, +			.len = 1, +			.buf = out_buf, +		}, +		{ +			.addr = 0x50, +			.flags = I2C_M_RD, +			.len = 1, +			.buf = buf, +		} +	}; + +	ret = i2c_transfer(&intel_output->ddc_bus->adapter, msgs, 2); +	if (ret == 2) +		return true; + +	return false; +} + +/** + * intel_ddc_get_modes - get modelist from monitor + * @output: DRM output device to use + * + * Fetch the EDID information from @output using the DDC bus. + */ +int intel_ddc_get_modes(struct drm_output *output) +{ +	struct intel_output *intel_output = output->driver_private; +	struct edid *edid; +	int ret = 0; + +	edid = drm_get_edid(output, &intel_output->ddc_bus->adapter); +	if (edid) { +		drm_mode_output_update_edid_property(output, edid); +		ret = drm_add_edid_modes(output, edid); +		kfree(edid); +	} +	return ret; +} diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c new file mode 100644 index 00000000..3887df00 --- /dev/null +++ b/linux-core/intel_sdvo.c @@ -0,0 +1,1168 @@ +/* + * Copyright © 2006-2007 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: + *	Eric Anholt <eric@anholt.net> + */ +/* + * Copyright 2006 Dave Airlie <airlied@linux.ie> + *   Jesse Barnes <jesse.barnes@intel.com> + */ + +#include <linux/i2c.h> +#include <linux/delay.h> +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "intel_drv.h" +#include "i915_drm.h" +#include "i915_drv.h" +#include "intel_sdvo_regs.h" + +struct intel_sdvo_priv { +	struct intel_i2c_chan *i2c_bus; +	int slaveaddr; +	int output_device; + +	u16 active_outputs; + +	struct intel_sdvo_caps caps; +	int pixel_clock_min, pixel_clock_max; + +	int save_sdvo_mult; +	u16 save_active_outputs; +	struct intel_sdvo_dtd save_input_dtd_1, save_input_dtd_2; +	struct intel_sdvo_dtd save_output_dtd[16]; +	u32 save_SDVOX; +	int hotplug_enabled; +}; + +/** + * Writes the SDVOB or SDVOC with the given value, but always writes both + * SDVOB and SDVOC to work around apparent hardware issues (according to + * comments in the BIOS). + */ +void intel_sdvo_write_sdvox(struct drm_output *output, u32 val) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_output *intel_output = output->driver_private; +	struct intel_sdvo_priv   *sdvo_priv = intel_output->dev_priv; +	u32 bval = val, cval = val; +	int i; + +	if (sdvo_priv->output_device == SDVOB) { +		cval = I915_READ(SDVOC); + +		if (sdvo_priv->hotplug_enabled) +			bval = bval | (1 << 26); +	} else { +		bval = I915_READ(SDVOB); + +		if (sdvo_priv->hotplug_enabled) +			cval = cval | (1 << 26); +	} +	/* +	 * Write the registers twice for luck. Sometimes, +	 * writing them only once doesn't appear to 'stick'. +	 * The BIOS does this too. Yay, magic +	 */ +	for (i = 0; i < 2; i++) +	{ +		I915_WRITE(SDVOB, bval); +		I915_READ(SDVOB); +		I915_WRITE(SDVOC, cval); +		I915_READ(SDVOC); +	} +} + +static bool intel_sdvo_read_byte(struct drm_output *output, u8 addr, +				 u8 *ch) +{ +	struct intel_output *intel_output = output->driver_private; +	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; +	u8 out_buf[2]; +	u8 buf[2]; +	int ret; + +	struct i2c_msg msgs[] = { +		{  +			.addr = sdvo_priv->i2c_bus->slave_addr, +			.flags = 0, +			.len = 1, +			.buf = out_buf, +		},  +		{ +			.addr = sdvo_priv->i2c_bus->slave_addr, +			.flags = I2C_M_RD, +			.len = 1, +			.buf = buf, +		} +	}; + +	out_buf[0] = addr; +	out_buf[1] = 0; + +	if ((ret = i2c_transfer(&sdvo_priv->i2c_bus->adapter, msgs, 2)) == 2) +	{ +//		DRM_DEBUG("got back from addr %02X = %02x\n", out_buf[0], buf[0]);  +		*ch = buf[0]; +		return true; +	} + +	DRM_DEBUG("i2c transfer returned %d\n", ret); +	return false; +} + + +static bool intel_sdvo_read_byte_quiet(struct drm_output *output, int addr, +				       u8 *ch) +{ +	return true; + +} + +static bool intel_sdvo_write_byte(struct drm_output *output, int addr, +				  u8 ch) +{ +	struct intel_output *intel_output = output->driver_private; +	u8 out_buf[2]; +	struct i2c_msg msgs[] = { +		{  +			.addr = intel_output->i2c_bus->slave_addr, +			.flags = 0, +			.len = 2, +			.buf = out_buf, +		} +	}; + +	out_buf[0] = addr; +	out_buf[1] = ch; + +	if (i2c_transfer(&intel_output->i2c_bus->adapter, msgs, 1) == 1) +	{ +		return true; +	} +	return false; +} + +#define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd} +/** Mapping of command numbers to names, for debug output */ +const static struct _sdvo_cmd_name { +    u8 cmd; +    char *name; +} sdvo_cmd_names[] = { +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_RESET), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DEVICE_CAPS), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FIRMWARE_REV), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TRAINED_INPUTS), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_OUTPUTS), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_OUTPUTS), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_IN_OUT_MAP), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_IN_OUT_MAP), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ATTACHED_DISPLAYS), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HOT_PLUG_SUPPORT), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_HOT_PLUG), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_HOT_PLUG), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_INPUT), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_OUTPUT), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART1), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART2), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART2), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART1), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART2), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART1), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART2), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CLOCK_RATE_MULT), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CLOCK_RATE_MULT), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_TV_FORMATS), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_FORMAT), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_FORMAT), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_RESOLUTION_SUPPORT), +    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTROL_BUS_SWITCH), +}; + +#define SDVO_NAME(dev_priv) ((dev_priv)->output_device == SDVOB ? "SDVOB" : "SDVOC") +#define SDVO_PRIV(output)   ((struct intel_sdvo_priv *) (output)->dev_priv) + +static void intel_sdvo_write_cmd(struct drm_output *output, u8 cmd, +				 void *args, int args_len) +{ +	struct intel_output *intel_output = output->driver_private; +	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; +	int i; + +        if (1) { +                DRM_DEBUG("%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd); +                for (i = 0; i < args_len; i++) +                        printk("%02X ", ((u8 *)args)[i]); +                for (; i < 8; i++) +                        printk("   "); +                for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) { +                        if (cmd == sdvo_cmd_names[i].cmd) { +                                printk("(%s)", sdvo_cmd_names[i].name); +                                break; +                        } +                } +                if (i == sizeof(sdvo_cmd_names)/ sizeof(sdvo_cmd_names[0])) +                        printk("(%02X)",cmd); +                printk("\n"); +        } +                         +	for (i = 0; i < args_len; i++) { +		intel_sdvo_write_byte(output, SDVO_I2C_ARG_0 - i, ((u8*)args)[i]); +	} + +	intel_sdvo_write_byte(output, SDVO_I2C_OPCODE, cmd); +} + +static const char *cmd_status_names[] = { +	"Power on", +	"Success", +	"Not supported", +	"Invalid arg", +	"Pending", +	"Target not specified", +	"Scaling not supported" +}; + +static u8 intel_sdvo_read_response(struct drm_output *output, void *response, +				   int response_len) +{ +	struct intel_output *intel_output = output->driver_private; +	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; +	int i; +	u8 status; +	u8 retry = 50; + +	while (retry--) { +		/* Read the command response */ +		for (i = 0; i < response_len; i++) { +			intel_sdvo_read_byte(output, SDVO_I2C_RETURN_0 + i, +				     &((u8 *)response)[i]); +		} + +		/* read the return status */ +		intel_sdvo_read_byte(output, SDVO_I2C_CMD_STATUS, &status); + +	        if (1) { +			DRM_DEBUG("%s: R: ", SDVO_NAME(sdvo_priv)); +       			for (i = 0; i < response_len; i++) +                        	printk("%02X ", ((u8 *)response)[i]); +                	for (; i < 8; i++) +                        	printk("   "); +                	if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) +                        	printk("(%s)", cmd_status_names[status]); +                	else +                        	printk("(??? %d)", status); +                	printk("\n"); +        	} + +		if (status != SDVO_CMD_STATUS_PENDING) +			return status; + +		mdelay(50); +	} + +	return status; +} + +int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) +{ +	if (mode->clock >= 100000) +		return 1; +	else if (mode->clock >= 50000) +		return 2; +	else +		return 4; +} + +/** + * Don't check status code from this as it switches the bus back to the + * SDVO chips which defeats the purpose of doing a bus switch in the first + * place. + */ +void intel_sdvo_set_control_bus_switch(struct drm_output *output, u8 target) +{ +	intel_sdvo_write_cmd(output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1); +} + +static bool intel_sdvo_set_target_input(struct drm_output *output, bool target_0, bool target_1) +{ +	struct intel_sdvo_set_target_input_args targets = {0}; +	u8 status; + +	if (target_0 && target_1) +		return SDVO_CMD_STATUS_NOTSUPP; + +	if (target_1) +		targets.target_1 = 1; + +	intel_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_INPUT, &targets, +			     sizeof(targets)); + +	status = intel_sdvo_read_response(output, NULL, 0); + +	return (status == SDVO_CMD_STATUS_SUCCESS); +} + +/** + * Return whether each input is trained. + * + * This function is making an assumption about the layout of the response, + * which should be checked against the docs. + */ +static bool intel_sdvo_get_trained_inputs(struct drm_output *output, bool *input_1, bool *input_2) +{ +	struct intel_sdvo_get_trained_inputs_response response; +	u8 status; + +	intel_sdvo_write_cmd(output, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0); +	status = intel_sdvo_read_response(output, &response, sizeof(response)); +	if (status != SDVO_CMD_STATUS_SUCCESS) +		return false; + +	*input_1 = response.input0_trained; +	*input_2 = response.input1_trained; +	return true; +} + +static bool intel_sdvo_get_active_outputs(struct drm_output *output, +					  u16 *outputs) +{ +	u8 status; + +	intel_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_OUTPUTS, NULL, 0); +	status = intel_sdvo_read_response(output, outputs, sizeof(*outputs)); + +	return (status == SDVO_CMD_STATUS_SUCCESS); +} + +static bool intel_sdvo_set_active_outputs(struct drm_output *output, +					  u16 outputs) +{ +	u8 status; + +	intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs, +			     sizeof(outputs)); +	status = intel_sdvo_read_response(output, NULL, 0); +	return (status == SDVO_CMD_STATUS_SUCCESS); +} + +static bool intel_sdvo_set_encoder_power_state(struct drm_output *output, +					       int mode) +{ +	u8 status, state = SDVO_ENCODER_STATE_ON; + +	switch (mode) { +	case DPMSModeOn: +		state = SDVO_ENCODER_STATE_ON; +		break; +	case DPMSModeStandby: +		state = SDVO_ENCODER_STATE_STANDBY; +		break; +	case DPMSModeSuspend: +		state = SDVO_ENCODER_STATE_SUSPEND; +		break; +	case DPMSModeOff: +		state = SDVO_ENCODER_STATE_OFF; +		break; +	} +	 +	intel_sdvo_write_cmd(output, SDVO_CMD_SET_ENCODER_POWER_STATE, &state, +			     sizeof(state)); +	status = intel_sdvo_read_response(output, NULL, 0); + +	return (status == SDVO_CMD_STATUS_SUCCESS); +} + +static bool intel_sdvo_get_input_pixel_clock_range(struct drm_output *output, +						   int *clock_min, +						   int *clock_max) +{ +	struct intel_sdvo_pixel_clock_range clocks; +	u8 status; + +	intel_sdvo_write_cmd(output, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, +			     NULL, 0); + +	status = intel_sdvo_read_response(output, &clocks, sizeof(clocks)); + +	if (status != SDVO_CMD_STATUS_SUCCESS) +		return false; + +	/* Convert the values from units of 10 kHz to kHz. */ +	*clock_min = clocks.min * 10; +	*clock_max = clocks.max * 10; + +	return true; +} + +static bool intel_sdvo_set_target_output(struct drm_output *output, +					 u16 outputs) +{ +	u8 status; + +	intel_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_OUTPUT, &outputs, +			     sizeof(outputs)); + +	status = intel_sdvo_read_response(output, NULL, 0); +	return (status == SDVO_CMD_STATUS_SUCCESS); +} + +static bool intel_sdvo_get_timing(struct drm_output *output, u8 cmd, +				  struct intel_sdvo_dtd *dtd) +{ +	u8 status; + +	intel_sdvo_write_cmd(output, cmd, NULL, 0); +	status = intel_sdvo_read_response(output, &dtd->part1, +					  sizeof(dtd->part1)); +	if (status != SDVO_CMD_STATUS_SUCCESS) +		return false; + +	intel_sdvo_write_cmd(output, cmd + 1, NULL, 0); +	status = intel_sdvo_read_response(output, &dtd->part2, +					  sizeof(dtd->part2)); +	if (status != SDVO_CMD_STATUS_SUCCESS) +		return false; + +	return true; +} + +static bool intel_sdvo_get_input_timing(struct drm_output *output, +					 struct intel_sdvo_dtd *dtd) +{ +	return intel_sdvo_get_timing(output, +				     SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd); +} + +static bool intel_sdvo_get_output_timing(struct drm_output *output, +					 struct intel_sdvo_dtd *dtd) +{ +	return intel_sdvo_get_timing(output, +				     SDVO_CMD_GET_OUTPUT_TIMINGS_PART1, dtd); +} + +static bool intel_sdvo_set_timing(struct drm_output *output, u8 cmd, +				  struct intel_sdvo_dtd *dtd) +{ +	u8 status; + +	intel_sdvo_write_cmd(output, cmd, &dtd->part1, sizeof(dtd->part1)); +	status = intel_sdvo_read_response(output, NULL, 0); +	if (status != SDVO_CMD_STATUS_SUCCESS) +		return false; + +	intel_sdvo_write_cmd(output, cmd + 1, &dtd->part2, sizeof(dtd->part2)); +	status = intel_sdvo_read_response(output, NULL, 0); +	if (status != SDVO_CMD_STATUS_SUCCESS) +		return false; + +	return true; +} + +static bool intel_sdvo_set_input_timing(struct drm_output *output, +					 struct intel_sdvo_dtd *dtd) +{ +	return intel_sdvo_set_timing(output, +				     SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd); +} + +static bool intel_sdvo_set_output_timing(struct drm_output *output, +					 struct intel_sdvo_dtd *dtd) +{ +	return intel_sdvo_set_timing(output, +				     SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd); +} + +#if 0 +static bool intel_sdvo_get_preferred_input_timing(struct drm_output *output, +						  struct intel_sdvo_dtd *dtd) +{ +	struct intel_output *intel_output = output->driver_private; +	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; +	u8 status; + +	intel_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1, +			     NULL, 0); + +	status = intel_sdvo_read_response(output, &dtd->part1, +					  sizeof(dtd->part1)); +	if (status != SDVO_CMD_STATUS_SUCCESS) +		return false; + +	intel_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, +			     NULL, 0); +	status = intel_sdvo_read_response(output, &dtd->part2, +					  sizeof(dtd->part2)); +	if (status != SDVO_CMD_STATUS_SUCCESS) +		return false; + +	return true; +} +#endif + +static int intel_sdvo_get_clock_rate_mult(struct drm_output *output) +{ +	u8 response, status; + +	intel_sdvo_write_cmd(output, SDVO_CMD_GET_CLOCK_RATE_MULT, NULL, 0); +	status = intel_sdvo_read_response(output, &response, 1); + +	if (status != SDVO_CMD_STATUS_SUCCESS) { +		DRM_DEBUG("Couldn't get SDVO clock rate multiplier\n"); +		return SDVO_CLOCK_RATE_MULT_1X; +	} else { +		DRM_DEBUG("Current clock rate multiplier: %d\n", response); +	} + +	return response; +} + +static bool intel_sdvo_set_clock_rate_mult(struct drm_output *output, u8 val) +{ +	u8 status; + +	intel_sdvo_write_cmd(output, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); +	status = intel_sdvo_read_response(output, NULL, 0); +	if (status != SDVO_CMD_STATUS_SUCCESS) +		return false; + +	return true; +} + +static bool intel_sdvo_mode_fixup(struct drm_output *output, +				  struct drm_display_mode *mode, +				  struct drm_display_mode *adjusted_mode) +{ +	/* Make the CRTC code factor in the SDVO pixel multiplier.  The SDVO +	 * device will be told of the multiplier during mode_set. +	 */ +	adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode); +	return true; +} + +static void intel_sdvo_mode_set(struct drm_output *output, +				struct drm_display_mode *mode, +				struct drm_display_mode *adjusted_mode) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_crtc *crtc = output->crtc; +	struct intel_crtc *intel_crtc = crtc->driver_private; +	struct intel_output *intel_output = output->driver_private; +	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; +	u16 width, height; +	u16 h_blank_len, h_sync_len, v_blank_len, v_sync_len; +	u16 h_sync_offset, v_sync_offset; +	u32 sdvox; +	struct intel_sdvo_dtd output_dtd; +	int sdvo_pixel_multiply; + +	if (!mode) +		return; + +	width = mode->crtc_hdisplay; +	height = mode->crtc_vdisplay; + +	/* do some mode translations */ +	h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start; +	h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; + +	v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start; +	v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; + +	h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start; +	v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start; + +	output_dtd.part1.clock = mode->clock / 10; +	output_dtd.part1.h_active = width & 0xff; +	output_dtd.part1.h_blank = h_blank_len & 0xff; +	output_dtd.part1.h_high = (((width >> 8) & 0xf) << 4) | +		((h_blank_len >> 8) & 0xf); +	output_dtd.part1.v_active = height & 0xff; +	output_dtd.part1.v_blank = v_blank_len & 0xff; +	output_dtd.part1.v_high = (((height >> 8) & 0xf) << 4) | +		((v_blank_len >> 8) & 0xf); +	 +	output_dtd.part2.h_sync_off = h_sync_offset; +	output_dtd.part2.h_sync_width = h_sync_len & 0xff; +	output_dtd.part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 | +		(v_sync_len & 0xf); +	output_dtd.part2.sync_off_width_high = ((h_sync_offset & 0x300) >> 2) | +		((h_sync_len & 0x300) >> 4) | ((v_sync_offset & 0x30) >> 2) | +		((v_sync_len & 0x30) >> 4); +	 +	output_dtd.part2.dtd_flags = 0x18; +	if (mode->flags & V_PHSYNC) +		output_dtd.part2.dtd_flags |= 0x2; +	if (mode->flags & V_PVSYNC) +		output_dtd.part2.dtd_flags |= 0x4; + +	output_dtd.part2.sdvo_flags = 0; +	output_dtd.part2.v_sync_off_high = v_sync_offset & 0xc0; +	output_dtd.part2.reserved = 0; + +	/* Set the output timing to the screen */ +	intel_sdvo_set_target_output(output, sdvo_priv->active_outputs); +	intel_sdvo_set_output_timing(output, &output_dtd); + +	/* Set the input timing to the screen. Assume always input 0. */ +	intel_sdvo_set_target_input(output, true, false); + +	/* We would like to use i830_sdvo_create_preferred_input_timing() to +	 * provide the device with a timing it can support, if it supports that +	 * feature.  However, presumably we would need to adjust the CRTC to +	 * output the preferred timing, and we don't support that currently. +	 */ +#if 0 +	success = intel_sdvo_create_preferred_input_timing(output, clock, +							   width, height); +	if (success) { +		struct intel_sdvo_dtd *input_dtd; +		 +		intel_sdvo_get_preferred_input_timing(output, &input_dtd); +		intel_sdvo_set_input_timing(output, &input_dtd); +	} +#else +	intel_sdvo_set_input_timing(output, &output_dtd); +#endif	 + +	switch (intel_sdvo_get_pixel_multiplier(mode)) { +	case 1: +		intel_sdvo_set_clock_rate_mult(output, +					       SDVO_CLOCK_RATE_MULT_1X); +		break; +	case 2: +		intel_sdvo_set_clock_rate_mult(output, +					       SDVO_CLOCK_RATE_MULT_2X); +		break; +	case 4: +		intel_sdvo_set_clock_rate_mult(output, +					       SDVO_CLOCK_RATE_MULT_4X); +		break; +	}	 + +	/* Set the SDVO control regs. */ +        if (0/*IS_I965GM(dev)*/) { +                sdvox = SDVO_BORDER_ENABLE; +        } else { +                sdvox = I915_READ(sdvo_priv->output_device); +                switch (sdvo_priv->output_device) { +                case SDVOB: +                        sdvox &= SDVOB_PRESERVE_MASK; +                        break; +                case SDVOC: +                        sdvox &= SDVOC_PRESERVE_MASK; +                        break; +                } +                sdvox |= (9 << 19) | SDVO_BORDER_ENABLE; +        } +	if (intel_crtc->pipe == 1) +		sdvox |= SDVO_PIPE_B_SELECT; + +	sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode); +	if (IS_I965G(dev)) { +		/* done in crtc_mode_set as the dpll_md reg must be written  +		   early */ +	} else if (IS_I945G(dev) || IS_I945GM(dev)) { +		/* done in crtc_mode_set as it lives inside the  +		   dpll register */ +	} else { +		sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; +	} + +	intel_sdvo_write_sdvox(output, sdvox); +} + +static void intel_sdvo_dpms(struct drm_output *output, int mode) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_output *intel_output = output->driver_private; +	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; +	u32 temp; + +	if (mode != DPMSModeOn) { +		intel_sdvo_set_active_outputs(output, 0); +		if (0) +			intel_sdvo_set_encoder_power_state(output, mode); + +		if (mode == DPMSModeOff) { +			temp = I915_READ(sdvo_priv->output_device); +			if ((temp & SDVO_ENABLE) != 0) { +				intel_sdvo_write_sdvox(output, temp & ~SDVO_ENABLE); +			} +		} +	} else { +		bool input1, input2; +		int i; +		u8 status; +		 +		temp = I915_READ(sdvo_priv->output_device); +		if ((temp & SDVO_ENABLE) == 0) +			intel_sdvo_write_sdvox(output, temp | SDVO_ENABLE); +		for (i = 0; i < 2; i++) +		  intel_wait_for_vblank(dev); +		 +		status = intel_sdvo_get_trained_inputs(output, &input1, +						       &input2); + +		 +		/* Warn if the device reported failure to sync.  +		 * A lot of SDVO devices fail to notify of sync, but it's +		 * a given it the status is a success, we succeeded. +		 */ +		if (status == SDVO_CMD_STATUS_SUCCESS && !input1) { +			DRM_DEBUG("First %s output reported failure to sync\n", +				   SDVO_NAME(sdvo_priv)); +		} +		 +		if (0) +			intel_sdvo_set_encoder_power_state(output, mode); +		intel_sdvo_set_active_outputs(output, sdvo_priv->active_outputs); +	}	 +	return; +} + +static void intel_sdvo_save(struct drm_output *output) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_output *intel_output = output->driver_private; +	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; +	int o; + +	sdvo_priv->save_sdvo_mult = intel_sdvo_get_clock_rate_mult(output); +	intel_sdvo_get_active_outputs(output, &sdvo_priv->save_active_outputs); + +	if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) { +		intel_sdvo_set_target_input(output, true, false); +		intel_sdvo_get_input_timing(output, +					    &sdvo_priv->save_input_dtd_1); +	} + +	if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) { +		intel_sdvo_set_target_input(output, false, true); +		intel_sdvo_get_input_timing(output, +					    &sdvo_priv->save_input_dtd_2); +	} + +	for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++) +	{ +	        u16  this_output = (1 << o); +		if (sdvo_priv->caps.output_flags & this_output) +		{ +			intel_sdvo_set_target_output(output, this_output); +			intel_sdvo_get_output_timing(output, +						     &sdvo_priv->save_output_dtd[o]); +		} +	} + +	sdvo_priv->save_SDVOX = I915_READ(sdvo_priv->output_device); +} + +static void intel_sdvo_restore(struct drm_output *output) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_output *intel_output = output->driver_private; +	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; +	int o; +	int i; +	bool input1, input2; +	u8 status; + +	intel_sdvo_set_active_outputs(output, 0); + +	for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++) +	{ +		u16  this_output = (1 << o); +		if (sdvo_priv->caps.output_flags & this_output) { +			intel_sdvo_set_target_output(output, this_output); +			intel_sdvo_set_output_timing(output, &sdvo_priv->save_output_dtd[o]); +		} +	} + +	if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) { +		intel_sdvo_set_target_input(output, true, false); +		intel_sdvo_set_input_timing(output, &sdvo_priv->save_input_dtd_1); +	} + +	if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) { +		intel_sdvo_set_target_input(output, false, true); +		intel_sdvo_set_input_timing(output, &sdvo_priv->save_input_dtd_2); +	} +	 +	intel_sdvo_set_clock_rate_mult(output, sdvo_priv->save_sdvo_mult); +	 +	I915_WRITE(sdvo_priv->output_device, sdvo_priv->save_SDVOX); +	 +	if (sdvo_priv->save_SDVOX & SDVO_ENABLE) +	{ +		for (i = 0; i < 2; i++) +			intel_wait_for_vblank(dev); +		status = intel_sdvo_get_trained_inputs(output, &input1, &input2); +		if (status == SDVO_CMD_STATUS_SUCCESS && !input1) +			DRM_DEBUG("First %s output reported failure to sync\n", +				   SDVO_NAME(sdvo_priv)); +	} +	 +	intel_sdvo_set_active_outputs(output, sdvo_priv->save_active_outputs); +} + +static int intel_sdvo_mode_valid(struct drm_output *output, +				 struct drm_display_mode *mode) +{ +	struct intel_output *intel_output = output->driver_private; +	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; + +	if (mode->flags & V_DBLSCAN) +		return MODE_NO_DBLESCAN; + +	if (sdvo_priv->pixel_clock_min > mode->clock) +		return MODE_CLOCK_LOW; + +	if (sdvo_priv->pixel_clock_max < mode->clock) +		return MODE_CLOCK_HIGH; + +	return MODE_OK; +} + +static bool intel_sdvo_get_capabilities(struct drm_output *output, struct intel_sdvo_caps *caps) +{ +	u8 status; + +	intel_sdvo_write_cmd(output, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0); +	status = intel_sdvo_read_response(output, caps, sizeof(*caps)); +	if (status != SDVO_CMD_STATUS_SUCCESS) +		return false; + +	return true; +} + + +static void intel_sdvo_dump_cmd(struct drm_output *output, int opcode) +{ + + +} + +static void intel_sdvo_dump_device(struct drm_output *output) +{ + +} + +void intel_sdvo_dump(void) +{ + +} + +struct drm_output* intel_sdvo_find(struct drm_device *dev, int sdvoB) +{ +	struct drm_output *output = 0; +	struct intel_output *iout = 0; +	struct intel_sdvo_priv *sdvo; + +	/* find the sdvo output */ +	list_for_each_entry(output, &dev->mode_config.output_list, head) { +		iout = output->driver_private; + +		if (iout->type != INTEL_OUTPUT_SDVO) +			continue; + +		sdvo = iout->dev_priv; + +		if (sdvo->output_device == SDVOB && sdvoB) +			return output; + +		if (sdvo->output_device == SDVOC && !sdvoB) +			return output; + +    } + +	return 0; +} + +int intel_sdvo_supports_hotplug(struct drm_output *output) +{ +	u8 response[2]; +	u8 status; +	DRM_DEBUG("\n"); + +	if (!output) +		return 0; + +	intel_sdvo_write_cmd(output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); +	status = intel_sdvo_read_response(output, &response, 2); + +	if (response[0] !=0) +		return 1; + +	return 0; +} + +void intel_sdvo_set_hotplug(struct drm_output *output, int on) +{ +	struct intel_output *intel_output = output->driver_private; +	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; +	u8 response[2]; +	u8 status; + +	intel_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); +	intel_sdvo_read_response(output, &response, 2); + +	if (on) { +		sdvo_priv->hotplug_enabled = 1; + +		intel_sdvo_write_cmd(output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); +		status = intel_sdvo_read_response(output, &response, 2); + +		intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); +	} else { +		sdvo_priv->hotplug_enabled = 0; + +		response[0] = 0; +		response[1] = 0; +		intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); +	} + +	intel_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); +	intel_sdvo_read_response(output, &response, 2); +} + +static enum drm_output_status intel_sdvo_detect(struct drm_output *output) +{ +	u8 response[2]; +	u8 status; + +	intel_sdvo_write_cmd(output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); +	status = intel_sdvo_read_response(output, &response, 2); + +	DRM_DEBUG("SDVO response %d %d\n", response[0], response[1]); +	if ((response[0] != 0) || (response[1] != 0)) +		return output_status_connected; +	else +		return output_status_disconnected; +} + +static int intel_sdvo_get_modes(struct drm_output *output) +{ +	/* set the bus switch and get the modes */ +	intel_sdvo_set_control_bus_switch(output, SDVO_CONTROL_BUS_DDC2); +	intel_ddc_get_modes(output); + +	if (list_empty(&output->probed_modes)) +		return 0; +	return 1; +#if 0 +	/* Mac mini hack.  On this device, I get DDC through the analog, which +	 * load-detects as disconnected.  I fail to DDC through the SDVO DDC, +	 * but it does load-detect as connected.  So, just steal the DDC bits  +	 * from analog when we fail at finding it the right way. +	 */ +	/* TODO */ +	return NULL; + +	return NULL; +#endif +} + +static void intel_sdvo_destroy(struct drm_output *output) +{ +	struct intel_output *intel_output = output->driver_private; + +	if (intel_output->i2c_bus) +		intel_i2c_destroy(intel_output->i2c_bus); + +	if (intel_output) { +		kfree(intel_output); +		output->driver_private = NULL; +	} +} + +static const struct drm_output_funcs intel_sdvo_output_funcs = { +	.dpms = intel_sdvo_dpms, +	.save = intel_sdvo_save, +	.restore = intel_sdvo_restore, +	.mode_valid = intel_sdvo_mode_valid, +	.mode_fixup = intel_sdvo_mode_fixup, +	.prepare = intel_output_prepare, +	.mode_set = intel_sdvo_mode_set, +	.commit = intel_output_commit, +	.detect = intel_sdvo_detect, +	.get_modes = intel_sdvo_get_modes, +	.cleanup = intel_sdvo_destroy +}; + +void intel_sdvo_init(struct drm_device *dev, int output_device) +{ +	struct drm_output *output; +	struct intel_output *intel_output; +	struct intel_sdvo_priv *sdvo_priv; +	struct intel_i2c_chan *i2cbus = NULL; +	int connector_type; +	u8 ch[0x40]; +	int i; +	int output_type, output_id; + +	output = drm_output_create(dev, &intel_sdvo_output_funcs, +				   DRM_MODE_OUTPUT_NONE); +	if (!output) +		return; + +	intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL); +	if (!intel_output) { +		drm_output_destroy(output); +		return; +	} + +	sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1); +	intel_output->type = INTEL_OUTPUT_SDVO; +	output->driver_private = intel_output; +	output->interlace_allowed = 0; +	output->doublescan_allowed = 0; + +	/* setup the DDC bus. */ +	if (output_device == SDVOB) +		i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB"); +	else +		i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC"); + +	if (i2cbus == NULL) { +		drm_output_destroy(output); +		return; +	} + +	sdvo_priv->i2c_bus = i2cbus; + +	if (output_device == SDVOB) { +		output_id = 1; +		sdvo_priv->i2c_bus->slave_addr = 0x38; +	} else { +		output_id = 2; +		sdvo_priv->i2c_bus->slave_addr = 0x39; +	} + +	sdvo_priv->output_device = output_device; +	sdvo_priv->hotplug_enabled = 0; +	intel_output->i2c_bus = i2cbus; +	intel_output->dev_priv = sdvo_priv; + + +	/* Read the regs to test if we can talk to the device */ +	for (i = 0; i < 0x40; i++) { +		if (!intel_sdvo_read_byte(output, i, &ch[i])) { +			DRM_DEBUG("No SDVO device found on SDVO%c\n", +				  output_device == SDVOB ? 'B' : 'C'); +			drm_output_destroy(output); +			return; +		} +	} + +	intel_sdvo_get_capabilities(output, &sdvo_priv->caps); + +	memset(&sdvo_priv->active_outputs, 0, sizeof(sdvo_priv->active_outputs)); + +	/* TODO, CVBS, SVID, YPRPB & SCART outputs. */ +	if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0) +	{ +		sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0; +		output->subpixel_order = SubPixelHorizontalRGB; +		output_type = DRM_MODE_OUTPUT_DAC; +		connector_type = ConnectorVGA; +	} +	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1) +	{ +		sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1; +		output->subpixel_order = SubPixelHorizontalRGB; +		output_type = DRM_MODE_OUTPUT_DAC; +		connector_type = ConnectorVGA; +	} +	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) +	{ +		sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS0; +		output->subpixel_order = SubPixelHorizontalRGB; +		output_type = DRM_MODE_OUTPUT_TMDS; +		connector_type = ConnectorDVID; +	} +	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS1) +	{ +		sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS1; +		output->subpixel_order = SubPixelHorizontalRGB; +		output_type = DRM_MODE_OUTPUT_TMDS; +		connector_type = ConnectorDVID; +	} +	else +	{ +		unsigned char bytes[2]; +		 +		memcpy (bytes, &sdvo_priv->caps.output_flags, 2); +		DRM_DEBUG("%s: No active RGB or TMDS outputs (0x%02x%02x)\n", +			  SDVO_NAME(sdvo_priv), +			  bytes[0], bytes[1]); +		drm_output_destroy(output); +		return; +	} +	 +	output->output_type = output_type; +	output->output_type_id = output_id; + +	/* Set the input timing to the screen. Assume always input 0. */ +	intel_sdvo_set_target_input(output, true, false); +	 +	intel_sdvo_get_input_pixel_clock_range(output, +					       &sdvo_priv->pixel_clock_min, +					       &sdvo_priv->pixel_clock_max); + + +	DRM_DEBUG("%s device VID/DID: %02X:%02X.%02X, " +		  "clock range %dMHz - %dMHz, " +		  "input 1: %c, input 2: %c, " +		  "output 1: %c, output 2: %c\n", +		  SDVO_NAME(sdvo_priv), +		  sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id, +		  sdvo_priv->caps.device_rev_id, +		  sdvo_priv->pixel_clock_min / 1000, +		  sdvo_priv->pixel_clock_max / 1000, +		  (sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', +		  (sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', +		  /* check currently supported outputs */ +		  sdvo_priv->caps.output_flags &  +		  	(SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N', +		  sdvo_priv->caps.output_flags &  +		  	(SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); + +	intel_output->ddc_bus = i2cbus;	 + +	drm_output_attach_property(output, dev->mode_config.connector_type_property, connector_type); +} diff --git a/linux-core/intel_sdvo_regs.h b/linux-core/intel_sdvo_regs.h new file mode 100644 index 00000000..a9d16711 --- /dev/null +++ b/linux-core/intel_sdvo_regs.h @@ -0,0 +1,328 @@ +/* + * Copyright © 2006-2007 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: + *	Eric Anholt <eric@anholt.net> + */ + +/** + * @file SDVO command definitions and structures. + */ + +#define SDVO_OUTPUT_FIRST   (0) +#define SDVO_OUTPUT_TMDS0   (1 << 0) +#define SDVO_OUTPUT_RGB0    (1 << 1) +#define SDVO_OUTPUT_CVBS0   (1 << 2) +#define SDVO_OUTPUT_SVID0   (1 << 3) +#define SDVO_OUTPUT_YPRPB0  (1 << 4) +#define SDVO_OUTPUT_SCART0  (1 << 5) +#define SDVO_OUTPUT_LVDS0   (1 << 6) +#define SDVO_OUTPUT_TMDS1   (1 << 8) +#define SDVO_OUTPUT_RGB1    (1 << 9) +#define SDVO_OUTPUT_CVBS1   (1 << 10) +#define SDVO_OUTPUT_SVID1   (1 << 11) +#define SDVO_OUTPUT_YPRPB1  (1 << 12) +#define SDVO_OUTPUT_SCART1  (1 << 13) +#define SDVO_OUTPUT_LVDS1   (1 << 14) +#define SDVO_OUTPUT_LAST    (14) + +struct intel_sdvo_caps { +    u8 vendor_id; +    u8 device_id; +    u8 device_rev_id; +    u8 sdvo_version_major; +    u8 sdvo_version_minor; +    unsigned int sdvo_inputs_mask:2; +    unsigned int smooth_scaling:1; +    unsigned int sharp_scaling:1; +    unsigned int up_scaling:1; +    unsigned int down_scaling:1; +    unsigned int stall_support:1; +    unsigned int pad:1; +    u16 output_flags; +} __attribute__((packed)); + +/** This matches the EDID DTD structure, more or less */ +struct intel_sdvo_dtd { +    struct { +	u16 clock;		/**< pixel clock, in 10kHz units */ +	u8 h_active;		/**< lower 8 bits (pixels) */ +	u8 h_blank;		/**< lower 8 bits (pixels) */ +	u8 h_high;		/**< upper 4 bits each h_active, h_blank */ +	u8 v_active;		/**< lower 8 bits (lines) */ +	u8 v_blank;		/**< lower 8 bits (lines) */ +	u8 v_high;		/**< upper 4 bits each v_active, v_blank */ +    } part1; + +    struct { +	u8 h_sync_off;	/**< lower 8 bits, from hblank start */ +	u8 h_sync_width;	/**< lower 8 bits (pixels) */ +	/** lower 4 bits each vsync offset, vsync width */ +	u8 v_sync_off_width; +	/** +	 * 2 high bits of hsync offset, 2 high bits of hsync width, +	 * bits 4-5 of vsync offset, and 2 high bits of vsync width. +	 */ +	u8 sync_off_width_high; +	u8 dtd_flags; +	u8 sdvo_flags; +	/** bits 6-7 of vsync offset at bits 6-7 */ +	u8 v_sync_off_high; +	u8 reserved; +    } part2; +} __attribute__((packed)); + +struct intel_sdvo_pixel_clock_range { +    u16 min;			/**< pixel clock, in 10kHz units */ +    u16 max;			/**< pixel clock, in 10kHz units */ +} __attribute__((packed)); + +struct intel_sdvo_preferred_input_timing_args { +    u16 clock; +    u16 width; +    u16 height; +} __attribute__((packed)); + +/* I2C registers for SDVO */ +#define SDVO_I2C_ARG_0				0x07 +#define SDVO_I2C_ARG_1				0x06 +#define SDVO_I2C_ARG_2				0x05 +#define SDVO_I2C_ARG_3				0x04 +#define SDVO_I2C_ARG_4				0x03 +#define SDVO_I2C_ARG_5				0x02 +#define SDVO_I2C_ARG_6				0x01 +#define SDVO_I2C_ARG_7				0x00 +#define SDVO_I2C_OPCODE				0x08 +#define SDVO_I2C_CMD_STATUS			0x09 +#define SDVO_I2C_RETURN_0			0x0a +#define SDVO_I2C_RETURN_1			0x0b +#define SDVO_I2C_RETURN_2			0x0c +#define SDVO_I2C_RETURN_3			0x0d +#define SDVO_I2C_RETURN_4			0x0e +#define SDVO_I2C_RETURN_5			0x0f +#define SDVO_I2C_RETURN_6			0x10 +#define SDVO_I2C_RETURN_7			0x11 +#define SDVO_I2C_VENDOR_BEGIN			0x20 + +/* Status results */ +#define SDVO_CMD_STATUS_POWER_ON		0x0 +#define SDVO_CMD_STATUS_SUCCESS			0x1 +#define SDVO_CMD_STATUS_NOTSUPP			0x2 +#define SDVO_CMD_STATUS_INVALID_ARG		0x3 +#define SDVO_CMD_STATUS_PENDING			0x4 +#define SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED	0x5 +#define SDVO_CMD_STATUS_SCALING_NOT_SUPP	0x6 + +/* SDVO commands, argument/result registers */ + +#define SDVO_CMD_RESET					0x01 + +/** Returns a struct intel_sdvo_caps */ +#define SDVO_CMD_GET_DEVICE_CAPS			0x02 + +#define SDVO_CMD_GET_FIRMWARE_REV			0x86 +# define SDVO_DEVICE_FIRMWARE_MINOR			SDVO_I2C_RETURN_0 +# define SDVO_DEVICE_FIRMWARE_MAJOR			SDVO_I2C_RETURN_1 +# define SDVO_DEVICE_FIRMWARE_PATCH			SDVO_I2C_RETURN_2 + +/** + * Reports which inputs are trained (managed to sync). + * + * Devices must have trained within 2 vsyncs of a mode change. + */ +#define SDVO_CMD_GET_TRAINED_INPUTS			0x03 +struct intel_sdvo_get_trained_inputs_response { +    unsigned int input0_trained:1; +    unsigned int input1_trained:1; +    unsigned int pad:6; +} __attribute__((packed)); + +/** Returns a struct intel_sdvo_output_flags of active outputs. */ +#define SDVO_CMD_GET_ACTIVE_OUTPUTS			0x04 + +/** + * Sets the current set of active outputs. + * + * Takes a struct intel_sdvo_output_flags.  Must be preceded by a SET_IN_OUT_MAP + * on multi-output devices. + */ +#define SDVO_CMD_SET_ACTIVE_OUTPUTS			0x05 + +/** + * Returns the current mapping of SDVO inputs to outputs on the device. + * + * Returns two struct intel_sdvo_output_flags structures. + */ +#define SDVO_CMD_GET_IN_OUT_MAP				0x06 + +/** + * Sets the current mapping of SDVO inputs to outputs on the device. + * + * Takes two struct i380_sdvo_output_flags structures. + */ +#define SDVO_CMD_SET_IN_OUT_MAP				0x07 + +/** + * Returns a struct intel_sdvo_output_flags of attached displays. + */ +#define SDVO_CMD_GET_ATTACHED_DISPLAYS			0x0b + +/** + * Returns a struct intel_sdvo_ouptut_flags of displays supporting hot plugging. + */ +#define SDVO_CMD_GET_HOT_PLUG_SUPPORT			0x0c + +/** + * Takes a struct intel_sdvo_output_flags. + */ +#define SDVO_CMD_SET_ACTIVE_HOT_PLUG			0x0d + +/** + * Returns a struct intel_sdvo_output_flags of displays with hot plug + * interrupts enabled. + */ +#define SDVO_CMD_GET_ACTIVE_HOT_PLUG			0x0e + +#define SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE		0x0f +struct intel_sdvo_get_interrupt_event_source_response { +    u16 interrupt_status; +    unsigned int ambient_light_interrupt:1; +    unsigned int pad:7; +} __attribute__((packed)); + +/** + * Selects which input is affected by future input commands. + * + * Commands affected include SET_INPUT_TIMINGS_PART[12], + * GET_INPUT_TIMINGS_PART[12], GET_PREFERRED_INPUT_TIMINGS_PART[12], + * GET_INPUT_PIXEL_CLOCK_RANGE, and CREATE_PREFERRED_INPUT_TIMINGS. + */ +#define SDVO_CMD_SET_TARGET_INPUT			0x10 +struct intel_sdvo_set_target_input_args { +    unsigned int target_1:1; +    unsigned int pad:7; +} __attribute__((packed)); + +/** + * Takes a struct intel_sdvo_output_flags of which outputs are targetted by + * future output commands. + * + * Affected commands inclue SET_OUTPUT_TIMINGS_PART[12], + * GET_OUTPUT_TIMINGS_PART[12], and GET_OUTPUT_PIXEL_CLOCK_RANGE. + */ +#define SDVO_CMD_SET_TARGET_OUTPUT			0x11 + +#define SDVO_CMD_GET_INPUT_TIMINGS_PART1		0x12 +#define SDVO_CMD_GET_INPUT_TIMINGS_PART2		0x13 +#define SDVO_CMD_SET_INPUT_TIMINGS_PART1		0x14 +#define SDVO_CMD_SET_INPUT_TIMINGS_PART2		0x15 +#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART1		0x16 +#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART2		0x17 +#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART1		0x18 +#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART2		0x19 +/* Part 1 */ +# define SDVO_DTD_CLOCK_LOW				SDVO_I2C_ARG_0 +# define SDVO_DTD_CLOCK_HIGH				SDVO_I2C_ARG_1 +# define SDVO_DTD_H_ACTIVE				SDVO_I2C_ARG_2 +# define SDVO_DTD_H_BLANK				SDVO_I2C_ARG_3 +# define SDVO_DTD_H_HIGH				SDVO_I2C_ARG_4 +# define SDVO_DTD_V_ACTIVE				SDVO_I2C_ARG_5 +# define SDVO_DTD_V_BLANK				SDVO_I2C_ARG_6 +# define SDVO_DTD_V_HIGH				SDVO_I2C_ARG_7 +/* Part 2 */ +# define SDVO_DTD_HSYNC_OFF				SDVO_I2C_ARG_0 +# define SDVO_DTD_HSYNC_WIDTH				SDVO_I2C_ARG_1 +# define SDVO_DTD_VSYNC_OFF_WIDTH			SDVO_I2C_ARG_2 +# define SDVO_DTD_SYNC_OFF_WIDTH_HIGH			SDVO_I2C_ARG_3 +# define SDVO_DTD_DTD_FLAGS				SDVO_I2C_ARG_4 +# define SDVO_DTD_DTD_FLAG_INTERLACED				(1 << 7) +# define SDVO_DTD_DTD_FLAG_STEREO_MASK				(3 << 5) +# define SDVO_DTD_DTD_FLAG_INPUT_MASK				(3 << 3) +# define SDVO_DTD_DTD_FLAG_SYNC_MASK				(3 << 1) +# define SDVO_DTD_SDVO_FLAS				SDVO_I2C_ARG_5 +# define SDVO_DTD_SDVO_FLAG_STALL				(1 << 7) +# define SDVO_DTD_SDVO_FLAG_CENTERED				(0 << 6) +# define SDVO_DTD_SDVO_FLAG_UPPER_LEFT				(1 << 6) +# define SDVO_DTD_SDVO_FLAG_SCALING_MASK			(3 << 4) +# define SDVO_DTD_SDVO_FLAG_SCALING_NONE			(0 << 4) +# define SDVO_DTD_SDVO_FLAG_SCALING_SHARP			(1 << 4) +# define SDVO_DTD_SDVO_FLAG_SCALING_SMOOTH			(2 << 4) +# define SDVO_DTD_VSYNC_OFF_HIGH			SDVO_I2C_ARG_6 + +/** + * Generates a DTD based on the given width, height, and flags. + * + * This will be supported by any device supporting scaling or interlaced + * modes. + */ +#define SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING		0x1a +# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_LOW		SDVO_I2C_ARG_0 +# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_HIGH		SDVO_I2C_ARG_1 +# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_LOW		SDVO_I2C_ARG_2 +# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_HIGH		SDVO_I2C_ARG_3 +# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_LOW		SDVO_I2C_ARG_4 +# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_HIGH	SDVO_I2C_ARG_5 +# define SDVO_PREFERRED_INPUT_TIMING_FLAGS		SDVO_I2C_ARG_6 +# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_INTERLACED		(1 << 0) +# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_SCALED		(1 << 1) + +#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1	0x1b +#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2	0x1c + +/** Returns a struct intel_sdvo_pixel_clock_range */ +#define SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE		0x1d +/** Returns a struct intel_sdvo_pixel_clock_range */ +#define SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE		0x1e + +/** Returns a byte bitfield containing SDVO_CLOCK_RATE_MULT_* flags */ +#define SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS		0x1f + +/** Returns a byte containing a SDVO_CLOCK_RATE_MULT_* flag */ +#define SDVO_CMD_GET_CLOCK_RATE_MULT			0x20 +/** Takes a byte containing a SDVO_CLOCK_RATE_MULT_* flag */ +#define SDVO_CMD_SET_CLOCK_RATE_MULT			0x21 +# define SDVO_CLOCK_RATE_MULT_1X				(1 << 0) +# define SDVO_CLOCK_RATE_MULT_2X				(1 << 1) +# define SDVO_CLOCK_RATE_MULT_4X				(1 << 3) + +#define SDVO_CMD_GET_SUPPORTED_TV_FORMATS		0x27 + +#define SDVO_CMD_GET_TV_FORMAT				0x28 + +#define SDVO_CMD_SET_TV_FORMAT				0x29 + +#define SDVO_CMD_GET_SUPPORTED_POWER_STATES		0x2a +#define SDVO_CMD_GET_ENCODER_POWER_STATE		0x2b +#define SDVO_CMD_SET_ENCODER_POWER_STATE		0x2c +# define SDVO_ENCODER_STATE_ON					(1 << 0) +# define SDVO_ENCODER_STATE_STANDBY				(1 << 1) +# define SDVO_ENCODER_STATE_SUSPEND				(1 << 2) +# define SDVO_ENCODER_STATE_OFF					(1 << 3) + +#define SDVO_CMD_SET_TV_RESOLUTION_SUPPORT		0x93 + +#define SDVO_CMD_SET_CONTROL_BUS_SWITCH			0x7a +# define SDVO_CONTROL_BUS_PROM				0x0 +# define SDVO_CONTROL_BUS_DDC1				0x1 +# define SDVO_CONTROL_BUS_DDC2				0x2 +# define SDVO_CONTROL_BUS_DDC3				0x3 + diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c new file mode 100644 index 00000000..0edbdbac --- /dev/null +++ b/linux-core/intel_tv.c @@ -0,0 +1,1763 @@ +/* + * Copyright © 2006 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: + *    Eric Anholt <eric@anholt.net> + * + */ + +/** @file + * Integrated TV-out support for the 915GM and 945GM. + */ + +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "drm_edid.h" +#include "intel_drv.h" +#include "i915_drm.h" +#include "i915_drv.h" + +enum tv_type { +	TV_TYPE_NONE, +	TV_TYPE_UNKNOWN, +	TV_TYPE_COMPOSITE, +	TV_TYPE_SVIDEO, +	TV_TYPE_COMPONENT +}; + +enum tv_margin { +	TV_MARGIN_LEFT, TV_MARGIN_TOP, +	TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM +}; + +/** Private structure for the integrated TV support */ +struct intel_tv_priv { +	int type; +	char *tv_format; +	int margin[4]; +	u32 save_TV_H_CTL_1; +	u32 save_TV_H_CTL_2; +	u32 save_TV_H_CTL_3; +	u32 save_TV_V_CTL_1; +	u32 save_TV_V_CTL_2; +	u32 save_TV_V_CTL_3; +	u32 save_TV_V_CTL_4; +	u32 save_TV_V_CTL_5; +	u32 save_TV_V_CTL_6; +	u32 save_TV_V_CTL_7; +	u32 save_TV_SC_CTL_1, save_TV_SC_CTL_2, save_TV_SC_CTL_3; + +	u32 save_TV_CSC_Y; +	u32 save_TV_CSC_Y2; +	u32 save_TV_CSC_U; +	u32 save_TV_CSC_U2; +	u32 save_TV_CSC_V; +	u32 save_TV_CSC_V2; +	u32 save_TV_CLR_KNOBS; +	u32 save_TV_CLR_LEVEL; +	u32 save_TV_WIN_POS; +	u32 save_TV_WIN_SIZE; +	u32 save_TV_FILTER_CTL_1; +	u32 save_TV_FILTER_CTL_2; +	u32 save_TV_FILTER_CTL_3; + +	u32 save_TV_H_LUMA[60]; +	u32 save_TV_H_CHROMA[60]; +	u32 save_TV_V_LUMA[43]; +	u32 save_TV_V_CHROMA[43]; + +	u32 save_TV_DAC; +	u32 save_TV_CTL; +}; + +struct video_levels { +	int blank, black, burst; +}; + +struct color_conversion { +	u16 ry, gy, by, ay; +	u16 ru, gu, bu, au; +	u16 rv, gv, bv, av; +}; + +static const u32 filter_table[] = { +	0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140, +	0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000, +	0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160, +	0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780, +	0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50, +	0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20, +	0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0, +	0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0, +	0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020, +	0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140, +	0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20, +	0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848, +	0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900, +	0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080, +	0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060, +	0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140, +	0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000, +	0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160, +	0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780, +	0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50, +	0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20, +	0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0, +	0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0, +	0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020, +	0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140, +	0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20, +	0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848, +	0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900, +	0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080, +	0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060, +	0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0, +	0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540, +	0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00, +	0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000, +	0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00, +	0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40, +	0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240, +	0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00, +	0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0, +	0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840, +	0x28003100, 0x28002F00, 0x00003100, 0x36403000,  +	0x2D002CC0, 0x30003640, 0x2D0036C0, +	0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540, +	0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00, +	0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000, +	0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00, +	0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40, +	0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240, +	0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00, +	0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0, +	0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840, +	0x28003100, 0x28002F00, 0x00003100, +}; + +/* + * Color conversion values have 3 separate fixed point formats: + * + * 10 bit fields (ay, au) + *   1.9 fixed point (b.bbbbbbbbb) + * 11 bit fields (ry, by, ru, gu, gv) + *   exp.mantissa (ee.mmmmmmmmm) + *   ee = 00 = 10^-1 (0.mmmmmmmmm) + *   ee = 01 = 10^-2 (0.0mmmmmmmmm) + *   ee = 10 = 10^-3 (0.00mmmmmmmmm) + *   ee = 11 = 10^-4 (0.000mmmmmmmmm) + * 12 bit fields (gy, rv, bu) + *   exp.mantissa (eee.mmmmmmmmm) + *   eee = 000 = 10^-1 (0.mmmmmmmmm) + *   eee = 001 = 10^-2 (0.0mmmmmmmmm) + *   eee = 010 = 10^-3 (0.00mmmmmmmmm) + *   eee = 011 = 10^-4 (0.000mmmmmmmmm) + *   eee = 100 = reserved + *   eee = 101 = reserved + *   eee = 110 = reserved + *   eee = 111 = 10^0 (m.mmmmmmmm) (only usable for 1.0 representation) + * + * Saturation and contrast are 8 bits, with their own representation: + * 8 bit field (saturation, contrast) + *   exp.mantissa (ee.mmmmmm) + *   ee = 00 = 10^-1 (0.mmmmmm) + *   ee = 01 = 10^0 (m.mmmmm) + *   ee = 10 = 10^1 (mm.mmmm) + *   ee = 11 = 10^2 (mmm.mmm) + * + * Simple conversion function: + * + * static u32 + * float_to_csc_11(float f) + * { + *     u32 exp; + *     u32 mant; + *     u32 ret; + *  + *     if (f < 0) + *         f = -f; + *  + *     if (f >= 1) { + *         exp = 0x7; + * 	   mant = 1 << 8; + *     } else { + *         for (exp = 0; exp < 3 && f < 0.5; exp++) + * 	       f *= 2.0; + *         mant = (f * (1 << 9) + 0.5); + *         if (mant >= (1 << 9)) + *             mant = (1 << 9) - 1; + *     } + *     ret = (exp << 9) | mant; + *     return ret; + * } + */ + +/* + * Behold, magic numbers!  If we plant them they might grow a big + * s-video cable to the sky... or something. + * + * Pre-converted to appropriate hex value. + */ + +/* + * PAL & NTSC values for composite & s-video connections + */ +static const struct color_conversion ntsc_m_csc_composite = { +	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104, +	.ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00, +	.rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00, +}; + +static const struct video_levels ntsc_m_levels_composite = { +	.blank = 225, .black = 267, .burst = 113, +}; + +static const struct color_conversion ntsc_m_csc_svideo = { +	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134, +	.ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00, +	.rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00, +}; + +static const struct video_levels ntsc_m_levels_svideo = { +	.blank = 266, .black = 316, .burst = 133, +}; + +static const struct color_conversion ntsc_j_csc_composite = { +	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119, +	.ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0f00, +	.rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0f00, +}; + +static const struct video_levels ntsc_j_levels_composite = { +	.blank = 225, .black = 225, .burst = 113, +}; + +static const struct color_conversion ntsc_j_csc_svideo = { +	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c, +	.ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0f00, +	.rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0f00, +}; + +static const struct video_levels ntsc_j_levels_svideo = { +	.blank = 266, .black = 266, .burst = 133, +}; + +static const struct color_conversion pal_csc_composite = { +	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113, +	.ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0f00, +	.rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0f00, +}; +	 +static const struct video_levels pal_levels_composite = { +	.blank = 237, .black = 237, .burst = 118, +}; + +static const struct color_conversion pal_csc_svideo = { +	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145, +	.ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0f00, +	.rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0f00, +}; + +static const struct video_levels pal_levels_svideo = { +	.blank = 280, .black = 280, .burst = 139, +}; + +static const struct color_conversion pal_m_csc_composite = { +	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104, +	.ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00, +	.rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00, +}; + +static const struct video_levels pal_m_levels_composite = { +	.blank = 225, .black = 267, .burst = 113, +}; + +static const struct color_conversion pal_m_csc_svideo = { +	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134, +	.ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00, +	.rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00, +}; + +static const struct video_levels pal_m_levels_svideo = { +	.blank = 266, .black = 316, .burst = 133, +}; + +static const struct color_conversion pal_n_csc_composite = { +	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104, +	.ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00, +	.rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00, +}; + +static const struct video_levels pal_n_levels_composite = { +	.blank = 225, .black = 267, .burst = 118, +}; + +static const struct color_conversion pal_n_csc_svideo = { +	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134, +	.ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00, +	.rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00, +}; + +static const struct video_levels pal_n_levels_svideo = { +	.blank = 266, .black = 316, .burst = 139, +}; + +/* + * Component connections + */ +static const struct color_conversion sdtv_csc_yprpb = { +	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0146, +	.ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0f00, +	.rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0f00, +}; + +static const struct color_conversion sdtv_csc_rgb = { +	.ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166, +	.ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166, +	.rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166, +}; + +static const struct color_conversion hdtv_csc_yprpb = { +	.ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0146, +	.ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0f00, +	.rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0f00, +}; + +static const struct color_conversion hdtv_csc_rgb = { +	.ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166, +	.ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166, +	.rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166, +}; + +static const struct video_levels component_levels = { +	.blank = 279, .black = 279, .burst = 0, +}; + + +struct tv_mode { +	char *name; +	int clock; +	int refresh; /* in millihertz (for precision) */ +	u32 oversample; +	int hsync_end, hblank_start, hblank_end, htotal; +	bool progressive, trilevel_sync, component_only; +	int vsync_start_f1, vsync_start_f2, vsync_len; +	bool veq_ena; +	int veq_start_f1, veq_start_f2, veq_len; +	int vi_end_f1, vi_end_f2, nbr_end; +	bool burst_ena; +	int hburst_start, hburst_len; +	int vburst_start_f1, vburst_end_f1; +	int vburst_start_f2, vburst_end_f2; +	int vburst_start_f3, vburst_end_f3; +	int vburst_start_f4, vburst_end_f4; +	/* +	 * subcarrier programming +	 */ +	int dda2_size, dda3_size, dda1_inc, dda2_inc, dda3_inc; +	u32 sc_reset; +	bool pal_burst; +	/* +	 * blank/black levels +	 */ +	const struct video_levels *composite_levels, *svideo_levels; +	const struct color_conversion *composite_color, *svideo_color; +	const u32 *filter_table; +	int max_srcw; +}; + + +/* + * Sub carrier DDA + * + *  I think this works as follows: + * + *  subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096 + * + * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value + * + * So, + *  dda1_ideal = subcarrier/pixel * 4096 + *  dda1_inc = floor (dda1_ideal) + *  dda2 = dda1_ideal - dda1_inc + * + *  then pick a ratio for dda2 that gives the closest approximation. If + *  you can't get close enough, you can play with dda3 as well. This + *  seems likely to happen when dda2 is small as the jumps would be larger + * + * To invert this, + * + *  pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size) + * + * The constants below were all computed using a 107.520MHz clock + */ +  +/** + * Register programming values for TV modes. + * + * These values account for -1s required. + */ + +const static struct tv_mode tv_modes[] = { +	{ +		.name		= "NTSC-M", +		.clock		= 107520,	 +		.refresh	= 29970, +		.oversample	= TV_OVERSAMPLE_8X, +		.component_only = 0, +		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */ + +		.hsync_end	= 64,		    .hblank_end		= 124, +		.hblank_start	= 836,		    .htotal		= 857, + +		.progressive	= FALSE,	    .trilevel_sync = FALSE, + +		.vsync_start_f1	= 6,		    .vsync_start_f2	= 7, +		.vsync_len	= 6, + +		.veq_ena	= TRUE,		    .veq_start_f1    	= 0, +		.veq_start_f2	= 1,		    .veq_len		= 18, + +		.vi_end_f1	= 20,		    .vi_end_f2		= 21, +		.nbr_end	= 240, + +		.burst_ena	= TRUE, +		.hburst_start	= 72,		    .hburst_len		= 34, +		.vburst_start_f1 = 9,		    .vburst_end_f1	= 240, +		.vburst_start_f2 = 10,		    .vburst_end_f2	= 240, +		.vburst_start_f3 = 9,		    .vburst_end_f3	= 240,  +		.vburst_start_f4 = 10,		    .vburst_end_f4	= 240, + +		/* desired 3.5800000 actual 3.5800000 clock 107.52 */ +		.dda1_inc	=    136, +		.dda2_inc	=   7624,	    .dda2_size		=  20013, +		.dda3_inc	=      0,	    .dda3_size		=      0, +		.sc_reset	= TV_SC_RESET_EVERY_4, +		.pal_burst	= FALSE, + +		.composite_levels = &ntsc_m_levels_composite, +		.composite_color = &ntsc_m_csc_composite, +		.svideo_levels  = &ntsc_m_levels_svideo, +		.svideo_color = &ntsc_m_csc_svideo, + +		.filter_table = filter_table, +	}, +	{ +		.name		= "NTSC-443", +		.clock		= 107520,	 +		.refresh	= 29970, +		.oversample	= TV_OVERSAMPLE_8X, +		.component_only = 0, +		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */ +		.hsync_end	= 64,		    .hblank_end		= 124, +		.hblank_start	= 836,		    .htotal		= 857, + +		.progressive	= FALSE,	    .trilevel_sync = FALSE, + +		.vsync_start_f1 = 6,		    .vsync_start_f2	= 7, +		.vsync_len	= 6, + +		.veq_ena	= TRUE,		    .veq_start_f1    	= 0, +		.veq_start_f2	= 1,		    .veq_len		= 18, + +		.vi_end_f1	= 20,		    .vi_end_f2		= 21, +		.nbr_end	= 240, + +		.burst_ena	= 8, +		.hburst_start	= 72,		    .hburst_len		= 34, +		.vburst_start_f1 = 9,		    .vburst_end_f1	= 240, +		.vburst_start_f2 = 10,		    .vburst_end_f2	= 240, +		.vburst_start_f3 = 9,		    .vburst_end_f3	= 240,  +		.vburst_start_f4 = 10,		    .vburst_end_f4	= 240, + +		/* desired 4.4336180 actual 4.4336180 clock 107.52 */ +		.dda1_inc       =    168, +		.dda2_inc       =  18557,       .dda2_size      =  20625, +		.dda3_inc       =      0,       .dda3_size      =      0, +		.sc_reset   = TV_SC_RESET_EVERY_8, +		.pal_burst  = TRUE, + +		.composite_levels = &ntsc_m_levels_composite, +		.composite_color = &ntsc_m_csc_composite, +		.svideo_levels  = &ntsc_m_levels_svideo, +		.svideo_color = &ntsc_m_csc_svideo, + +		.filter_table = filter_table, +	}, +	{ +		.name		= "NTSC-J", +		.clock		= 107520,	 +		.refresh	= 29970, +		.oversample	= TV_OVERSAMPLE_8X, +		.component_only = 0, + +		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */ +		.hsync_end	= 64,		    .hblank_end		= 124, +		.hblank_start = 836,	    .htotal		= 857, + +		.progressive	= FALSE,    .trilevel_sync = FALSE, + +		.vsync_start_f1	= 6,	    .vsync_start_f2	= 7, +		.vsync_len	= 6, + +		.veq_ena	= TRUE,		    .veq_start_f1    	= 0, +		.veq_start_f2 = 1,	    .veq_len		= 18, + +		.vi_end_f1	= 20,		    .vi_end_f2		= 21, +		.nbr_end	= 240, + +		.burst_ena	= TRUE, +		.hburst_start	= 72,		    .hburst_len		= 34, +		.vburst_start_f1 = 9,		    .vburst_end_f1	= 240, +		.vburst_start_f2 = 10,		    .vburst_end_f2	= 240, +		.vburst_start_f3 = 9,		    .vburst_end_f3	= 240,  +		.vburst_start_f4 = 10,		    .vburst_end_f4	= 240, + +		/* desired 3.5800000 actual 3.5800000 clock 107.52 */ +		.dda1_inc	=    136, +		.dda2_inc	=   7624,	    .dda2_size		=  20013, +		.dda3_inc	=      0,	    .dda3_size		=      0, +		.sc_reset	= TV_SC_RESET_EVERY_4, +		.pal_burst	= FALSE, + +		.composite_levels = &ntsc_j_levels_composite, +		.composite_color = &ntsc_j_csc_composite, +		.svideo_levels  = &ntsc_j_levels_svideo, +		.svideo_color = &ntsc_j_csc_svideo, + +		.filter_table = filter_table, +	}, +	{ +		.name		= "PAL-M", +		.clock		= 107520,	 +		.refresh	= 29970, +		.oversample	= TV_OVERSAMPLE_8X, +		.component_only = 0, + +		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */ +		.hsync_end	= 64,		  .hblank_end		= 124, +		.hblank_start = 836,	  .htotal		= 857, + +		.progressive	= FALSE,	    .trilevel_sync = FALSE, + +		.vsync_start_f1	= 6,		    .vsync_start_f2	= 7, +		.vsync_len	= 6, + +		.veq_ena	= TRUE,		    .veq_start_f1    	= 0, +		.veq_start_f2	= 1,		    .veq_len		= 18, + +		.vi_end_f1	= 20,		    .vi_end_f2		= 21, +		.nbr_end	= 240, + +		.burst_ena	= TRUE, +		.hburst_start	= 72,		    .hburst_len		= 34, +		.vburst_start_f1 = 9,		    .vburst_end_f1	= 240, +		.vburst_start_f2 = 10,		    .vburst_end_f2	= 240, +		.vburst_start_f3 = 9,		    .vburst_end_f3	= 240,  +		.vburst_start_f4 = 10,		    .vburst_end_f4	= 240, + +		/* desired 3.5800000 actual 3.5800000 clock 107.52 */ +		.dda1_inc	=    136, +		.dda2_inc	=    7624,	    .dda2_size		=  20013, +		.dda3_inc	=      0,	    .dda3_size		=      0, +		.sc_reset	= TV_SC_RESET_EVERY_4, +		.pal_burst  = FALSE, + +		.composite_levels = &pal_m_levels_composite, +		.composite_color = &pal_m_csc_composite, +		.svideo_levels  = &pal_m_levels_svideo, +		.svideo_color = &pal_m_csc_svideo, + +		.filter_table = filter_table, +	}, +	{ +		/* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */ +		.name	    = "PAL-N", +		.clock		= 107520,	 +		.refresh	= 25000, +		.oversample	= TV_OVERSAMPLE_8X, +		.component_only = 0, + +		.hsync_end	= 64,		    .hblank_end		= 128, +		.hblank_start = 844,	    .htotal		= 863, + +		.progressive  = FALSE,    .trilevel_sync = FALSE, + + +		.vsync_start_f1	= 6,	   .vsync_start_f2	= 7, +		.vsync_len	= 6, + +		.veq_ena	= TRUE,		    .veq_start_f1    	= 0, +		.veq_start_f2	= 1,		    .veq_len		= 18, + +		.vi_end_f1	= 24,		    .vi_end_f2		= 25, +		.nbr_end	= 286, + +		.burst_ena	= TRUE, +		.hburst_start = 73,	    	    .hburst_len		= 34, +		.vburst_start_f1 = 8,	    .vburst_end_f1	= 285, +		.vburst_start_f2 = 8,	    .vburst_end_f2	= 286, +		.vburst_start_f3 = 9,	    .vburst_end_f3	= 286,  +		.vburst_start_f4 = 9,	    .vburst_end_f4	= 285, + + +		/* desired 4.4336180 actual 4.4336180 clock 107.52 */ +		.dda1_inc       =    168, +		.dda2_inc       =  18557,       .dda2_size      =  20625, +		.dda3_inc       =      0,       .dda3_size      =      0, +		.sc_reset   = TV_SC_RESET_EVERY_8, +		.pal_burst  = TRUE, + +		.composite_levels = &pal_n_levels_composite, +		.composite_color = &pal_n_csc_composite, +		.svideo_levels  = &pal_n_levels_svideo, +		.svideo_color = &pal_n_csc_svideo, + +		.filter_table = filter_table, +	}, +	{ +		/* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */ +		.name	    = "PAL", +		.clock		= 107520,	 +		.refresh	= 25000, +		.oversample	= TV_OVERSAMPLE_8X, +		.component_only = 0, + +		.hsync_end	= 64,		    .hblank_end		= 128, +		.hblank_start	= 844,	    .htotal		= 863, + +		.progressive	= FALSE,    .trilevel_sync = FALSE, + +		.vsync_start_f1	= 5,	    .vsync_start_f2	= 6, +		.vsync_len	= 5, + +		.veq_ena	= TRUE,		    .veq_start_f1    	= 0, +		.veq_start_f2	= 1,	    .veq_len		= 15, + +		.vi_end_f1	= 24,		    .vi_end_f2		= 25, +		.nbr_end	= 286, + +		.burst_ena	= TRUE, +		.hburst_start	= 73,		    .hburst_len		= 32, +		.vburst_start_f1 = 8,		    .vburst_end_f1	= 285, +		.vburst_start_f2 = 8,		    .vburst_end_f2	= 286, +		.vburst_start_f3 = 9,		    .vburst_end_f3	= 286,  +		.vburst_start_f4 = 9,		    .vburst_end_f4	= 285, + +		/* desired 4.4336180 actual 4.4336180 clock 107.52 */ +		.dda1_inc       =    168, +		.dda2_inc       =  18557,       .dda2_size      =  20625, +		.dda3_inc       =      0,       .dda3_size      =      0, +		.sc_reset   = TV_SC_RESET_EVERY_8, +		.pal_burst  = TRUE, + +		.composite_levels = &pal_levels_composite, +		.composite_color = &pal_csc_composite, +		.svideo_levels  = &pal_levels_svideo, +		.svideo_color = &pal_csc_svideo, + +		.filter_table = filter_table, +	}, +	{ +		.name       = "480p@59.94Hz", +		.clock 	= 107520,	 +		.refresh	= 59940, +		.oversample     = TV_OVERSAMPLE_4X, +		.component_only = 1, + +		.hsync_end      = 64,               .hblank_end         = 122, +		.hblank_start   = 842,              .htotal             = 857, + +		.progressive    = TRUE,.trilevel_sync = FALSE, + +		.vsync_start_f1 = 12,               .vsync_start_f2     = 12, +		.vsync_len      = 12, + +		.veq_ena        = FALSE, + +		.vi_end_f1      = 44,               .vi_end_f2          = 44, +		.nbr_end        = 496, + +		.burst_ena      = FALSE, + +		.filter_table = filter_table, +	}, +	{ +		.name       = "480p@60Hz", +		.clock 	= 107520,	 +		.refresh	= 60000, +		.oversample     = TV_OVERSAMPLE_4X, +		.component_only = 1, + +		.hsync_end      = 64,               .hblank_end         = 122, +		.hblank_start   = 842,              .htotal             = 856, + +		.progressive    = TRUE,.trilevel_sync = FALSE, + +		.vsync_start_f1 = 12,               .vsync_start_f2     = 12, +		.vsync_len      = 12, + +		.veq_ena        = FALSE, + +		.vi_end_f1      = 44,               .vi_end_f2          = 44, +		.nbr_end        = 496, + +		.burst_ena      = FALSE, + +		.filter_table = filter_table, +	}, +	{ +		.name       = "576p", +		.clock 	= 107520,	 +		.refresh	= 50000, +		.oversample     = TV_OVERSAMPLE_4X, +		.component_only = 1, + +		.hsync_end      = 64,               .hblank_end         = 139, +		.hblank_start   = 859,              .htotal             = 863, + +		.progressive    = TRUE,		.trilevel_sync = FALSE, + +		.vsync_start_f1 = 10,               .vsync_start_f2     = 10, +		.vsync_len      = 10, + +		.veq_ena        = FALSE, + +		.vi_end_f1      = 48,               .vi_end_f2          = 48, +		.nbr_end        = 575, + +		.burst_ena      = FALSE, + +		.filter_table = filter_table, +	}, +	{ +		.name       = "720p@60Hz", +		.clock		= 148800,	 +		.refresh	= 60000, +		.oversample     = TV_OVERSAMPLE_2X, +		.component_only = 1, + +		.hsync_end      = 80,               .hblank_end         = 300, +		.hblank_start   = 1580,             .htotal             = 1649, + +		.progressive    = TRUE, 	    .trilevel_sync = TRUE, + +		.vsync_start_f1 = 10,               .vsync_start_f2     = 10, +		.vsync_len      = 10, + +		.veq_ena        = FALSE, + +		.vi_end_f1      = 29,               .vi_end_f2          = 29, +		.nbr_end        = 719, + +		.burst_ena      = FALSE, + +		.filter_table = filter_table, +	}, +	{ +		.name       = "720p@59.94Hz", +		.clock		= 148800,	 +		.refresh	= 59940, +		.oversample     = TV_OVERSAMPLE_2X, +		.component_only = 1, + +		.hsync_end      = 80,               .hblank_end         = 300, +		.hblank_start   = 1580,             .htotal             = 1651, + +		.progressive    = TRUE, 	    .trilevel_sync = TRUE, + +		.vsync_start_f1 = 10,               .vsync_start_f2     = 10, +		.vsync_len      = 10, + +		.veq_ena        = FALSE, + +		.vi_end_f1      = 29,               .vi_end_f2          = 29, +		.nbr_end        = 719, + +		.burst_ena      = FALSE, + +		.filter_table = filter_table, +	}, +	{ +		.name       = "720p@50Hz", +		.clock		= 148800,	 +		.refresh	= 50000, +		.oversample     = TV_OVERSAMPLE_2X, +		.component_only = 1, + +		.hsync_end      = 80,               .hblank_end         = 300, +		.hblank_start   = 1580,             .htotal             = 1979, + +		.progressive    = TRUE, 	        .trilevel_sync = TRUE, + +		.vsync_start_f1 = 10,               .vsync_start_f2     = 10, +		.vsync_len      = 10, + +		.veq_ena        = FALSE, + +		.vi_end_f1      = 29,               .vi_end_f2          = 29, +		.nbr_end        = 719, + +		.burst_ena      = FALSE, + +		.filter_table = filter_table, +		.max_srcw = 800 +	}, +	{ +		.name       = "1080i@50Hz", +		.clock		= 148800,	 +		.refresh	= 25000, +		.oversample     = TV_OVERSAMPLE_2X, +		.component_only = 1, + +		.hsync_end      = 88,               .hblank_end         = 235, +		.hblank_start   = 2155,             .htotal             = 2639, + +		.progressive    = FALSE, 	    .trilevel_sync = TRUE, + +		.vsync_start_f1 = 4,              .vsync_start_f2     = 5, +		.vsync_len      = 10, + +		.veq_ena	= TRUE,		    .veq_start_f1    	= 4, +		.veq_start_f2   = 4,	    .veq_len		= 10, + + +		.vi_end_f1      = 21,           .vi_end_f2          = 22, +		.nbr_end        = 539, + +		.burst_ena      = FALSE, + +		.filter_table = filter_table, +	}, +	{ +		.name       = "1080i@60Hz", +		.clock		= 148800,	 +		.refresh	= 30000, +		.oversample     = TV_OVERSAMPLE_2X, +		.component_only = 1, + +		.hsync_end      = 88,               .hblank_end         = 235, +		.hblank_start   = 2155,             .htotal             = 2199, + +		.progressive    = FALSE, 	    .trilevel_sync = TRUE, + +		.vsync_start_f1 = 4,               .vsync_start_f2     = 5, +		.vsync_len      = 10, + +		.veq_ena	= TRUE,		    .veq_start_f1    	= 4, +		.veq_start_f2	= 4,		    .veq_len		= 10, + + +		.vi_end_f1      = 21,               .vi_end_f2          = 22, +		.nbr_end        = 539, + +		.burst_ena      = FALSE, + +		.filter_table = filter_table, +	}, +	{ +		.name       = "1080i@59.94Hz", +		.clock		= 148800,	 +		.refresh	= 29970, +		.oversample     = TV_OVERSAMPLE_2X, +		.component_only = 1, + +		.hsync_end      = 88,               .hblank_end         = 235, +		.hblank_start   = 2155,             .htotal             = 2200, + +		.progressive    = FALSE, 	    .trilevel_sync = TRUE, + +		.vsync_start_f1 = 4,            .vsync_start_f2    = 5, +		.vsync_len      = 10, + +		.veq_ena	= TRUE,		    .veq_start_f1	= 4, +		.veq_start_f2 = 4,	    	    .veq_len = 10, + + +		.vi_end_f1      = 21,           .vi_end_f2         	= 22, +		.nbr_end        = 539, + +		.burst_ena      = FALSE, + +		.filter_table = filter_table, +	}, +}; + +#define NUM_TV_MODES sizeof(tv_modes) / sizeof (tv_modes[0]) + +static void +intel_tv_dpms(struct drm_output *output, int mode) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; + +	switch(mode) { +	case DPMSModeOn: +		I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE); +		break; +	case DPMSModeStandby: +	case DPMSModeSuspend: +	case DPMSModeOff: +		I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE); +		break; +	} +} + +static void +intel_tv_save(struct drm_output *output) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_output *intel_output = output->driver_private; +	struct intel_tv_priv *tv_priv = intel_output->dev_priv; +	int i; + +	tv_priv->save_TV_H_CTL_1 = I915_READ(TV_H_CTL_1); +	tv_priv->save_TV_H_CTL_2 = I915_READ(TV_H_CTL_2); +	tv_priv->save_TV_H_CTL_3 = I915_READ(TV_H_CTL_3); +	tv_priv->save_TV_V_CTL_1 = I915_READ(TV_V_CTL_1); +	tv_priv->save_TV_V_CTL_2 = I915_READ(TV_V_CTL_2); +	tv_priv->save_TV_V_CTL_3 = I915_READ(TV_V_CTL_3); +	tv_priv->save_TV_V_CTL_4 = I915_READ(TV_V_CTL_4); +	tv_priv->save_TV_V_CTL_5 = I915_READ(TV_V_CTL_5); +	tv_priv->save_TV_V_CTL_6 = I915_READ(TV_V_CTL_6); +	tv_priv->save_TV_V_CTL_7 = I915_READ(TV_V_CTL_7); +	tv_priv->save_TV_SC_CTL_1 = I915_READ(TV_SC_CTL_1); +	tv_priv->save_TV_SC_CTL_2 = I915_READ(TV_SC_CTL_2); +	tv_priv->save_TV_SC_CTL_3 = I915_READ(TV_SC_CTL_3); + +	tv_priv->save_TV_CSC_Y = I915_READ(TV_CSC_Y); +	tv_priv->save_TV_CSC_Y2 = I915_READ(TV_CSC_Y2); +	tv_priv->save_TV_CSC_U = I915_READ(TV_CSC_U); +	tv_priv->save_TV_CSC_U2 = I915_READ(TV_CSC_U2); +	tv_priv->save_TV_CSC_V = I915_READ(TV_CSC_V); +	tv_priv->save_TV_CSC_V2 = I915_READ(TV_CSC_V2); +	tv_priv->save_TV_CLR_KNOBS = I915_READ(TV_CLR_KNOBS); +	tv_priv->save_TV_CLR_LEVEL = I915_READ(TV_CLR_LEVEL); +	tv_priv->save_TV_WIN_POS = I915_READ(TV_WIN_POS); +	tv_priv->save_TV_WIN_SIZE = I915_READ(TV_WIN_SIZE); +	tv_priv->save_TV_FILTER_CTL_1 = I915_READ(TV_FILTER_CTL_1); +	tv_priv->save_TV_FILTER_CTL_2 = I915_READ(TV_FILTER_CTL_2); +	tv_priv->save_TV_FILTER_CTL_3 = I915_READ(TV_FILTER_CTL_3); + +	for (i = 0; i < 60; i++) +		tv_priv->save_TV_H_LUMA[i] = I915_READ(TV_H_LUMA_0 + (i <<2)); +	for (i = 0; i < 60; i++) +		tv_priv->save_TV_H_CHROMA[i] = I915_READ(TV_H_CHROMA_0 + (i <<2)); +	for (i = 0; i < 43; i++) +		tv_priv->save_TV_V_LUMA[i] = I915_READ(TV_V_LUMA_0 + (i <<2)); +	for (i = 0; i < 43; i++) +		tv_priv->save_TV_V_CHROMA[i] = I915_READ(TV_V_CHROMA_0 + (i <<2)); + +	tv_priv->save_TV_DAC = I915_READ(TV_DAC); +	tv_priv->save_TV_CTL = I915_READ(TV_CTL); +} + +static void +intel_tv_restore(struct drm_output *output) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_output *intel_output = output->driver_private; +	struct intel_tv_priv *tv_priv = intel_output->dev_priv; +	struct drm_crtc *crtc = output->crtc; +	struct intel_crtc *intel_crtc; +	int i; + +	/* FIXME: No CRTC? */ +	if (!crtc) +		return; + +	intel_crtc = crtc->driver_private; +	I915_WRITE(TV_H_CTL_1, tv_priv->save_TV_H_CTL_1); +	I915_WRITE(TV_H_CTL_2, tv_priv->save_TV_H_CTL_2); +	I915_WRITE(TV_H_CTL_3, tv_priv->save_TV_H_CTL_3); +	I915_WRITE(TV_V_CTL_1, tv_priv->save_TV_V_CTL_1); +	I915_WRITE(TV_V_CTL_2, tv_priv->save_TV_V_CTL_2); +	I915_WRITE(TV_V_CTL_3, tv_priv->save_TV_V_CTL_3); +	I915_WRITE(TV_V_CTL_4, tv_priv->save_TV_V_CTL_4); +	I915_WRITE(TV_V_CTL_5, tv_priv->save_TV_V_CTL_5); +	I915_WRITE(TV_V_CTL_6, tv_priv->save_TV_V_CTL_6); +	I915_WRITE(TV_V_CTL_7, tv_priv->save_TV_V_CTL_7); +	I915_WRITE(TV_SC_CTL_1, tv_priv->save_TV_SC_CTL_1); +	I915_WRITE(TV_SC_CTL_2, tv_priv->save_TV_SC_CTL_2); +	I915_WRITE(TV_SC_CTL_3, tv_priv->save_TV_SC_CTL_3); + +	I915_WRITE(TV_CSC_Y, tv_priv->save_TV_CSC_Y); +	I915_WRITE(TV_CSC_Y2, tv_priv->save_TV_CSC_Y2); +	I915_WRITE(TV_CSC_U, tv_priv->save_TV_CSC_U); +	I915_WRITE(TV_CSC_U2, tv_priv->save_TV_CSC_U2); +	I915_WRITE(TV_CSC_V, tv_priv->save_TV_CSC_V); +	I915_WRITE(TV_CSC_V2, tv_priv->save_TV_CSC_V2); +	I915_WRITE(TV_CLR_KNOBS, tv_priv->save_TV_CLR_KNOBS); +	I915_WRITE(TV_CLR_LEVEL, tv_priv->save_TV_CLR_LEVEL); + +	{ +		int pipeconf_reg = (intel_crtc->pipe == 0) ? +			PIPEACONF : PIPEBCONF; +		int dspcntr_reg = (intel_crtc->plane == 0) ? +			DSPACNTR : DSPBCNTR; +		int pipeconf = I915_READ(pipeconf_reg); +		int dspcntr = I915_READ(dspcntr_reg); +		int dspbase_reg = (intel_crtc->plane == 0) ? +			DSPABASE : DSPBBASE; +		/* Pipe must be off here */ +		I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE); +		/* Flush the plane changes */ +		I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + +		if (!IS_I9XX(dev)) { +			/* Wait for vblank for the disable to take effect */ +			intel_wait_for_vblank(dev); +		} + +		I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE); +		/* Wait for vblank for the disable to take effect. */ +		intel_wait_for_vblank(dev); + +		/* Filter ctl must be set before TV_WIN_SIZE */ +		I915_WRITE(TV_FILTER_CTL_1, tv_priv->save_TV_FILTER_CTL_1); +		I915_WRITE(TV_FILTER_CTL_2, tv_priv->save_TV_FILTER_CTL_2); +		I915_WRITE(TV_FILTER_CTL_3, tv_priv->save_TV_FILTER_CTL_3); +		I915_WRITE(TV_WIN_POS, tv_priv->save_TV_WIN_POS); +		I915_WRITE(TV_WIN_SIZE, tv_priv->save_TV_WIN_SIZE); +		I915_WRITE(pipeconf_reg, pipeconf); +		I915_WRITE(dspcntr_reg, dspcntr); +		/* Flush the plane changes */ +		I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); +	} + +	for (i = 0; i < 60; i++) +		I915_WRITE(TV_H_LUMA_0 + (i <<2), tv_priv->save_TV_H_LUMA[i]); +	for (i = 0; i < 60; i++) +		I915_WRITE(TV_H_CHROMA_0 + (i <<2), tv_priv->save_TV_H_CHROMA[i]); +	for (i = 0; i < 43; i++) +		I915_WRITE(TV_V_LUMA_0 + (i <<2), tv_priv->save_TV_V_LUMA[i]); +	for (i = 0; i < 43; i++) +		I915_WRITE(TV_V_CHROMA_0 + (i <<2), tv_priv->save_TV_V_CHROMA[i]); + +	I915_WRITE(TV_DAC, tv_priv->save_TV_DAC); +	I915_WRITE(TV_CTL, tv_priv->save_TV_CTL); +} + +static const struct tv_mode * +intel_tv_mode_lookup (char *tv_format) +{ +	int i; +     +	for (i = 0; i < sizeof(tv_modes) / sizeof (tv_modes[0]); i++) { +		const struct tv_mode *tv_mode = &tv_modes[i]; + +		if (!strcmp(tv_format, tv_mode->name)) +			return tv_mode; +	} +	return NULL; +} + +static const struct tv_mode * +intel_tv_mode_find (struct drm_output *output) +{ +	struct intel_output *intel_output = output->driver_private; +	struct intel_tv_priv *tv_priv = intel_output->dev_priv; + +	return intel_tv_mode_lookup(tv_priv->tv_format); +} + +static enum drm_mode_status +intel_tv_mode_valid(struct drm_output *output, struct drm_display_mode *mode) +{ +	const struct tv_mode *tv_mode = intel_tv_mode_find(output); + +	/* Ensure TV refresh is close to desired refresh */ +	if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode)) < 1) +		return MODE_OK; +	return MODE_CLOCK_RANGE; +} + + +static bool +intel_tv_mode_fixup(struct drm_output *output, struct drm_display_mode *mode, +		    struct drm_display_mode *adjusted_mode) +{ +	struct drm_device *dev = output->dev; +	struct drm_mode_config *drm_config = &dev->mode_config; +	const struct tv_mode *tv_mode = intel_tv_mode_find (output); +	struct drm_output *other_output; + +	if (!tv_mode) +		return FALSE; +     +	/* FIXME: lock output list */ +	list_for_each_entry(other_output, &drm_config->output_list, head) { +		if (other_output != output && +		    other_output->crtc == output->crtc) +			return FALSE; +	} + +	adjusted_mode->clock = tv_mode->clock; +	return TRUE; +} + +static void +intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode, +		  struct drm_display_mode *adjusted_mode) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_crtc *crtc = output->crtc; +	struct intel_crtc *intel_crtc = crtc->driver_private; +	struct intel_output *intel_output = output->driver_private; +	struct intel_tv_priv *tv_priv = intel_output->dev_priv; +	const struct tv_mode *tv_mode = intel_tv_mode_find(output); +	u32 tv_ctl; +	u32 hctl1, hctl2, hctl3; +	u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7; +	u32 scctl1, scctl2, scctl3; +	int i, j; +	const struct video_levels *video_levels; +	const struct color_conversion *color_conversion; +	bool burst_ena; +     +	if (!tv_mode) +		return;	/* can't happen (mode_prepare prevents this) */ +     +	tv_ctl = 0; + +	switch (tv_priv->type) { +	default: +	case TV_TYPE_UNKNOWN: +	case TV_TYPE_COMPOSITE: +		tv_ctl |= TV_ENC_OUTPUT_COMPOSITE; +		video_levels = tv_mode->composite_levels; +		color_conversion = tv_mode->composite_color; +		burst_ena = tv_mode->burst_ena; +		break; +	case TV_TYPE_COMPONENT: +		tv_ctl |= TV_ENC_OUTPUT_COMPONENT; +		video_levels = &component_levels; +		if (tv_mode->burst_ena) +			color_conversion = &sdtv_csc_yprpb; +		else +			color_conversion = &hdtv_csc_yprpb; +		burst_ena = FALSE; +		break; +	case TV_TYPE_SVIDEO: +		tv_ctl |= TV_ENC_OUTPUT_SVIDEO; +		video_levels = tv_mode->svideo_levels; +		color_conversion = tv_mode->svideo_color; +		burst_ena = tv_mode->burst_ena; +		break; +	} +	hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) | +		(tv_mode->htotal << TV_HTOTAL_SHIFT); + +	hctl2 = (tv_mode->hburst_start << 16) | +		(tv_mode->hburst_len << TV_HBURST_LEN_SHIFT); + +	if (burst_ena) +		hctl2 |= TV_BURST_ENA; + +	hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) | +		(tv_mode->hblank_end << TV_HBLANK_END_SHIFT); + +	vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) | +		(tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) | +		(tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT); + +	vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) | +		(tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) | +		(tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT); + +	vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) | +		(tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) | +		(tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT); + +	if (tv_mode->veq_ena) +		vctl3 |= TV_EQUAL_ENA; + +	vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) | +		(tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT); + +	vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) | +		(tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT); + +	vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) | +		(tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT); + +	vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) | +		(tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT); + +	if (intel_crtc->pipe == 1) +		tv_ctl |= TV_ENC_PIPEB_SELECT; +	tv_ctl |= tv_mode->oversample; + +	if (tv_mode->progressive) +		tv_ctl |= TV_PROGRESSIVE; +	if (tv_mode->trilevel_sync) +		tv_ctl |= TV_TRILEVEL_SYNC; +	if (tv_mode->pal_burst) +		tv_ctl |= TV_PAL_BURST; +	scctl1 = 0; +	if (tv_mode->dda1_inc) +		scctl1 |= TV_SC_DDA1_EN; + +	if (tv_mode->dda2_inc) +		scctl1 |= TV_SC_DDA2_EN; + +	if (tv_mode->dda3_inc) +		scctl1 |= TV_SC_DDA3_EN; + +	scctl1 |= tv_mode->sc_reset; +	scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT; +	scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT; + +	scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT | +		tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT; + +	scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT | +		tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT; + +	/* Enable two fixes for the chips that need them. */ +	if (dev->pci_device < 0x2772) +		tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX; + +	I915_WRITE(TV_H_CTL_1, hctl1); +	I915_WRITE(TV_H_CTL_2, hctl2); +	I915_WRITE(TV_H_CTL_3, hctl3); +	I915_WRITE(TV_V_CTL_1, vctl1); +	I915_WRITE(TV_V_CTL_2, vctl2); +	I915_WRITE(TV_V_CTL_3, vctl3); +	I915_WRITE(TV_V_CTL_4, vctl4); +	I915_WRITE(TV_V_CTL_5, vctl5); +	I915_WRITE(TV_V_CTL_6, vctl6); +	I915_WRITE(TV_V_CTL_7, vctl7); +	I915_WRITE(TV_SC_CTL_1, scctl1); +	I915_WRITE(TV_SC_CTL_2, scctl2); +	I915_WRITE(TV_SC_CTL_3, scctl3); + +	I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) | +		   color_conversion->gy); +	I915_WRITE(TV_CSC_Y2,(color_conversion->by << 16) | +		   color_conversion->ay); +	I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) | +		   color_conversion->gu); +	I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) | +		   color_conversion->au); +	I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) | +		   color_conversion->gv); +	I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) | +		   color_conversion->av); + +	I915_WRITE(TV_CLR_KNOBS, 0x00606000); +	I915_WRITE(TV_CLR_LEVEL, ((video_levels->black << TV_BLACK_LEVEL_SHIFT) | +			      (video_levels->blank << TV_BLANK_LEVEL_SHIFT))); +	{ +		int pipeconf_reg = (intel_crtc->pipe == 0) ? +			PIPEACONF : PIPEBCONF; +		int dspcntr_reg = (intel_crtc->plane == 0) ? +			DSPACNTR : DSPBCNTR; +		int pipeconf = I915_READ(pipeconf_reg); +		int dspcntr = I915_READ(dspcntr_reg); +		int dspbase_reg = (intel_crtc->plane == 0) ? +			DSPABASE : DSPBBASE; +		int xpos = 0x0, ypos = 0x0; +		unsigned int xsize, ysize; +		/* Pipe must be off here */ +		I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE); +		/* Flush the plane changes */ +		I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + +		/* Wait for vblank for the disable to take effect */ +		if (!IS_I9XX(dev)) +			intel_wait_for_vblank(dev); + +		I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE); +		/* Wait for vblank for the disable to take effect. */ +		intel_wait_for_vblank(dev); + +		/* Filter ctl must be set before TV_WIN_SIZE */ +		I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);  +		xsize = tv_mode->hblank_start - tv_mode->hblank_end; +		if (tv_mode->progressive) +			ysize = tv_mode->nbr_end + 1; +		else +			ysize = 2*tv_mode->nbr_end + 1; + +		xpos += tv_priv->margin[TV_MARGIN_LEFT]; +		ypos += tv_priv->margin[TV_MARGIN_TOP]; +		xsize -= (tv_priv->margin[TV_MARGIN_LEFT] +  +			  tv_priv->margin[TV_MARGIN_RIGHT]); +		ysize -= (tv_priv->margin[TV_MARGIN_TOP] +  +			  tv_priv->margin[TV_MARGIN_BOTTOM]); +		I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos); +		I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize); + +		I915_WRITE(pipeconf_reg, pipeconf); +		I915_WRITE(dspcntr_reg, dspcntr); +		/* Flush the plane changes */ +		I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); +	} 	 + +	j = 0; +	for (i = 0; i < 60; i++) +		I915_WRITE(TV_H_LUMA_0 + (i<<2), tv_mode->filter_table[j++]); +	for (i = 0; i < 60; i++) +		I915_WRITE(TV_H_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]); +	for (i = 0; i < 43; i++) +		I915_WRITE(TV_V_LUMA_0 + (i<<2), tv_mode->filter_table[j++]); +	for (i = 0; i < 43; i++) +		I915_WRITE(TV_V_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]); +	I915_WRITE(TV_DAC, 0); +	I915_WRITE(TV_CTL, tv_ctl); +} + +static const struct drm_display_mode reported_modes[] = { +	{ +		.name = "NTSC 480i", +		.clock = 107520, +		.hdisplay = 1280, +		.hsync_start = 1368, +		.hsync_end = 1496, +		.htotal = 1712, + +		.vdisplay = 1024, +		.vsync_start = 1027, +		.vsync_end = 1034, +		.vtotal = 1104, +		.type = DRM_MODE_TYPE_DRIVER, +	}, +}; + +/** + * Detects TV presence by checking for load. + * + * Requires that the current pipe's DPLL is active. + + * \return TRUE if TV is connected. + * \return FALSE if TV is disconnected. + */ +static int +intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output) +{ +	struct drm_device *dev = output->dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct intel_output *intel_output = output->driver_private; +	u32 tv_ctl, save_tv_ctl; +	u32 tv_dac, save_tv_dac; +	int type = TV_TYPE_UNKNOWN; + +	tv_dac = I915_READ(TV_DAC); +	/* +	 * Detect TV by polling) +	 */ +	if (intel_output->load_detect_temp) { +		/* TV not currently running, prod it with destructive detect */ +		save_tv_dac = tv_dac; +		tv_ctl = I915_READ(TV_CTL); +		save_tv_ctl = tv_ctl; +		tv_ctl &= ~TV_ENC_ENABLE; +		tv_ctl &= ~TV_TEST_MODE_MASK; +		tv_ctl |= TV_TEST_MODE_MONITOR_DETECT; +		tv_dac &= ~TVDAC_SENSE_MASK; +		tv_dac |= (TVDAC_STATE_CHG_EN | +			   TVDAC_A_SENSE_CTL | +			   TVDAC_B_SENSE_CTL | +			   TVDAC_C_SENSE_CTL | +			   DAC_CTL_OVERRIDE | +			   DAC_A_0_7_V | +			   DAC_B_0_7_V | +			   DAC_C_0_7_V); +		I915_WRITE(TV_CTL, tv_ctl); +		I915_WRITE(TV_DAC, tv_dac); +		intel_wait_for_vblank(dev); +		tv_dac = I915_READ(TV_DAC); +		I915_WRITE(TV_DAC, save_tv_dac); +		I915_WRITE(TV_CTL, save_tv_ctl); +	} +	/* +	 *  A B C +	 *  0 1 1 Composite +	 *  1 0 X svideo +	 *  0 0 0 Component +	 */ +	if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) { +		DRM_DEBUG("Detected Composite TV connection\n"); +		type = TV_TYPE_COMPOSITE; +	} else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) { +		DRM_DEBUG("Detected S-Video TV connection\n"); +		type = TV_TYPE_SVIDEO; +	} else if ((tv_dac & TVDAC_SENSE_MASK) == 0) { +		DRM_DEBUG("Detected Component TV connection\n"); +		type = TV_TYPE_COMPONENT; +	} else { +		DRM_DEBUG("No TV connection detected\n"); +		type = TV_TYPE_NONE; +	} + +	return type; +} + +static int +intel_tv_format_configure_property (struct drm_output *output); + +/** + * Detect the TV connection. + * + * Currently this always returns OUTPUT_STATUS_UNKNOWN, as we need to be sure + * we have a pipe programmed in order to probe the TV. + */ +static enum drm_output_status +intel_tv_detect(struct drm_output *output) +{ +	struct drm_crtc *crtc; +	struct drm_display_mode mode; +	struct intel_output *intel_output = output->driver_private; +	struct intel_tv_priv *tv_priv = intel_output->dev_priv; +	int dpms_mode; +	int type = tv_priv->type; + +	mode = reported_modes[0]; +	drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V); +#if 0 +	/* FIXME: pipe allocation for load detection */ +	crtc = i830GetLoadDetectPipe (output, &mode, &dpms_mode); +	if (crtc) { +		type = intel_tv_detect_type(crtc, output); +		i830ReleaseLoadDetectPipe (output, dpms_mode); +	} +#endif +	if (type != tv_priv->type) { +		tv_priv->type = type; +		intel_tv_format_configure_property (output); +	} +	 +	switch (type) { +	case TV_TYPE_NONE: +		return output_status_disconnected; +	case TV_TYPE_UNKNOWN: +		return output_status_unknown; +	default: +		return output_status_connected; +	} +} + +static struct input_res { +	char *name; +	int w, h;	 +} input_res_table[] =  +{ +	{"640x480", 640, 480}, +	{"800x600", 800, 600}, +	{"1024x768", 1024, 768}, +	{"1280x1024", 1280, 1024}, +	{"848x480", 848, 480}, +	{"1280x720", 1280, 720}, +	{"1920x1080", 1920, 1080}, +}; + +/** + * Stub get_modes function. + * + * This should probably return a set of fixed modes, unless we can figure out + * how to probe modes off of TV connections. + */ + +static int +intel_tv_get_modes(struct drm_output *output) +{ +	struct drm_display_mode *mode_ptr; +	const struct tv_mode *tv_mode = intel_tv_mode_find(output); +	int j; + +	for (j = 0; j < sizeof(input_res_table) / sizeof(input_res_table[0]); +	     j++) { +		struct input_res *input = &input_res_table[j]; +		unsigned int hactive_s = input->w; +		unsigned int vactive_s = input->h; +	 +		if (tv_mode->max_srcw && input->w > tv_mode->max_srcw) +			continue; + +		if (input->w > 1024 && (!tv_mode->progressive  +					&& !tv_mode->component_only)) +			continue; + +		mode_ptr = drm_calloc(1, sizeof(struct drm_display_mode), +				      DRM_MEM_DRIVER); +		strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN); + +		mode_ptr->hdisplay = hactive_s; +		mode_ptr->hsync_start = hactive_s + 1; +		mode_ptr->hsync_end = hactive_s + 64; +		if (mode_ptr->hsync_end <= mode_ptr->hsync_start) +			mode_ptr->hsync_end = mode_ptr->hsync_start + 1; +		mode_ptr->htotal = hactive_s + 96; + +		mode_ptr->vdisplay = vactive_s; +		mode_ptr->vsync_start = vactive_s + 1; +		mode_ptr->vsync_end = vactive_s + 32; +		if (mode_ptr->vsync_end <= mode_ptr->vsync_start) +			mode_ptr->vsync_end = mode_ptr->vsync_start  + 1; +		mode_ptr->vtotal = vactive_s + 33; + +		mode_ptr->clock = (int) (tv_mode->refresh *  +					 mode_ptr->vtotal *  +					 mode_ptr->htotal / 1000) / 1000; +	 +		mode_ptr->type = DRM_MODE_TYPE_DRIVER; +		drm_mode_probed_add(output, mode_ptr); +	}  + +	return 0; +} + +static void +intel_tv_destroy (struct drm_output *output) +{ +	if (output->driver_private) +		drm_free(output->driver_private, sizeof(struct intel_tv_priv), +			 DRM_MEM_DRIVER); +} + +static bool +intel_tv_format_set_property(struct drm_output *output, +			     struct drm_property *prop, uint64_t val) +{ +#if 0 +	struct intel_output *intel_output = output->driver_private; +	struct intel_tv_priv *tv_priv = intel_output->dev_priv; +	const struct tv_mode *tv_mode = +		intel_tv_mode_lookup(tv_priv->tv_format); +	int			    err; + +	if (!tv_mode) +		tv_mode = &tv_modes[0]; +	err = RRChangeOutputProperty (output->randr_output, tv_format_atom, +				      XA_ATOM, 32, PropModeReplace, 1, +				      &tv_format_name_atoms[tv_mode - tv_modes], +				      FALSE, TRUE); +	return err == Success; +#endif +	return 0; +} + +     +/** + * Configure the TV_FORMAT property to list only supported formats + * + * Unless the connector is component, list only the formats supported by + * svideo and composite + */ + +static int +intel_tv_format_configure_property(struct drm_output *output) +{ +#if 0 +	struct intel_output *intel_output = output->driver_private; +	struct intel_tv_priv *tv_priv = intel_output->dev_priv; +	Atom		    current_atoms[NUM_TV_MODES]; +	int			    num_atoms = 0; +	int			    i; +     +	if (!output->randr_output) +		return Success; + +	for (i = 0; i < NUM_TV_MODES; i++) +		if (!tv_modes[i].component_only || +		    tv_priv->type == TV_TYPE_COMPONENT) +			current_atoms[num_atoms++] = tv_format_name_atoms[i]; +     +	return RRConfigureOutputProperty(output->randr_output, tv_format_atom, +					 TRUE, FALSE, FALSE,  +					 num_atoms, (INT32 *) current_atoms); +#endif +	return 0; +} + +static void +intel_tv_create_resources(struct drm_output *output) +{ +	struct drm_device *dev = output->dev; +	struct intel_output *intel_output = output->driver_private; +	struct intel_tv_priv *tv_priv = intel_output->dev_priv; +	int i, err; + +#if 0 +	/* Set up the tv_format property, which takes effect on mode set +	 * and accepts strings that match exactly +	 */ +	tv_format_atom = MakeAtom(TV_FORMAT_NAME, sizeof(TV_FORMAT_NAME) - 1, +				  TRUE); + +	for (i = 0; i < NUM_TV_MODES; i++) +		tv_format_name_atoms[i] = MakeAtom (tv_modes[i].name, +						    strlen (tv_modes[i].name), +						    TRUE); + +	err = intel_tv_format_configure_property (output); + +	if (err != 0) { +		xf86DrvMsg(dev->scrnIndex, X_ERROR, +			   "RRConfigureOutputProperty error, %d\n", err); +	} + +	/* Set the current value of the tv_format property */ +	if (!intel_tv_format_set_property (output)) +		xf86DrvMsg(dev->scrnIndex, X_ERROR, +			   "RRChangeOutputProperty error, %d\n", err); + +	for (i = 0; i < 4; i++) +	{ +		INT32	range[2]; +		margin_atoms[i] = MakeAtom(margin_names[i], strlen (margin_names[i]), +					   TRUE); + +		range[0] = 0; +		range[1] = 100; +		err = RRConfigureOutputProperty(output->randr_output, margin_atoms[i], +						TRUE, TRUE, FALSE, 2, range); +     +		if (err != 0) +			xf86DrvMsg(dev->scrnIndex, X_ERROR, +				   "RRConfigureOutputProperty error, %d\n", err); + +		err = RRChangeOutputProperty(output->randr_output, margin_atoms[i], +					     XA_INTEGER, 32, PropModeReplace, +					     1, &tv_priv->margin[i], +					     FALSE, TRUE); +		if (err != 0) +			xf86DrvMsg(dev->scrnIndex, X_ERROR, +				   "RRChangeOutputProperty error, %d\n", err); +	} +#endif +} + +static bool +intel_tv_set_property(struct drm_output *output, struct drm_property *property, +		      uint64_t val) +{ +	struct drm_device *dev = output->dev; +	int ret = 0; +     +	if (property == dev->mode_config.tv_left_margin_property || +	    property == dev->mode_config.tv_right_margin_property || +	    property == dev->mode_config.tv_top_margin_property || +	    property == dev->mode_config.tv_bottom_margin_property) { +		ret = drm_output_property_set_value(output, property, val); +	} else { +		/* TV mode handling here */ +	} + +	return ret; +} + +static const struct drm_output_funcs intel_tv_output_funcs = { +	.dpms = intel_tv_dpms, +	.save = intel_tv_save, +	.restore = intel_tv_restore, +	.mode_valid = intel_tv_mode_valid, +	.mode_fixup = intel_tv_mode_fixup, +	.prepare = intel_output_prepare, +	.mode_set = intel_tv_mode_set, +	.commit = intel_output_commit, +	.detect = intel_tv_detect, +	.get_modes = intel_tv_get_modes, +	.cleanup = intel_tv_destroy, +	.set_property = intel_tv_set_property, +}; + +void +intel_tv_init(struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_output *output; +	struct intel_output *intel_output; +	struct intel_tv_priv *tv_priv; +	u32 tv_dac_on, tv_dac_off, save_tv_dac; + +	/* FIXME: better TV detection and/or quirks */ +#if 0 +	if (tv_priv->quirk_flag & QUIRK_IGNORE_TV) +		return; +#endif +	if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED) +		return; + +	/* +	 * Sanity check the TV output by checking to see if the +	 * DAC register holds a value +	 */ +	save_tv_dac = I915_READ(TV_DAC); + +	I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN); +	tv_dac_on = I915_READ(TV_DAC); + +	I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN); +	tv_dac_off = I915_READ(TV_DAC); + +	I915_WRITE(TV_DAC, save_tv_dac); + +	/* +	 * If the register does not hold the state change enable +	 * bit, (either as a 0 or a 1), assume it doesn't really +	 * exist +	 */ +	if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 ||  +	    (tv_dac_off & TVDAC_STATE_CHG_EN) != 0) +		return; + +	output = drm_output_create(dev, &intel_tv_output_funcs, +				   DRM_MODE_OUTPUT_TVDAC); + +	if (!output) +		return; + +	intel_output = drm_calloc(1, sizeof(struct intel_output) + +				  sizeof(struct intel_tv_priv), DRM_MEM_DRIVER); +	if (!intel_output) { +		drm_output_destroy(output); +		return; +	} + +	tv_priv = (struct intel_tv_priv *)(intel_output + 1); +	intel_output->type = INTEL_OUTPUT_TVOUT; +	output->possible_crtcs = ((1 << 0) | (1 << 1)); +	output->possible_clones = (1 << INTEL_OUTPUT_TVOUT); +	intel_output->dev_priv = tv_priv; +	tv_priv->type = TV_TYPE_UNKNOWN; + +	tv_priv->tv_format = NULL; +     +	/* BIOS margin values */ +	tv_priv->margin[TV_MARGIN_LEFT] = 54; +	tv_priv->margin[TV_MARGIN_TOP] = 36; +	tv_priv->margin[TV_MARGIN_RIGHT] = 46; +	tv_priv->margin[TV_MARGIN_BOTTOM] = 37; +     +	if (!tv_priv->tv_format) +		tv_priv->tv_format = kstrdup(tv_modes[0].name, GFP_KERNEL); +     +	output->driver_private = intel_output; +	output->interlace_allowed = FALSE; +	output->doublescan_allowed = FALSE; +} diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c new file mode 100644 index 00000000..5dff1898 --- /dev/null +++ b/linux-core/radeon_buffer.c @@ -0,0 +1,263 @@ +/************************************************************************** + *  + * Copyright 2007 Dave Airlie + * All Rights Reserved. + *  + * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + *  + **************************************************************************/ +/* + * Authors: Dave Airlie <airlied@linux.ie> + */ + +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +struct drm_ttm_backend *radeon_create_ttm_backend_entry(struct drm_device * dev) +{ +	drm_radeon_private_t *dev_priv = dev->dev_private; + +	if(dev_priv->flags & RADEON_IS_AGP) +		return drm_agp_init_ttm(dev); +	else +		return ati_pcigart_init_ttm(dev, &dev_priv->gart_info, radeon_gart_flush); +} + +int radeon_fence_types(struct drm_buffer_object *bo, uint32_t * class, uint32_t * type) +{ +	*class = 0; +	if (bo->mem.flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) +		*type = 3; +	else +		*type = 1; +	return 0; +} + +int radeon_invalidate_caches(struct drm_device * dev, uint64_t flags) +{ +	drm_radeon_private_t *dev_priv = dev->dev_private; +	RING_LOCALS; + +	BEGIN_RING(4); +	RADEON_FLUSH_CACHE(); +	RADEON_FLUSH_ZCACHE(); +	ADVANCE_RING(); +	return 0; +} + +uint64_t radeon_evict_flags(struct drm_buffer_object *bo) +{ +	switch (bo->mem.mem_type) { +	case DRM_BO_MEM_LOCAL: +	case DRM_BO_MEM_TT: +		return DRM_BO_FLAG_MEM_LOCAL; +	case DRM_BO_MEM_VRAM: +		if (bo->mem.num_pages > 128) +			return DRM_BO_MEM_TT; +		else +			return DRM_BO_MEM_LOCAL; +	default: +		return DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_CACHED; +	} +} + +int radeon_init_mem_type(struct drm_device * dev, uint32_t type, +			 struct drm_mem_type_manager * man) +{ +	drm_radeon_private_t *dev_priv = dev->dev_private; + +	switch (type) { +	case DRM_BO_MEM_LOCAL: +		man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | +		    _DRM_FLAG_MEMTYPE_CACHED; +		man->drm_bus_maptype = 0; +		break; +	case DRM_BO_MEM_VRAM: +		man->flags =  _DRM_FLAG_MEMTYPE_FIXED | _DRM_FLAG_MEMTYPE_MAPPABLE | _DRM_FLAG_NEEDS_IOREMAP; +		man->io_addr = NULL; +		man->drm_bus_maptype = _DRM_FRAME_BUFFER; +		man->io_offset = drm_get_resource_start(dev, 0); +		man->io_size = drm_get_resource_len(dev, 0); +		break; +	case DRM_BO_MEM_TT: +		if (dev_priv->flags & RADEON_IS_AGP) { +			if (!(drm_core_has_AGP(dev) && dev->agp)) { +				DRM_ERROR("AGP is not enabled for memory type %u\n", +					  (unsigned)type); +				return -EINVAL; +			} +			man->io_offset = dev->agp->agp_info.aper_base; +			man->io_size = dev->agp->agp_info.aper_size * 1024 * 1024; +			man->io_addr = NULL; +			man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | +				_DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_NEEDS_IOREMAP; +			man->drm_bus_maptype = _DRM_AGP; +		} else { +			man->io_offset = dev_priv->gart_vm_start; +			man->io_size = dev_priv->gart_size; +			man->io_addr = NULL; +			man->flags = _DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_MEMTYPE_MAPPABLE | _DRM_FLAG_MEMTYPE_CMA; +			man->drm_bus_maptype = _DRM_SCATTER_GATHER; +		} +		break; +	default: +		DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); +		return -EINVAL; +	} +	return 0; +} + +static void radeon_emit_copy_blit(struct drm_device * dev, +				  uint32_t src_offset, +				  uint32_t dst_offset, +				  uint32_t pages, int direction) +{ +	uint32_t cur_pages; +	uint32_t stride = PAGE_SIZE; +	drm_radeon_private_t *dev_priv = dev->dev_private; +	uint32_t format, height; +	RING_LOCALS; + +	if (!dev_priv) +		return; + +	/* 32-bit copy format */ +	format = RADEON_COLOR_FORMAT_ARGB8888; + +	/* radeon limited to 16k stride */ +	stride &= 0x3fff; +	while(pages > 0) { +		cur_pages = pages; +		if (cur_pages > 2048) +			cur_pages = 2048; +		pages -= cur_pages; + +		/* needs verification */ +		BEGIN_RING(7);		 +		OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5)); +		OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL | +			 RADEON_GMC_DST_PITCH_OFFSET_CNTL | +			 RADEON_GMC_BRUSH_NONE | +			 (format << 8) | +			 RADEON_GMC_SRC_DATATYPE_COLOR | +			 RADEON_ROP3_S | +			 RADEON_DP_SRC_SOURCE_MEMORY | +			 RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS); +		if (direction) { +			OUT_RING((stride << 22) | (src_offset >> 10)); +			OUT_RING((stride << 22) | (dst_offset >> 10)); +		} else { +			OUT_RING((stride << 22) | (dst_offset >> 10)); +			OUT_RING((stride << 22) | (src_offset >> 10)); +		} +		OUT_RING(0); +		OUT_RING(pages); /* x - y */ +		OUT_RING((stride << 16) | cur_pages); +		ADVANCE_RING(); +	} + +	BEGIN_RING(2); +	RADEON_WAIT_UNTIL_2D_IDLE(); +	ADVANCE_RING(); + +	return; +} + +static int radeon_move_blit(struct drm_buffer_object * bo, +			    int evict, int no_wait, struct drm_bo_mem_reg *new_mem) +{ +	struct drm_bo_mem_reg *old_mem = &bo->mem; +	int dir = 0; + +	if ((old_mem->mem_type == new_mem->mem_type) && +	    (new_mem->mm_node->start < +	     old_mem->mm_node->start + old_mem->mm_node->size)) { +		dir = 1; +	} + +	radeon_emit_copy_blit(bo->dev, +			      old_mem->mm_node->start << PAGE_SHIFT, +			      new_mem->mm_node->start << PAGE_SHIFT, +			      new_mem->num_pages, dir); + +	 +	return drm_bo_move_accel_cleanup(bo, evict, no_wait, 0, +					 DRM_FENCE_TYPE_EXE | +					 DRM_RADEON_FENCE_TYPE_RW, +					 DRM_RADEON_FENCE_FLAG_FLUSHED, new_mem); +} + +static int radeon_move_flip(struct drm_buffer_object * bo, +			    int evict, int no_wait, struct drm_bo_mem_reg * new_mem) +{ +	struct drm_device *dev = bo->dev; +	struct drm_bo_mem_reg tmp_mem; +	int ret; + +	tmp_mem = *new_mem; +	tmp_mem.mm_node = NULL; +	tmp_mem.flags = DRM_BO_FLAG_MEM_TT | +	    DRM_BO_FLAG_CACHED | DRM_BO_FLAG_FORCE_CACHING; + +	ret = drm_bo_mem_space(bo, &tmp_mem, no_wait); +	if (ret) +		return ret; + +	ret = drm_ttm_bind(bo->ttm, &tmp_mem); +	if (ret) +		goto out_cleanup; + +	ret = radeon_move_blit(bo, 1, no_wait, &tmp_mem); +	if (ret) +		goto out_cleanup; + +	ret = drm_bo_move_ttm(bo, evict, no_wait, new_mem); +out_cleanup: +	if (tmp_mem.mm_node) { +		mutex_lock(&dev->struct_mutex); +		if (tmp_mem.mm_node != bo->pinned_node) +			drm_mm_put_block(tmp_mem.mm_node); +		tmp_mem.mm_node = NULL; +		mutex_unlock(&dev->struct_mutex); +	} +	return ret; +} + +int radeon_move(struct drm_buffer_object * bo, +		int evict, int no_wait, struct drm_bo_mem_reg * new_mem) +{ +	struct drm_bo_mem_reg *old_mem = &bo->mem; + +	DRM_DEBUG("\n"); +	if (old_mem->mem_type == DRM_BO_MEM_LOCAL) { +		return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); +	} else if (new_mem->mem_type == DRM_BO_MEM_LOCAL) { +		if (radeon_move_flip(bo, evict, no_wait, new_mem)) +			return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); +	} else { +		if (radeon_move_blit(bo, evict, no_wait, new_mem)) +			return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); +	} +	return 0; +} + diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index f0f3320e..355e4c22 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -56,6 +56,38 @@ static struct pci_device_id pciidlist[] = {  	radeon_PCI_IDS  }; + +#ifdef RADEON_HAVE_FENCE +static struct drm_fence_driver radeon_fence_driver = { +	.num_classes = 1, +	.wrap_diff = (1 << 30), +	.flush_diff = (1 << 29), +	.sequence_mask = 0xffffffffU, +	.lazy_capable = 1, +	.emit = radeon_fence_emit_sequence, +	.poke_flush = radeon_poke_flush, +	.has_irq = radeon_fence_has_irq, +}; +#endif +#ifdef RADEON_HAVE_BUFFER + +static uint32_t radeon_mem_prios[] = {DRM_BO_MEM_VRAM, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL}; +static uint32_t radeon_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_VRAM, DRM_BO_MEM_LOCAL}; + +static struct drm_bo_driver radeon_bo_driver = { +	.mem_type_prio = radeon_mem_prios, +	.mem_busy_prio = radeon_busy_prios, +	.num_mem_type_prio = sizeof(radeon_mem_prios)/sizeof(uint32_t), +	.num_mem_busy_prio = sizeof(radeon_busy_prios)/sizeof(uint32_t), +	.create_ttm_backend_entry = radeon_create_ttm_backend_entry, +	.fence_type = radeon_fence_types, +	.invalidate_caches = radeon_invalidate_caches, +	.init_mem_type = radeon_init_mem_type, +	.evict_flags = radeon_evict_flags, +	.move = radeon_move, +}; +#endif +  static int probe(struct pci_dev *pdev, const struct pci_device_id *ent);  static struct drm_driver driver = {  	.driver_features = @@ -101,6 +133,13 @@ static struct drm_driver driver = {  		.remove = __devexit_p(drm_cleanup_pci),  	}, +#ifdef RADEON_HAVE_FENCE +	.fence_driver = &radeon_fence_driver, +#endif +#ifdef RADEON_HAVE_BUFFER +	.bo_driver = &radeon_bo_driver, +#endif +  	.name = DRIVER_NAME,  	.desc = DRIVER_DESC,  	.date = DRIVER_DATE, diff --git a/linux-core/radeon_fence.c b/linux-core/radeon_fence.c new file mode 100644 index 00000000..682f0bee --- /dev/null +++ b/linux-core/radeon_fence.c @@ -0,0 +1,125 @@ +/************************************************************************** + *  + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA + * All Rights Reserved. + *  + * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + *  + **************************************************************************/ +/* + * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com> + */ + +#include "drmP.h" +#include "drm.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +/* + * Implements an intel sync flush operation. + */ + +static void radeon_perform_flush(struct drm_device * dev) +{ +	drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; +	struct drm_fence_manager *fm = &dev->fm; +	struct drm_fence_class_manager *fc = &dev->fm.fence_class[0]; +	struct drm_fence_driver *driver = dev->driver->fence_driver; +	uint32_t pending_flush_types = 0; +	uint32_t sequence; + +	if (!dev_priv) +		return; + +	pending_flush_types = fc->pending_flush | +		((fc->pending_exe_flush) ? DRM_FENCE_TYPE_EXE : 0); + +	if (pending_flush_types) { +		sequence = READ_BREADCRUMB(dev_priv); +					      +		drm_fence_handler(dev, 0, sequence, pending_flush_types, 0); +	} + +	return; +} + +void radeon_poke_flush(struct drm_device * dev, uint32_t class) +{ +	struct drm_fence_manager *fm = &dev->fm; +	unsigned long flags; + +	if (class != 0) +		return; + +	write_lock_irqsave(&fm->lock, flags); +	radeon_perform_flush(dev); +	write_unlock_irqrestore(&fm->lock, flags); +} + +int radeon_fence_emit_sequence(struct drm_device *dev, uint32_t class, +			       uint32_t flags, uint32_t *sequence, +			       uint32_t *native_type) +{ +	drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; +	RING_LOCALS; + +	if (!dev_priv) +		return -EINVAL; + +	*native_type = DRM_FENCE_TYPE_EXE; +	if (flags & DRM_RADEON_FENCE_FLAG_FLUSHED) { +		*native_type |= DRM_RADEON_FENCE_TYPE_RW; +		 +		BEGIN_RING(4); +		 +		RADEON_FLUSH_CACHE(); +		RADEON_FLUSH_ZCACHE(); +		ADVANCE_RING(); +	} + +	radeon_emit_irq(dev); +	*sequence = (uint32_t) dev_priv->counter; + + +	return 0; +} + +void radeon_fence_handler(struct drm_device * dev) +{ +	struct drm_fence_manager *fm = &dev->fm; + +	write_lock(&fm->lock); +	radeon_perform_flush(dev); +	write_unlock(&fm->lock); +} + +int radeon_fence_has_irq(struct drm_device *dev, uint32_t class, uint32_t flags) +{ +	/* +	 * We have an irq that tells us when we have a new breadcrumb. +	 */ + +	if (class == 0 && flags == DRM_FENCE_TYPE_EXE) +		return 1; + +	return 0; +} diff --git a/linux-core/radeon_ms.h b/linux-core/radeon_ms.h new file mode 120000 index 00000000..da340c5d --- /dev/null +++ b/linux-core/radeon_ms.h @@ -0,0 +1 @@ +../shared-core/radeon_ms.h
\ No newline at end of file diff --git a/linux-core/radeon_ms_bo.c b/linux-core/radeon_ms_bo.c new file mode 120000 index 00000000..d05df59f --- /dev/null +++ b/linux-core/radeon_ms_bo.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_bo.c
\ No newline at end of file diff --git a/linux-core/radeon_ms_bus.c b/linux-core/radeon_ms_bus.c new file mode 120000 index 00000000..50f649d0 --- /dev/null +++ b/linux-core/radeon_ms_bus.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_bus.c
\ No newline at end of file diff --git a/linux-core/radeon_ms_combios.c b/linux-core/radeon_ms_combios.c new file mode 120000 index 00000000..d7b99958 --- /dev/null +++ b/linux-core/radeon_ms_combios.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_combios.c
\ No newline at end of file diff --git a/linux-core/radeon_ms_combios.h b/linux-core/radeon_ms_combios.h new file mode 120000 index 00000000..5b19c708 --- /dev/null +++ b/linux-core/radeon_ms_combios.h @@ -0,0 +1 @@ +../shared-core/radeon_ms_combios.h
\ No newline at end of file diff --git a/linux-core/radeon_ms_compat.c b/linux-core/radeon_ms_compat.c new file mode 100644 index 00000000..6efdc786 --- /dev/null +++ b/linux-core/radeon_ms_compat.c @@ -0,0 +1,67 @@ +/* + * Copyright 2007 Dave Airlie + * Copyright 2007 Alex Deucher + * Copyright 2007 Michel Dänzer + * Copyright 2007 Roland Scheidegger + * Copyright 2007 Vladimir Dergachev + * Copyright 2007 Nicolai Haehnle + * Copyright 2007 Aapo Tahkola + * Copyright 2007 Ben Skeggs + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: + *    Jerome Glisse <glisse@freedesktop.org> + */ +#include "drmP.h" +#include "drm.h" +#include "radeon_ms.h" + +/** + * Called whenever a 32-bit process running under a 64-bit kernel + * performs an ioctl on /dev/dri/card<n>. + + * \param filp file pointer. + * \param cmd command. + * \param arg user argument. + * \return zero on success or negative number on failure. + */ +long radeon_ms_compat_ioctl(struct file *filp, unsigned int cmd, +			    unsigned long arg) +{ +	unsigned int nr = DRM_IOCTL_NR(cmd); +	drm_ioctl_compat_t *fn = NULL; +	int ret; + +	if (nr < DRM_COMMAND_BASE) +		return drm_compat_ioctl(filp, cmd, arg); + +	lock_kernel(); +	if (fn != NULL) +		ret = (*fn)(filp, cmd, arg); +	else +		ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg); +	unlock_kernel(); + +	return ret; +} diff --git a/linux-core/radeon_ms_cp.c b/linux-core/radeon_ms_cp.c new file mode 120000 index 00000000..6aee3e6e --- /dev/null +++ b/linux-core/radeon_ms_cp.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_cp.c
\ No newline at end of file diff --git a/linux-core/radeon_ms_cp_mc.c b/linux-core/radeon_ms_cp_mc.c new file mode 120000 index 00000000..0ae1a647 --- /dev/null +++ b/linux-core/radeon_ms_cp_mc.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_cp_mc.c
\ No newline at end of file diff --git a/linux-core/radeon_ms_crtc.c b/linux-core/radeon_ms_crtc.c new file mode 120000 index 00000000..31f11447 --- /dev/null +++ b/linux-core/radeon_ms_crtc.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_crtc.c
\ No newline at end of file diff --git a/linux-core/radeon_ms_dac.c b/linux-core/radeon_ms_dac.c new file mode 120000 index 00000000..cb523cfb --- /dev/null +++ b/linux-core/radeon_ms_dac.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_dac.c
\ No newline at end of file diff --git a/linux-core/radeon_ms_drm.c b/linux-core/radeon_ms_drm.c new file mode 120000 index 00000000..8bbf19a5 --- /dev/null +++ b/linux-core/radeon_ms_drm.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_drm.c
\ No newline at end of file diff --git a/linux-core/radeon_ms_drm.h b/linux-core/radeon_ms_drm.h new file mode 120000 index 00000000..5d9d7319 --- /dev/null +++ b/linux-core/radeon_ms_drm.h @@ -0,0 +1 @@ +../shared-core/radeon_ms_drm.h
\ No newline at end of file diff --git a/linux-core/radeon_ms_drv.c b/linux-core/radeon_ms_drv.c new file mode 100644 index 00000000..d7b0eecc --- /dev/null +++ b/linux-core/radeon_ms_drv.c @@ -0,0 +1,143 @@ +/* + * Copyright 2007 Jerome Glisse. + * All Rights Reserved. + * + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: + *    Jerome Glisse <glisse@freedesktop.org> + */ +#include "drm_pciids.h" +#include "radeon_ms.h" + +extern struct drm_fence_driver radeon_ms_fence_driver; +extern struct drm_bo_driver radeon_ms_bo_driver; +extern struct drm_ioctl_desc radeon_ms_ioctls[]; +extern int radeon_ms_num_ioctls; + +static int radeon_ms_driver_dri_library_name(struct drm_device * dev, +					     char * buf); +static int radeon_ms_driver_probe(struct pci_dev *pdev, +				  const struct pci_device_id *ent); + +static struct pci_device_id pciidlist[] = { +	radeon_ms_PCI_IDS +}; + +static struct drm_driver driver = { +	.load = radeon_ms_driver_load, +	.firstopen = NULL, +	.open = radeon_ms_driver_open, +	.preclose = NULL, +	.postclose = NULL, +	.lastclose = radeon_ms_driver_lastclose, +	.unload = radeon_ms_driver_unload, +	.dma_ioctl = radeon_ms_driver_dma_ioctl, +	.dma_ready = NULL, +	.dma_quiescent = NULL, +	.context_ctor = NULL, +	.context_dtor = NULL, +	.kernel_context_switch = NULL, +	.kernel_context_switch_unlock = NULL, +	.dri_library_name = radeon_ms_driver_dri_library_name, +	.device_is_agp = NULL, +	.irq_handler = radeon_ms_irq_handler, +	.irq_preinstall = radeon_ms_irq_preinstall, +	.irq_postinstall = radeon_ms_irq_postinstall, +	.irq_uninstall = radeon_ms_irq_uninstall, +	.reclaim_buffers = drm_core_reclaim_buffers, +	.reclaim_buffers_locked = NULL, +	.reclaim_buffers_idlelocked = NULL, +	.get_map_ofs = drm_core_get_map_ofs, +	.get_reg_ofs = drm_core_get_reg_ofs, +	.set_version = NULL, +	.fb_probe = radeonfb_probe, +	.fb_remove = radeonfb_remove, +	.fence_driver = &radeon_ms_fence_driver, +	.bo_driver = &radeon_ms_bo_driver, +	.major = DRIVER_MAJOR, +	.minor = DRIVER_MINOR, +	.patchlevel = DRIVER_PATCHLEVEL, +	.name = DRIVER_NAME, +	.desc = DRIVER_DESC, +	.date = DRIVER_DATE, +	.driver_features = +	    DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | +  	    DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED, +	.dev_priv_size = 0,  +	.ioctls = radeon_ms_ioctls, +	.num_ioctls = 0, +	.fops = { +		.owner = THIS_MODULE, +		.open = drm_open, +		.release = drm_release, +		.ioctl = drm_ioctl, +		.mmap = drm_mmap, +		.poll = drm_poll, +		.fasync = drm_fasync, +#if defined(CONFIG_COMPAT) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) +		.compat_ioctl = radeon_ms_compat_ioctl, +#endif +		}, +	.pci_driver = { +		.name = DRIVER_NAME, +		.id_table = pciidlist, +		.probe = radeon_ms_driver_probe, +		.remove = __devexit_p(drm_cleanup_pci), +	}, +}; + +static int radeon_ms_driver_probe(struct pci_dev *pdev, +				  const struct pci_device_id *ent) +{ +	return drm_get_dev(pdev, ent, &driver); +} + +static int radeon_ms_driver_dri_library_name(struct drm_device * dev, +					     char * buf) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	int ret; + +	switch (dev_priv->family) { +	default: +		ret = snprintf(buf, PAGE_SIZE, "\n"); +	} +	return ret; +} + +static void __exit radeon_ms_driver_exit(void) +{ +	drm_exit(&driver); +} + +static int __init radeon_ms_driver_init(void) +{ +	driver.num_ioctls = radeon_ms_num_ioctls; +	return drm_init(&driver, pciidlist); +} + +module_init(radeon_ms_driver_init); +module_exit(radeon_ms_driver_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL and additional rights"); diff --git a/linux-core/radeon_ms_drv.h b/linux-core/radeon_ms_drv.h new file mode 100644 index 00000000..529f9c42 --- /dev/null +++ b/linux-core/radeon_ms_drv.h @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Dave Airlie + * Copyright 2007 Alex Deucher + * Copyright 2007 Michel Dänzer + * Copyright 2007 Roland Scheidegger + * Copyright 2007 Vladimir Dergachev + * Copyright 2007 Nicolai Haehnle + * Copyright 2007 Aapo Tahkola + * Copyright 2007 Ben Skeggs + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: + *    Jérôme Glisse <glisse@freedesktop.org> + */ +#ifndef __RADEON_MS_DRV_H__ +#define __RADEON_MS_DRV_H__ + +#include <linux/i2c.h> +#include <linux/i2c-id.h> +#include <linux/i2c-algo-bit.h> +#include "drm.h" +#include "drmP.h" + +#endif diff --git a/linux-core/radeon_ms_exec.c b/linux-core/radeon_ms_exec.c new file mode 120000 index 00000000..cb397fbf --- /dev/null +++ b/linux-core/radeon_ms_exec.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_exec.c
\ No newline at end of file diff --git a/linux-core/radeon_ms_family.c b/linux-core/radeon_ms_family.c new file mode 120000 index 00000000..1f12e092 --- /dev/null +++ b/linux-core/radeon_ms_family.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_family.c
\ No newline at end of file diff --git a/linux-core/radeon_ms_fb.c b/linux-core/radeon_ms_fb.c new file mode 100644 index 00000000..fc9e99ec --- /dev/null +++ b/linux-core/radeon_ms_fb.c @@ -0,0 +1,457 @@ +/* + * Copyright © 2007 David Airlie + * Copyright © 2007 Jerome Glisse + * + * All Rights Reserved. + * + * 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 on 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 + * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS 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. + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/init.h> + +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "radeon_ms.h" + +struct radeonfb_par { +	struct drm_device       *dev; +	struct drm_crtc         *crtc; +	struct drm_display_mode *fb_mode; +}; + +static int radeonfb_setcolreg(unsigned regno, unsigned red, +			       unsigned green, unsigned blue, +			       unsigned transp, struct fb_info *info) +{ +	struct radeonfb_par *par = info->par; +	struct drm_framebuffer *fb = par->crtc->fb; +	struct drm_crtc *crtc = par->crtc; + +	if (regno > 255) { +		return 1; +	} +	if (crtc->funcs->gamma_set) { +		crtc->funcs->gamma_set(crtc, red, green, blue, regno); +	} +	if (regno < 16) { +		switch (fb->depth) { +		case 15: +			fb->pseudo_palette[regno] = ((red & 0xf800) >>  1) | +				((green & 0xf800) >>  6) | +				((blue & 0xf800) >> 11); +			break; +		case 16: +			fb->pseudo_palette[regno] = (red & 0xf800) | +				((green & 0xfc00) >>  5) | +				((blue  & 0xf800) >> 11); +			break; +		case 24: +		case 32: +			fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | +				(green & 0xff00) | +				((blue  & 0xff00) >> 8); +			break; +		} +	} +	return 0; +} + +static int radeonfb_check_var(struct fb_var_screeninfo *var, +			       struct fb_info *info) +{ +        struct radeonfb_par *par = info->par; +	struct drm_framebuffer *fb = par->crtc->fb; + +        if (!var->pixclock) +                return -EINVAL; + +        /* Need to resize the fb object !!! */ +        if (var->xres > fb->width || var->yres > fb->height) { +                DRM_ERROR("Requested width/height is greater than " +			  "current fb object %dx%d > %dx%d\n", +			  var->xres, var->yres, fb->width, fb->height); +                DRM_ERROR("Need resizing code.\n"); +                return -EINVAL; +        } + +        switch (var->bits_per_pixel) { +        case 16: +		if (var->green.length == 5) { +			var->red.offset = 10; +			var->green.offset = 5; +			var->blue.offset = 0; +			var->red.length = 5; +			var->green.length = 5; +			var->blue.length = 5; +			var->transp.length = 0; +			var->transp.offset = 0; +		} else { +	                var->red.offset = 11; +			var->green.offset = 6; +			var->blue.offset = 0; +			var->red.length = 5; +			var->green.length = 6; +			var->blue.length = 5; +			var->transp.length = 0; +			var->transp.offset = 0; +		} +                break; +	case 32: +                if (var->transp.length) { +			var->red.offset = 16; +			var->green.offset = 8; +			var->blue.offset = 0; +			var->red.length = 8; +			var->green.length = 8; +			var->blue.length = 8; +			var->transp.length = 8; +			var->transp.offset = 24; +		} else { +			var->red.offset = 16; +			var->green.offset = 8; +			var->blue.offset = 0; +			var->red.length = 8; +			var->green.length = 8; +			var->blue.length = 8; +			var->transp.length = 0; +			var->transp.offset = 0; +		} +		break; +        default: +		return -EINVAL;  +        } +	return 0; +} + +static bool radeonfb_mode_equal(struct drm_display_mode *mode1, +			        struct drm_display_mode *mode2) +{ +	if (mode1->hdisplay == mode2->hdisplay && +	    mode1->hsync_start == mode2->hsync_start && +	    mode1->hsync_end == mode2->hsync_end && +	    mode1->htotal == mode2->htotal && +	    mode1->hskew == mode2->hskew && +	    mode1->vdisplay == mode2->vdisplay && +	    mode1->vsync_start == mode2->vsync_start && +	    mode1->vsync_end == mode2->vsync_end && +	    mode1->vtotal == mode2->vtotal && +	    mode1->vscan == mode2->vscan && +	    mode1->flags == mode2->flags) { +	    	/* FIXME: what about adding a margin for clock ? */ +		if (mode1->clock == mode2->clock) +			return true; +		return false; +	} +	 +	return false; +} + +static int radeonfb_set_par(struct fb_info *info) +{ +	struct radeonfb_par *par = info->par; +	struct drm_framebuffer *fb = par->crtc->fb; +	struct drm_device *dev = par->dev; +        struct drm_display_mode *drm_mode, *search_mode; +        struct drm_output *output; +        struct fb_var_screeninfo *var = &info->var; +	int found = 0; + +        switch (var->bits_per_pixel) { +        case 16: +		fb->depth = (var->green.length == 6) ? 16 : 15; +		break; +        case 32: +		fb->depth = (var->transp.length > 0) ? 32 : 24; +		break; +	default: +		return -EINVAL;  +	} +	fb->bits_per_pixel = var->bits_per_pixel; + +	info->fix.line_length = fb->pitch; +	info->fix.smem_len = info->fix.line_length * fb->height; +	info->fix.visual = FB_VISUAL_TRUECOLOR; +	info->screen_size = info->fix.smem_len; /* ??? */ + +        /* Should we walk the output's modelist or just create our own ??? +         * For now, we create and destroy a mode based on the incoming  +         * parameters. But there's commented out code below which scans  +         * the output list too. +         */ +	drm_mode = drm_mode_create(dev); +	drm_mode->hdisplay = var->xres; +	drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin; +	drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len; +	drm_mode->htotal = drm_mode->hsync_end + var->left_margin; +	drm_mode->vdisplay = var->yres; +	drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin; +	drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len; +	drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin; +	drm_mode->clock = PICOS2KHZ(var->pixclock); +	drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); +	drm_mode_set_name(drm_mode); +	drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); + +        list_for_each_entry(output, &dev->mode_config.output_list, head) { +                if (output->crtc == par->crtc) +                        break; +        } + +	drm_mode_debug_printmodeline(dev, drm_mode);     +        list_for_each_entry(search_mode, &output->modes, head) { +		drm_mode_debug_printmodeline(dev, search_mode); +		if (radeonfb_mode_equal(drm_mode, search_mode)) { +			drm_mode_destroy(dev, drm_mode); +			drm_mode = search_mode; +			found = 1; +			break; +		} +	} + +	if (!found) { +		if (par->fb_mode) { +			drm_mode_detachmode_crtc(dev, par->fb_mode); +		} +		par->fb_mode = drm_mode; +		drm_mode_debug_printmodeline(dev, drm_mode); +		/* attach mode */ +		drm_mode_attachmode_crtc(dev, par->crtc, par->fb_mode); +	} + +	if (par->crtc->enabled) { +		if (!drm_mode_equal(&par->crtc->mode, drm_mode)) { +			if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) { +				return -EINVAL; +			} +		} +	} + +	return 0; +} + +static struct fb_ops radeonfb_ops = { +	.owner = THIS_MODULE, +	//	.fb_open = radeonfb_open, +	//	.fb_read = radeonfb_read, +	//	.fb_write = radeonfb_write, +	//	.fb_release = radeonfb_release, +	//	.fb_ioctl = radeonfb_ioctl, +	.fb_check_var = radeonfb_check_var, +	.fb_set_par = radeonfb_set_par, +	.fb_setcolreg = radeonfb_setcolreg, +	.fb_fillrect = cfb_fillrect, +	.fb_copyarea = cfb_copyarea, +	.fb_imageblit = cfb_imageblit, +}; + +int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc) +{ +	struct fb_info *info; +	struct radeonfb_par *par; +	struct device *device = &dev->pdev->dev;  +	struct drm_framebuffer *fb; +	struct drm_display_mode *mode = crtc->desired_mode; +	int ret; + +	info = framebuffer_alloc(sizeof(struct radeonfb_par), device); +	if (!info){ +		DRM_INFO("[radeon_ms] framebuffer_alloc failed\n"); +		return -EINVAL; +	} + +	fb = drm_framebuffer_create(dev); +	if (!fb) { +		framebuffer_release(info); +		DRM_ERROR("[radeon_ms] failed to allocate fb.\n"); +		return -EINVAL; +	} +	crtc->fb = fb; + +	fb->width = crtc->desired_mode->hdisplay; +	fb->height = crtc->desired_mode->vdisplay; +	fb->bits_per_pixel = 32; +	fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); +	fb->depth = 24; +	/* one page alignment should be fine for constraint (micro|macro tiling, +	 * bit depth, color buffer offset, ...) */ +	ret = drm_buffer_object_create(dev, fb->width * fb->height * 4,  +				       drm_bo_type_kernel, +				       DRM_BO_FLAG_READ | +				       DRM_BO_FLAG_WRITE | +				       DRM_BO_FLAG_NO_EVICT | +				       DRM_BO_FLAG_MEM_VRAM, +				       DRM_BO_HINT_DONT_FENCE, +				       1, +				       0, +				       &fb->bo); +	if (ret || fb->bo == NULL) { +		DRM_ERROR("[radeon_ms] failed to allocate framebuffer\n"); +		drm_framebuffer_destroy(fb); +		framebuffer_release(info); +		return -EINVAL; +	} + +	fb->offset = fb->bo->offset; +	DRM_INFO("[radeon_ms] framebuffer %dx%d at 0x%08lX\n", +		 fb->width, fb->height, fb->bo->offset); + +	fb->fbdev = info; +	par = info->par; +	par->dev = dev; +	par->crtc = crtc; +	info->fbops = &radeonfb_ops; +	strcpy(info->fix.id, "radeonfb"); +	info->fix.type = FB_TYPE_PACKED_PIXELS; +	info->fix.visual = FB_VISUAL_TRUECOLOR; +	info->fix.type_aux = 0; +	info->fix.xpanstep = 8; +	info->fix.ypanstep = 1; +	info->fix.ywrapstep = 0; +	info->fix.accel = FB_ACCEL_ATI_RADEON; +	info->fix.type_aux = 0; +	info->fix.mmio_start = 0; +	info->fix.mmio_len = 0; +	info->fix.line_length = fb->pitch; +	info->fix.smem_start = fb->offset + dev->mode_config.fb_base; +	info->fix.smem_len = info->fix.line_length * fb->height; +	info->flags = FBINFO_DEFAULT; +	DRM_INFO("[radeon_ms] fb physical start : 0x%lX\n", info->fix.smem_start); +	DRM_INFO("[radeon_ms] fb physical size  : %d\n", info->fix.smem_len); + +	ret = drm_mem_reg_ioremap(dev, &fb->bo->mem, &fb->virtual_base); +	if (ret) { +		DRM_ERROR("error mapping fb: %d\n", ret); +	} + +	info->screen_base = fb->virtual_base; +	info->screen_size = info->fix.smem_len; /* FIXME */ +	info->pseudo_palette = fb->pseudo_palette; +	info->var.xres_virtual = fb->width; +	info->var.yres_virtual = fb->height; +	info->var.bits_per_pixel = fb->bits_per_pixel; +	info->var.xoffset = 0; +	info->var.yoffset = 0; +	info->var.activate = FB_ACTIVATE_NOW; +	info->var.height = -1; +	info->var.width = -1; +	info->var.vmode = FB_VMODE_NONINTERLACED; + +	info->var.xres = mode->hdisplay; +	info->var.right_margin = mode->hsync_start - mode->hdisplay; +	info->var.hsync_len = mode->hsync_end - mode->hsync_start; +	info->var.left_margin = mode->htotal - mode->hsync_end; +	info->var.yres = mode->vdisplay; +	info->var.lower_margin = mode->vsync_start - mode->vdisplay; +	info->var.vsync_len = mode->vsync_end - mode->vsync_start; +	info->var.upper_margin = mode->vtotal - mode->vsync_end; +	info->var.pixclock = 10000000 / mode->htotal * 1000 / +		mode->vtotal * 100; +	/* avoid overflow */ +	info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; + +	info->pixmap.size = 64*1024; +	info->pixmap.buf_align = 8; +	info->pixmap.access_align = 32; +	info->pixmap.flags = FB_PIXMAP_SYSTEM; +	info->pixmap.scan_align = 1; + +	DRM_DEBUG("fb depth is %d\n", fb->depth); +	DRM_DEBUG("   pitch is %d\n", fb->pitch); +	switch(fb->depth) { + 	case 15: +                info->var.red.offset = 10; +		info->var.green.offset = 5; +		info->var.blue.offset = 0; +		info->var.red.length = info->var.green.length = +			info->var.blue.length = 5; +		info->var.transp.offset = 15; +                info->var.transp.length = 1; +                break; +	case 16: +                info->var.red.offset = 11; +                info->var.green.offset = 5; +                info->var.blue.offset = 0; +                info->var.red.length = 5; +                info->var.green.length = 6; +                info->var.blue.length = 5; +                info->var.transp.offset = 0; + 		break; +	case 24: +                info->var.red.offset = 16; +                info->var.green.offset = 8; +                info->var.blue.offset = 0; +                info->var.red.length = info->var.green.length = +                        info->var.blue.length = 8; +                info->var.transp.offset = 0; +                info->var.transp.length = 0; +                break; +	case 32: +		info->var.red.offset = 16; +		info->var.green.offset = 8; +		info->var.blue.offset = 0; +		info->var.red.length = info->var.green.length = +			info->var.blue.length = 8; +		info->var.transp.offset = 24; +		info->var.transp.length = 8; +		break; +	default: +		DRM_ERROR("only support 15, 16, 24 or 32bits per pixel " +			  "got %d\n", fb->depth); +		return -EINVAL; +		break; +	} + +	if (register_framebuffer(info) < 0) { +		return -EINVAL; +	} + +	DRM_INFO("[radeon_ms] fb%d: %s frame buffer device\n", info->node, +		 info->fix.id); +	return 0; +} +EXPORT_SYMBOL(radeonfb_probe); + +int radeonfb_remove(struct drm_device *dev, struct drm_crtc *crtc) +{ +	struct drm_framebuffer *fb = crtc->fb; +	struct fb_info *info = fb->fbdev; +	 +	if (info) { +		unregister_framebuffer(info); +		framebuffer_release(info); +		drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base); +		drm_bo_usage_deref_unlocked(&fb->bo); +		drm_framebuffer_destroy(fb); +	} +	return 0; +} +EXPORT_SYMBOL(radeonfb_remove); +MODULE_LICENSE("GPL"); diff --git a/linux-core/radeon_ms_fence.c b/linux-core/radeon_ms_fence.c new file mode 120000 index 00000000..383cc070 --- /dev/null +++ b/linux-core/radeon_ms_fence.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_fence.c
\ No newline at end of file diff --git a/linux-core/radeon_ms_gpu.c b/linux-core/radeon_ms_gpu.c new file mode 120000 index 00000000..fa5e05bf --- /dev/null +++ b/linux-core/radeon_ms_gpu.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_gpu.c
\ No newline at end of file diff --git a/linux-core/radeon_ms_i2c.c b/linux-core/radeon_ms_i2c.c new file mode 120000 index 00000000..1863e6d6 --- /dev/null +++ b/linux-core/radeon_ms_i2c.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_i2c.c
\ No newline at end of file diff --git a/linux-core/radeon_ms_irq.c b/linux-core/radeon_ms_irq.c new file mode 120000 index 00000000..c4e60ba6 --- /dev/null +++ b/linux-core/radeon_ms_irq.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_irq.c
\ No newline at end of file diff --git a/linux-core/radeon_ms_output.c b/linux-core/radeon_ms_output.c new file mode 120000 index 00000000..6a38b671 --- /dev/null +++ b/linux-core/radeon_ms_output.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_output.c
\ No newline at end of file diff --git a/linux-core/radeon_ms_properties.c b/linux-core/radeon_ms_properties.c new file mode 120000 index 00000000..e2e0dc0b --- /dev/null +++ b/linux-core/radeon_ms_properties.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_properties.c
\ No newline at end of file diff --git a/linux-core/radeon_ms_properties.h b/linux-core/radeon_ms_properties.h new file mode 120000 index 00000000..59783e89 --- /dev/null +++ b/linux-core/radeon_ms_properties.h @@ -0,0 +1 @@ +../shared-core/radeon_ms_properties.h
\ No newline at end of file diff --git a/linux-core/radeon_ms_reg.h b/linux-core/radeon_ms_reg.h new file mode 120000 index 00000000..24b01b42 --- /dev/null +++ b/linux-core/radeon_ms_reg.h @@ -0,0 +1 @@ +../shared-core/radeon_ms_reg.h
\ No newline at end of file diff --git a/linux-core/radeon_ms_rom.c b/linux-core/radeon_ms_rom.c new file mode 120000 index 00000000..80f5f606 --- /dev/null +++ b/linux-core/radeon_ms_rom.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_rom.c
\ No newline at end of file diff --git a/linux-core/radeon_ms_rom.h b/linux-core/radeon_ms_rom.h new file mode 120000 index 00000000..f20e42be --- /dev/null +++ b/linux-core/radeon_ms_rom.h @@ -0,0 +1 @@ +../shared-core/radeon_ms_rom.h
\ No newline at end of file diff --git a/linux-core/radeon_ms_state.c b/linux-core/radeon_ms_state.c new file mode 120000 index 00000000..2d2e2ef7 --- /dev/null +++ b/linux-core/radeon_ms_state.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_state.c
\ No newline at end of file diff --git a/linux-core/via_fence.c b/linux-core/via_fence.c index 3a680a32..20df4779 100644 --- a/linux-core/via_fence.c +++ b/linux-core/via_fence.c @@ -63,7 +63,7 @@ static void via_fence_poll(struct drm_device *dev, uint32_t class,  		if (!dev_priv->have_idlelock) { -			drm_idlelock_take(&dev->lock); +			drm_idlelock_take(&dev->primary->master->lock);  			dev_priv->have_idlelock = 1;  		} diff --git a/shared-core/drm.h b/shared-core/drm.h index 6c134566..0d7cfd25 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -950,6 +950,174 @@ struct drm_mm_init_arg {  	uint64_t p_size;  }; +/* + * Drm mode setting + */ +#define DRM_DISPLAY_INFO_LEN 32 +#define DRM_OUTPUT_NAME_LEN 32 +#define DRM_DISPLAY_MODE_LEN 32 +#define DRM_PROP_NAME_LEN 32 + +#define DRM_MODE_TYPE_BUILTIN	(1<<0) +#define DRM_MODE_TYPE_CLOCK_C	((1<<1) | DRM_MODE_TYPE_BUILTIN) +#define DRM_MODE_TYPE_CRTC_C	((1<<2) | DRM_MODE_TYPE_BUILTIN) +#define DRM_MODE_TYPE_PREFERRED	(1<<3) +#define DRM_MODE_TYPE_DEFAULT	(1<<4) +#define DRM_MODE_TYPE_USERDEF	(1<<5) +#define DRM_MODE_TYPE_DRIVER	(1<<6) + +struct drm_mode_modeinfo { +	unsigned int clock; +	unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew; +	unsigned short vdisplay, vsync_start, vsync_end, vtotal, vscan; + +	unsigned int vrefresh; /* vertical refresh * 1000 */ + +	unsigned int flags; +	unsigned int type; +	char name[DRM_DISPLAY_MODE_LEN]; +}; + +struct drm_mode_card_res { +	uint64_t fb_id_ptr; +	uint64_t crtc_id_ptr; +	uint64_t output_id_ptr; +	int count_fbs; +	int count_crtcs; +	int count_outputs; +	int min_width, max_width; +	int min_height, max_height; +}; + +struct drm_mode_crtc { +	uint64_t set_outputs_ptr; + +	unsigned int crtc_id; /**< Id */ +	unsigned int fb_id; /**< Id of framebuffer */ + +	int x, y; /**< Position on the frameuffer */ + +	int count_outputs; +	unsigned int outputs; /**< Outputs that are connected */ + +	int count_possibles; +	unsigned int possibles; /**< Outputs that can be connected */ +	int gamma_size; +	int mode_valid; +	struct drm_mode_modeinfo mode; +}; + +#define DRM_MODE_OUTPUT_NONE 0 +#define DRM_MODE_OUTPUT_DAC  1 +#define DRM_MODE_OUTPUT_TMDS 2 +#define DRM_MODE_OUTPUT_LVDS 3 +#define DRM_MODE_OUTPUT_TVDAC 4 + +struct drm_mode_get_output { + +	uint64_t modes_ptr; +	uint64_t props_ptr; +	uint64_t prop_values_ptr; + +	int count_modes; +	int count_props; +	unsigned int output; /**< Id */ +	unsigned int crtc; /**< Id of crtc */ +	unsigned int output_type; +	unsigned int output_type_id; + +	unsigned int connection; +	unsigned int mm_width, mm_height; /**< HxW in millimeters */ +	unsigned int subpixel; +	int count_crtcs; +	int count_clones; +	unsigned int crtcs; /**< possible crtc to connect to */ +	unsigned int clones; /**< list of clones */ +}; + +#define DRM_MODE_PROP_PENDING (1<<0) +#define DRM_MODE_PROP_RANGE (1<<1) +#define DRM_MODE_PROP_IMMUTABLE (1<<2) +#define DRM_MODE_PROP_ENUM (1<<3) // enumerated type with text strings +#define DRM_MODE_PROP_BLOB (1<<4) + +struct drm_mode_property_enum { +	uint64_t value; +	unsigned char name[DRM_PROP_NAME_LEN]; +}; + +struct drm_mode_get_property { +	uint64_t values_ptr; /* values and blob lengths */ +	uint64_t enum_blob_ptr; /* enum and blob id ptrs */ + +	unsigned int prop_id; +	unsigned int flags; +	unsigned char name[DRM_PROP_NAME_LEN]; + +	int count_values; +	int count_enum_blobs; +}; + +struct drm_mode_output_set_property { +	uint64_t value; +	unsigned int prop_id; +	unsigned int output_id; +}; + +struct drm_mode_get_blob { +	uint32_t blob_id; +	uint32_t length; +	uint64_t data; +}; + +struct drm_mode_fb_cmd { +        unsigned int buffer_id; +        unsigned int width, height; +        unsigned int pitch; +        unsigned int bpp; +        unsigned int handle; +	unsigned int depth; +}; + +struct drm_mode_mode_cmd { +	unsigned int output_id; +	struct drm_mode_modeinfo mode; +}; + +#define DRM_MODE_CURSOR_BO   0x01 +#define DRM_MODE_CURSOR_MOVE 0x02 + +/* + * depending on the value in flags diffrent members are used. + * + * CURSOR_BO uses + *    crtc + *    width + *    height + *    handle - if 0 turns the cursor of + * + * CURSOR_MOVE uses + *    crtc + *    x + *    y + */ +struct drm_mode_cursor { +	unsigned int flags; +	unsigned int crtc; +	int x; +	int y; +	uint32_t width; +	uint32_t height; +	unsigned int handle; +}; + +/* + * oh so ugly hotplug + */ +struct drm_mode_hotplug { +	uint32_t counter; +}; +  /**   * \name Ioctls Definitions   */ @@ -1042,6 +1210,23 @@ struct drm_mm_init_arg {  #define DRM_IOCTL_BO_WAIT_IDLE          DRM_IOWR(0xd5, struct drm_bo_map_wait_idle_arg)  #define DRM_IOCTL_BO_VERSION          DRM_IOR(0xd6, struct drm_bo_version_arg) +#define DRM_IOCTL_MODE_GETRESOURCES     DRM_IOWR(0xA0, struct drm_mode_card_res) +#define DRM_IOCTL_MODE_GETCRTC          DRM_IOWR(0xA1, struct drm_mode_crtc) +#define DRM_IOCTL_MODE_GETOUTPUT        DRM_IOWR(0xA2, struct drm_mode_get_output) +#define DRM_IOCTL_MODE_SETCRTC          DRM_IOWR(0xA3, struct drm_mode_crtc) +#define DRM_IOCTL_MODE_ADDFB            DRM_IOWR(0xA4, struct drm_mode_fb_cmd) +#define DRM_IOCTL_MODE_RMFB             DRM_IOWR(0xA5, unsigned int) +#define DRM_IOCTL_MODE_GETFB            DRM_IOWR(0xA6, struct drm_mode_fb_cmd) + +#define DRM_IOCTL_MODE_SETPROPERTY     DRM_IOWR(0xA7, struct drm_mode_output_set_property) +#define DRM_IOCTL_MODE_GETPROPBLOB     DRM_IOWR(0xA8, struct drm_mode_get_blob) +#define DRM_IOCTL_MODE_ATTACHMODE      DRM_IOWR(0xA9, struct drm_mode_mode_cmd) +#define DRM_IOCTL_MODE_DETACHMODE      DRM_IOWR(0xAA, struct drm_mode_mode_cmd) + +#define DRM_IOCTL_MODE_GETPROPERTY     DRM_IOWR(0xAB, struct drm_mode_get_property) +#define DRM_IOCTL_MODE_CURSOR          DRM_IOWR(0xAC, struct drm_mode_cursor) +#define DRM_IOCTL_MODE_HOTPLUG         DRM_IOWR(0xAD, struct drm_mode_hotplug) +  /*@}*/  /** diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt index 63b5cd50..c895d7f7 100644 --- a/shared-core/drm_pciids.txt +++ b/shared-core/drm_pciids.txt @@ -1,3 +1,7 @@ +[radeon_ms] +0x1002 0x4150 CHIP_RV350|RADEON_AGP "ATI Radeon RV350 9600" +0x1002 0x5b63 CHIP_RV370|RADEON_PCIE "ATI Radeon RV370 X550" +  [radeon]  0x1002 0x3150 CHIP_RV380|RADEON_IS_MOBILITY "ATI Radeon Mobility X600 M24"  0x1002 0x3152 CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon Mobility X300 M24" diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 3874ed58..3d489231 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -38,8 +38,8 @@   */  int i915_wait_ring(struct drm_device * dev, int n, const char *caller)  { -	drm_i915_private_t *dev_priv = dev->dev_private; -	drm_i915_ring_buffer_t *ring = &(dev_priv->ring); +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_i915_ring_buffer *ring = &(dev_priv->ring);  	u32 last_head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;  	int i; @@ -63,8 +63,8 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)  void i915_kernel_lost_context(struct drm_device * dev)  { -	drm_i915_private_t *dev_priv = dev->dev_private; -	drm_i915_ring_buffer_t *ring = &(dev_priv->ring); +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_i915_ring_buffer *ring = &(dev_priv->ring);  	ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;  	ring->tail = I915_READ(LP_RING + RING_TAIL) & TAIL_ADDR; @@ -73,9 +73,8 @@ void i915_kernel_lost_context(struct drm_device * dev)  		ring->space += ring->Size;  } -static int i915_dma_cleanup(struct drm_device * dev) +int i915_dma_cleanup(struct drm_device * dev)  { -	drm_i915_private_t *dev_priv = dev->dev_private;  	/* Make sure interrupts are disabled here because the uninstall ioctl  	 * may not have been called from userspace and after dev_private  	 * is freed, it's too late. @@ -83,26 +82,6 @@ static int i915_dma_cleanup(struct drm_device * dev)  	if (dev->irq)  		drm_irq_uninstall(dev); -	if (dev_priv->ring.virtual_start) { -		drm_core_ioremapfree(&dev_priv->ring.map, dev); -		dev_priv->ring.virtual_start = 0; -		dev_priv->ring.map.handle = 0; -		dev_priv->ring.map.size = 0; -	} - -	if (dev_priv->status_page_dmah) { -		drm_pci_free(dev, dev_priv->status_page_dmah); -		dev_priv->status_page_dmah = NULL; -		/* Need to rewrite hardware status page */ -		I915_WRITE(0x02080, 0x1ffff000); -	} - -	if (dev_priv->status_gfx_addr) { -		dev_priv->status_gfx_addr = 0; -		drm_core_ioremapfree(&dev_priv->hws_map, dev); -		I915_WRITE(0x02080, 0x1ffff000); -	} -  	return 0;  } @@ -171,18 +150,9 @@ static int i915_initialize(struct drm_device * dev,  			   struct drm_file *file_priv,  			   drm_i915_init_t * init)  { -	drm_i915_private_t *dev_priv = dev->dev_private; -	int ret; - -	dev_priv->sarea = drm_getsarea(dev); -	if (!dev_priv->sarea) { -		DRM_ERROR("can not find sarea!\n"); -		i915_dma_cleanup(dev); -		return -EINVAL; -	} - -	if (init->mmio_offset != 0) -		dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; +	dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);  	if (!dev_priv->mmio_map) {  		i915_dma_cleanup(dev);  		DRM_ERROR("can not find mmio map!\n"); @@ -193,41 +163,32 @@ static int i915_initialize(struct drm_device * dev,  	dev_priv->max_validate_buffers = I915_MAX_VALIDATE_BUFFERS;  #endif -	if (init->sarea_priv_offset) -		dev_priv->sarea_priv = (drm_i915_sarea_t *) -			((u8 *) dev_priv->sarea->handle + -			 init->sarea_priv_offset); -	else { -		/* No sarea_priv for you! */ -		dev_priv->sarea_priv = NULL; -	} - -	dev_priv->ring.Start = init->ring_start; -	dev_priv->ring.End = init->ring_end; -	dev_priv->ring.Size = init->ring_size; -	dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; - -	dev_priv->ring.map.offset = init->ring_start; -	dev_priv->ring.map.size = init->ring_size; -	dev_priv->ring.map.type = 0; -	dev_priv->ring.map.flags = 0; -	dev_priv->ring.map.mtrr = 0; - -	drm_core_ioremap(&dev_priv->ring.map, dev); - -	if (dev_priv->ring.map.handle == NULL) { -		i915_dma_cleanup(dev); -		DRM_ERROR("can not ioremap virtual address for" -			  " ring buffer\n"); -		return -ENOMEM; +	if (!dev_priv->ring.Size) { +		dev_priv->ring.Start = init->ring_start; +		dev_priv->ring.End = init->ring_end; +		dev_priv->ring.Size = init->ring_size; +		dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; +		 +		dev_priv->ring.map.offset = init->ring_start; +		dev_priv->ring.map.size = init->ring_size; +		dev_priv->ring.map.type = 0; +		dev_priv->ring.map.flags = 0; +		dev_priv->ring.map.mtrr = 0; +		 +		drm_core_ioremap(&dev_priv->ring.map, dev); +		 +		if (dev_priv->ring.map.handle == NULL) { +			i915_dma_cleanup(dev); +			DRM_ERROR("can not ioremap virtual address for" +				  " ring buffer\n"); +			return -ENOMEM; +		} +		dev_priv->ring.virtual_start = dev_priv->ring.map.handle;  	} -	dev_priv->ring.virtual_start = dev_priv->ring.map.handle;  	dev_priv->cpp = init->cpp; - -	if (dev_priv->sarea_priv) -		dev_priv->sarea_priv->pf_current_page = 0; +	master_priv->sarea_priv->pf_current_page = 0;  	/* We are using separate values as placeholders for mechanisms for  	 * private backbuffer/depthbuffer usage. @@ -281,15 +242,10 @@ static int i915_initialize(struct drm_device * dev,  static int i915_dma_resume(struct drm_device * dev)  { -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;  	DRM_DEBUG("\n"); -	if (!dev_priv->sarea) { -		DRM_ERROR("can not find sarea!\n"); -		return -EINVAL; -	} -  	if (!dev_priv->mmio_map) {  		DRM_ERROR("can not find mmio map!\n");  		return -EINVAL; @@ -320,7 +276,7 @@ static int i915_dma_resume(struct drm_device * dev)  static int i915_dma_init(struct drm_device *dev, void *data,  			 struct drm_file *file_priv)  { -	drm_i915_init_t *init = data; +	struct drm_i915_init *init = data;  	int retcode = 0;  	switch (init->func) { @@ -421,7 +377,7 @@ static int validate_cmd(int cmd)  static int i915_emit_cmds(struct drm_device *dev, int __user *buffer,  			  int dwords)  { -	drm_i915_private_t *dev_priv = dev->dev_private; +	struct drm_i915_private *dev_priv = dev->dev_private;  	int i;  	RING_LOCALS; @@ -462,7 +418,7 @@ static int i915_emit_box(struct drm_device * dev,  			 struct drm_clip_rect __user * boxes,  			 int i, int DR1, int DR4)  { -	drm_i915_private_t *dev_priv = dev->dev_private; +	struct drm_i915_private *dev_priv = dev->dev_private;  	struct drm_clip_rect box;  	RING_LOCALS; @@ -503,7 +459,8 @@ static int i915_emit_box(struct drm_device * dev,  void i915_emit_breadcrumb(struct drm_device *dev)  { -	drm_i915_private_t *dev_priv = dev->dev_private; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;  	RING_LOCALS;  	if (++dev_priv->counter > BREADCRUMB_MASK) { @@ -511,8 +468,7 @@ void i915_emit_breadcrumb(struct drm_device *dev)  		 DRM_DEBUG("Breadcrumb counter wrapped around\n");  	} -	if (dev_priv->sarea_priv) -		dev_priv->sarea_priv->last_enqueue = dev_priv->counter; +	master_priv->sarea_priv->last_enqueue = dev_priv->counter;  	BEGIN_LP_RING(4);  	OUT_RING(CMD_STORE_DWORD_IDX); @@ -525,7 +481,7 @@ void i915_emit_breadcrumb(struct drm_device *dev)  int i915_emit_mi_flush(struct drm_device *dev, uint32_t flush)  { -	drm_i915_private_t *dev_priv = dev->dev_private; +	struct drm_i915_private *dev_priv = dev->dev_private;  	uint32_t flush_cmd = CMD_MI_FLUSH;  	RING_LOCALS; @@ -545,10 +501,10 @@ int i915_emit_mi_flush(struct drm_device *dev, uint32_t flush)  static int i915_dispatch_cmdbuffer(struct drm_device * dev, -				   drm_i915_cmdbuffer_t * cmd) +				   struct drm_i915_cmdbuffer * cmd)  {  #ifdef I915_HAVE_FENCE -	drm_i915_private_t *dev_priv = dev->dev_private; +	struct drm_i915_private *dev_priv = dev->dev_private;  #endif  	int nbox = cmd->num_cliprects;  	int i = 0, count, ret; @@ -586,7 +542,7 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev,  static int i915_dispatch_batchbuffer(struct drm_device * dev,  				     drm_i915_batchbuffer_t * batch)  { -	drm_i915_private_t *dev_priv = dev->dev_private; +	struct drm_i915_private *dev_priv = dev->dev_private;  	struct drm_clip_rect __user *boxes = batch->cliprects;  	int nbox = batch->num_cliprects;  	int i = 0, count; @@ -640,38 +596,39 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,  static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync)  { -	drm_i915_private_t *dev_priv = dev->dev_private; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;  	u32 num_pages, current_page, next_page, dspbase;  	int shift = 2 * plane, x, y;  	RING_LOCALS;  	/* Calculate display base offset */ -	num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; -	current_page = (dev_priv->sarea_priv->pf_current_page >> shift) & 0x3; +	num_pages = master_priv->sarea_priv->third_handle ? 3 : 2; +	current_page = (master_priv->sarea_priv->pf_current_page >> shift) & 0x3;  	next_page = (current_page + 1) % num_pages;  	switch (next_page) {  	default:  	case 0: -		dspbase = dev_priv->sarea_priv->front_offset; +		dspbase = master_priv->sarea_priv->front_offset;  		break;  	case 1: -		dspbase = dev_priv->sarea_priv->back_offset; +		dspbase = master_priv->sarea_priv->back_offset;  		break;  	case 2: -		dspbase = dev_priv->sarea_priv->third_offset; +		dspbase = master_priv->sarea_priv->third_offset;  		break;  	}  	if (plane == 0) { -		x = dev_priv->sarea_priv->planeA_x; -		y = dev_priv->sarea_priv->planeA_y; +		x = master_priv->sarea_priv->planeA_x; +		y = master_priv->sarea_priv->planeA_y;  	} else { -		x = dev_priv->sarea_priv->planeB_x; -		y = dev_priv->sarea_priv->planeB_y; +		x = master_priv->sarea_priv->planeB_x; +		y = master_priv->sarea_priv->planeB_y;  	} -	dspbase += (y * dev_priv->sarea_priv->pitch + x) * dev_priv->cpp; +	dspbase += (y * master_priv->sarea_priv->pitch + x) * dev_priv->cpp;  	DRM_DEBUG("plane=%d current_page=%d dspbase=0x%x\n", plane, current_page,  		  dspbase); @@ -682,21 +639,22 @@ static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync)  				       MI_WAIT_FOR_PLANE_A_FLIP)));  	OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | (sync ? 0 : ASYNC_FLIP) |  		 (plane ? DISPLAY_PLANE_B : DISPLAY_PLANE_A)); -	OUT_RING(dev_priv->sarea_priv->pitch * dev_priv->cpp); +	OUT_RING(master_priv->sarea_priv->pitch * dev_priv->cpp);  	OUT_RING(dspbase);  	ADVANCE_LP_RING(); -	dev_priv->sarea_priv->pf_current_page &= ~(0x3 << shift); -	dev_priv->sarea_priv->pf_current_page |= next_page << shift; +	master_priv->sarea_priv->pf_current_page &= ~(0x3 << shift); +	master_priv->sarea_priv->pf_current_page |= next_page << shift;  }  void i915_dispatch_flip(struct drm_device * dev, int planes, int sync)  { -	drm_i915_private_t *dev_priv = dev->dev_private; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;  	int i;  	DRM_DEBUG("planes=0x%x pfCurrentPage=%d\n", -		  planes, dev_priv->sarea_priv->pf_current_page); +		  planes, master_priv->sarea_priv->pf_current_page);  	i915_emit_mi_flush(dev, MI_READ_FLUSH | MI_EXE_FLUSH); @@ -713,7 +671,7 @@ void i915_dispatch_flip(struct drm_device * dev, int planes, int sync)  static int i915_quiescent(struct drm_device *dev)  { -	drm_i915_private_t *dev_priv = dev->dev_private; +	struct drm_i915_private *dev_priv = dev->dev_private;  	i915_kernel_lost_context(dev);  	return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__); @@ -731,9 +689,10 @@ static int i915_flush_ioctl(struct drm_device *dev, void *data,  static int i915_batchbuffer(struct drm_device *dev, void *data,  			    struct drm_file *file_priv)  { -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; +	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;  	drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) -	    dev_priv->sarea_priv; +	    master_priv->sarea_priv;  	drm_i915_batchbuffer_t *batch = data;  	int ret; @@ -761,10 +720,11 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,  static int i915_cmdbuffer(struct drm_device *dev, void *data,  			  struct drm_file *file_priv)  { -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; -	drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) -	    dev_priv->sarea_priv; -	drm_i915_cmdbuffer_t *cmdbuf = data; +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; +	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; +	struct drm_i915_sarea *sarea_priv = (struct drm_i915_sarea *) +		master_priv->sarea_priv; +	struct drm_i915_cmdbuffer *cmdbuf = data;  	int ret;  	DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n", @@ -966,7 +926,7 @@ static int i915_exec_reloc(struct drm_file *file_priv, drm_handle_t buf_handle,  			   struct drm_i915_validate_buffer *buffers,  			   uint32_t buf_count)  { -	struct drm_device *dev = file_priv->head->dev; +	struct drm_device *dev = file_priv->minor->dev;  	struct i915_relocatee_info relocatee;  	int ret = 0;  	int b; @@ -1026,7 +986,7 @@ int i915_validate_buffer_list(struct drm_file *file_priv,  	unsigned long next = 0;  	int ret = 0;  	unsigned buf_count = 0; -	struct drm_device *dev = file_priv->head->dev; +	struct drm_device *dev = file_priv->minor->dev;  	uint32_t buf_handle;  	uint32_t __user *reloc_user_ptr; @@ -1117,11 +1077,12 @@ out_err:  static int i915_execbuffer(struct drm_device *dev, void *data,  			   struct drm_file *file_priv)  { -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; +	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;  	drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) -		dev_priv->sarea_priv; +		master_priv->sarea_priv;  	struct drm_i915_execbuffer *exec_buf = data; -	struct _drm_i915_batchbuffer *batch = &exec_buf->batch; +	struct drm_i915_batchbuffer *batch = &exec_buf->batch;  	struct drm_fence_arg *fence_arg = &exec_buf->fence_arg;  	int num_buffers;  	int ret; @@ -1222,21 +1183,22 @@ out_free:  }  #endif -static int i915_do_cleanup_pageflip(struct drm_device * dev) +int i915_do_cleanup_pageflip(struct drm_device * dev)  { -	drm_i915_private_t *dev_priv = dev->dev_private; -	int i, planes, num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; +	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; +	int i, planes, num_pages;  	DRM_DEBUG("\n"); - -	for (i = 0, planes = 0; i < 2; i++) -		if (dev_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) { -			dev_priv->sarea_priv->pf_current_page = -				(dev_priv->sarea_priv->pf_current_page & +	num_pages = master_priv->sarea_priv->third_handle ? 3 : 2; +	for (i = 0, planes = 0; i < 2; i++) { +		if (master_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) { +			master_priv->sarea_priv->pf_current_page = +				(master_priv->sarea_priv->pf_current_page &  				 ~(0x3 << (2 * i))) | ((num_pages - 1) << (2 * i));  			planes |= 1 << i;  		} +	}  	if (planes)  		i915_dispatch_flip(dev, planes, 0); @@ -1246,7 +1208,7 @@ static int i915_do_cleanup_pageflip(struct drm_device * dev)  static int i915_flip_bufs(struct drm_device *dev, void *data, struct drm_file *file_priv)  { -	drm_i915_flip_t *param = data; +	struct drm_i915_flip *param = data;  	DRM_DEBUG("\n"); @@ -1268,8 +1230,8 @@ static int i915_flip_bufs(struct drm_device *dev, void *data, struct drm_file *f  static int i915_getparam(struct drm_device *dev, void *data,  			 struct drm_file *file_priv)  { -	drm_i915_private_t *dev_priv = dev->dev_private; -	drm_i915_getparam_t *param = data; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_i915_getparam *param = data;  	int value;  	if (!dev_priv) { @@ -1306,7 +1268,7 @@ static int i915_getparam(struct drm_device *dev, void *data,  static int i915_setparam(struct drm_device *dev, void *data,  			 struct drm_file *file_priv)  { -	drm_i915_private_t *dev_priv = dev->dev_private; +	struct drm_i915_private *dev_priv = dev->dev_private;  	drm_i915_setparam_t *param = data;  	if (!dev_priv) { @@ -1347,8 +1309,8 @@ static int i915_mmio(struct drm_device *dev, void *data,  		     struct drm_file *file_priv)  {  	uint32_t buf[8]; -	drm_i915_private_t *dev_priv = dev->dev_private; -	drm_i915_mmio_entry_t *e; +	struct drm_i915_private *dev_priv = dev->dev_private; +	drm_i915_mmio_entry_t *e;	   	drm_i915_mmio_t *mmio = data;  	void __iomem *base;  	int i; @@ -1393,7 +1355,7 @@ static int i915_mmio(struct drm_device *dev, void *data,  static int i915_set_status_page(struct drm_device *dev, void *data,  				struct drm_file *file_priv)  { -	drm_i915_private_t *dev_priv = dev->dev_private; +	struct drm_i915_private *dev_priv = dev->dev_private;  	drm_i915_hws_addr_t *hws = data;  	if (!dev_priv) { @@ -1421,67 +1383,14 @@ static int i915_set_status_page(struct drm_device *dev, void *data,  	dev_priv->hw_status_page = dev_priv->hws_map.handle;  	memset(dev_priv->hw_status_page, 0, PAGE_SIZE); -	I915_WRITE(0x02080, dev_priv->status_gfx_addr); +	I915_WRITE(I915REG_HWS_PGA, dev_priv->status_gfx_addr);  	DRM_DEBUG("load hws 0x2080 with gfx mem 0x%x\n",  			dev_priv->status_gfx_addr);  	DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page);  	return 0;  } -int i915_driver_load(struct drm_device *dev, unsigned long flags) -{ -	struct drm_i915_private *dev_priv = dev->dev_private; -	unsigned long base, size; -	int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1; - -	/* i915 has 4 more counters */ -	dev->counters += 4; -	dev->types[6] = _DRM_STAT_IRQ; -	dev->types[7] = _DRM_STAT_PRIMARY; -	dev->types[8] = _DRM_STAT_SECONDARY; -	dev->types[9] = _DRM_STAT_DMA; - -	dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER); -	if (dev_priv == NULL) -		return -ENOMEM; - -	memset(dev_priv, 0, sizeof(drm_i915_private_t)); - -	dev->dev_private = (void *)dev_priv; - -	/* Add register map (needed for suspend/resume) */ -	base = drm_get_resource_start(dev, mmio_bar); -	size = drm_get_resource_len(dev, mmio_bar); - -	ret = drm_addmap(dev, base, size, _DRM_REGISTERS, -		_DRM_KERNEL | _DRM_DRIVER, &dev_priv->mmio_map); - -#ifdef __linux__ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) -	intel_init_chipset_flush_compat(dev); -#endif -#endif - -	return ret; -} - -int i915_driver_unload(struct drm_device *dev) -{ -	struct drm_i915_private *dev_priv = dev->dev_private; - -	if (dev_priv->mmio_map) -		drm_rmmap(dev, dev_priv->mmio_map); - -	drm_free(dev->dev_private, sizeof(drm_i915_private_t), -		 DRM_MEM_DRIVER); -#ifdef __linux__ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) -	intel_fini_chipset_flush_compat(dev); -#endif -#endif -	return 0; -} - +#if 0 /* FIXME DRI2 */  void i915_driver_lastclose(struct drm_device * dev)  {  	drm_i915_private_t *dev_priv = dev->dev_private; @@ -1507,12 +1416,7 @@ void i915_driver_lastclose(struct drm_device * dev)  	i915_dma_cleanup(dev);  } - -void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) -{ -	drm_i915_private_t *dev_priv = dev->dev_private; -	i915_mem_release(dev, file_priv, dev_priv->agp_heap); -} +#endif  struct drm_ioctl_desc i915_ioctls[] = {  	DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), @@ -1556,10 +1460,3 @@ int i915_driver_device_is_agp(struct drm_device * dev)  	return 1;  } -int i915_driver_firstopen(struct drm_device *dev) -{ -#ifdef I915_HAVE_BUFFER -	drm_bo_driver_init(dev); -#endif -	return 0; -} diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index b889a303..6067fa02 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -39,7 +39,7 @@  				 * of chars for next/prev indices */  #define I915_LOG_MIN_TEX_REGION_SIZE 14 -typedef struct _drm_i915_init { +typedef struct drm_i915_init {  	enum {  		I915_INIT_DMA = 0x01,  		I915_CLEANUP_DMA = 0x02, @@ -69,7 +69,7 @@ typedef struct _drm_i915_init {  	unsigned int sarea_handle;  } drm_i915_init_t; -typedef struct _drm_i915_sarea { +typedef struct drm_i915_sarea {  	struct drm_tex_region texList[I915_NR_TEX_REGIONS + 1];  	int last_upload;	/* last time texture was uploaded */  	int last_enqueue;	/* last time a buffer was enqueued */ @@ -202,7 +202,7 @@ typedef struct drm_i915_flip {  /* Allow drivers to submit batchbuffers directly to hardware, relying   * on the security mechanisms provided by hardware.   */ -typedef struct _drm_i915_batchbuffer { +typedef struct drm_i915_batchbuffer {  	int start;		/* agp offset */  	int used;		/* nr bytes in use */  	int DR1;		/* hw flags for GFX_OP_DRAWRECT_INFO */ @@ -214,7 +214,7 @@ typedef struct _drm_i915_batchbuffer {  /* As above, but pass a pointer to userspace buffer which can be   * validated by the kernel prior to sending to hardware.   */ -typedef struct _drm_i915_cmdbuffer { +typedef struct drm_i915_cmdbuffer {  	char __user *buf;	/* pointer to userspace command buffer */  	int sz;			/* nr bytes in buf */  	int DR1;		/* hw flags for GFX_OP_DRAWRECT_INFO */ @@ -366,7 +366,7 @@ struct drm_i915_op_arg {  struct drm_i915_execbuffer {  	uint64_t ops_list;  	uint32_t num_buffers; -	struct _drm_i915_batchbuffer batch; +	struct drm_i915_batchbuffer batch;  	drm_context_t context; /* for lockless use in the future */  	struct drm_fence_arg fence_arg;  }; diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 4d3ac0a5..f6c0005d 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -71,7 +71,7 @@  #define I915_MAX_VALIDATE_BUFFERS 4096  #endif -typedef struct _drm_i915_ring_buffer { +struct drm_i915_ring_buffer {  	int tail_mask;  	unsigned long Start;  	unsigned long End; @@ -81,7 +81,7 @@ typedef struct _drm_i915_ring_buffer {  	int tail;  	int space;  	drm_local_map_t map; -} drm_i915_ring_buffer_t; +};  struct mem_block {  	struct mem_block *next; @@ -91,22 +91,31 @@ struct mem_block {  	struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */  }; -typedef struct _drm_i915_vbl_swap { +struct drm_i915_vbl_swap {  	struct list_head head;  	drm_drawable_t drw_id;  	unsigned int plane;  	unsigned int sequence;  	int flip; -} drm_i915_vbl_swap_t; +	struct drm_minor *minor; +}; -typedef struct drm_i915_private { +struct drm_i915_master_private {  	drm_local_map_t *sarea; +	struct drm_i915_sarea *sarea_priv; +}; +	 +struct drm_i915_private { +	struct drm_buffer_object *ring_buffer; +  	drm_local_map_t *mmio_map; -	drm_i915_sarea_t *sarea_priv; -	drm_i915_ring_buffer_t ring; +	unsigned long mmiobase; +	unsigned long mmiolen; -	drm_dma_handle_t *status_page_dmah; +	struct drm_i915_ring_buffer ring; + +	struct drm_dma_handle *status_page_dmah;  	void *hw_status_page;  	dma_addr_t dma_status_page;  	uint32_t counter; @@ -131,6 +140,8 @@ typedef struct drm_i915_private {  	uint32_t irq_enable_reg;  	int irq_enabled; +	struct workqueue_struct *wq; +  #ifdef I915_HAVE_FENCE  	uint32_t flush_sequence;  	uint32_t flush_flags; @@ -141,12 +152,18 @@ typedef struct drm_i915_private {  	void *agp_iomap;  	unsigned int max_validate_buffers;  	struct mutex cmdbuf_mutex; +	size_t stolen_base;  #endif  	DRM_SPINTYPE swaps_lock; -	drm_i915_vbl_swap_t vbl_swaps; +	struct drm_i915_vbl_swap vbl_swaps;  	unsigned int swaps_pending; +	/* LVDS info */ +	int backlight_duty_cycle;  /* restore backlight to this value */ +	bool panel_wants_dither; +	struct drm_display_mode *panel_fixed_mode; +  	/* DRI2 sarea */  	struct drm_buffer_object *sarea_bo;  	struct drm_bo_kmap_obj sarea_kmap; @@ -237,7 +254,7 @@ typedef struct drm_i915_private {  	u8 saveDACMASK;  	u8 saveDACDATA[256*3]; /* 256 3-byte colors */  	u8 saveCR[36]; -} drm_i915_private_t; +};  enum intel_chip_family {  	CHIP_I8XX = 0x01, @@ -249,10 +266,12 @@ enum intel_chip_family {  extern struct drm_ioctl_desc i915_ioctls[];  extern int i915_max_ioctl; +extern int i915_master_create(struct drm_device *dev, struct drm_master *master); +extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master);  				/* i915_dma.c */  extern void i915_kernel_lost_context(struct drm_device * dev);  extern int i915_driver_load(struct drm_device *, unsigned long flags); -extern int i915_driver_unload(struct drm_device *); +extern int i915_driver_unload(struct drm_device *dev);  extern void i915_driver_lastclose(struct drm_device * dev);  extern void i915_driver_preclose(struct drm_device *dev,  				 struct drm_file *file_priv); @@ -263,6 +282,8 @@ extern void i915_emit_breadcrumb(struct drm_device *dev);  extern void i915_dispatch_flip(struct drm_device * dev, int pipes, int sync);  extern int i915_emit_mi_flush(struct drm_device *dev, uint32_t flush);  extern int i915_driver_firstopen(struct drm_device *dev); +extern int i915_do_cleanup_pageflip(struct drm_device *dev); +extern int i915_dma_cleanup(struct drm_device *dev);  /* i915_irq.c */  extern int i915_irq_emit(struct drm_device *dev, void *data, @@ -279,13 +300,14 @@ extern int i915_vblank_pipe_set(struct drm_device *dev, void *data,  extern int i915_vblank_pipe_get(struct drm_device *dev, void *data,  				struct drm_file *file_priv);  extern int i915_emit_irq(struct drm_device * dev); +extern void i915_enable_interrupt (struct drm_device *dev);  extern int i915_enable_vblank(struct drm_device *dev, int crtc);  extern void i915_disable_vblank(struct drm_device *dev, int crtc);  extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc);  extern int i915_vblank_swap(struct drm_device *dev, void *data,  			    struct drm_file *file_priv); -extern void i915_user_irq_on(drm_i915_private_t *dev_priv); -extern void i915_user_irq_off(drm_i915_private_t *dev_priv); +extern void i915_user_irq_on(struct drm_i915_private *dev_priv); +extern void i915_user_irq_off(struct drm_i915_private *dev_priv);  /* i915_mem.c */  extern int i915_mem_alloc(struct drm_device *dev, void *data, @@ -328,6 +350,12 @@ extern void intel_fini_chipset_flush_compat(struct drm_device *dev);  #endif  #endif + +/* modesetting */ +extern void intel_modeset_init(struct drm_device *dev); +extern void intel_modeset_cleanup(struct drm_device *dev); + +  #define I915_READ(reg)          DRM_READ32(dev_priv->mmio_map, (reg))  #define I915_WRITE(reg,val)     DRM_WRITE32(dev_priv->mmio_map, (reg), (val))  #define I915_READ16(reg)	DRM_READ16(dev_priv->mmio_map, (reg)) @@ -365,8 +393,31 @@ extern void intel_fini_chipset_flush_compat(struct drm_device *dev);  	I915_WRITE(LP_RING + RING_TAIL, outring);			\  } while(0) +#define MI_NOOP	(0x00 << 23) +  extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); +/* + * The Bridge device's PCI config space has information about the + * fb aperture size and the amount of pre-reserved memory. + */ +#define INTEL_GMCH_CTRL		0x52 +#define INTEL_GMCH_ENABLED	0x4 +#define INTEL_GMCH_MEM_MASK	0x1 +#define INTEL_GMCH_MEM_64M	0x1 +#define INTEL_GMCH_MEM_128M	0 + +#define INTEL_855_GMCH_GMS_MASK		(0x7 << 4) +#define INTEL_855_GMCH_GMS_DISABLED	(0x0 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_1M	(0x1 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_4M	(0x2 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_8M	(0x3 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_16M	(0x4 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_32M	(0x5 << 4) + +#define INTEL_915G_GMCH_GMS_STOLEN_48M	(0x6 << 4) +#define INTEL_915G_GMCH_GMS_STOLEN_64M	(0x7 << 4) +  /* Extended config space */  #define LBB 0xf4 @@ -433,6 +484,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);  #define BB1_UNPROTECTED       (0<<0)  #define BB2_END_ADDR_MASK     (~0x7) +#define I915REG_HWS_PGA		0x02080 +  /* Framebuffer compression */  #define FBC_CFB_BASE		0x03200 /* 4k page aligned */  #define FBC_LL_BASE		0x03204 /* 4k page aligned */ @@ -516,6 +569,63 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);  #define I915_VBLANK_INTERRUPT_ENABLE	(1UL<<17)  #define I915_VBLANK_CLEAR		(1UL<<1) +#define GPIOA			0x5010 +#define GPIOB			0x5014 +#define GPIOC			0x5018 +#define GPIOD			0x501c +#define GPIOE			0x5020 +#define GPIOF			0x5024 +#define GPIOG			0x5028 +#define GPIOH			0x502c +# define GPIO_CLOCK_DIR_MASK		(1 << 0) +# define GPIO_CLOCK_DIR_IN		(0 << 1) +# define GPIO_CLOCK_DIR_OUT		(1 << 1) +# define GPIO_CLOCK_VAL_MASK		(1 << 2) +# define GPIO_CLOCK_VAL_OUT		(1 << 3) +# define GPIO_CLOCK_VAL_IN		(1 << 4) +# define GPIO_CLOCK_PULLUP_DISABLE	(1 << 5) +# define GPIO_DATA_DIR_MASK		(1 << 8) +# define GPIO_DATA_DIR_IN		(0 << 9) +# define GPIO_DATA_DIR_OUT		(1 << 9) +# define GPIO_DATA_VAL_MASK		(1 << 10) +# define GPIO_DATA_VAL_OUT		(1 << 11) +# define GPIO_DATA_VAL_IN		(1 << 12) +# define GPIO_DATA_PULLUP_DISABLE	(1 << 13) + +/* p317, 319 + */ +#define VCLK2_VCO_M        0x6008 /* treat as 16 bit? (includes msbs) */ +#define VCLK2_VCO_N        0x600a +#define VCLK2_VCO_DIV_SEL  0x6012 + +#define VCLK_DIVISOR_VGA0   0x6000 +#define VCLK_DIVISOR_VGA1   0x6004 +#define VCLK_POST_DIV	    0x6010 +/** Selects a post divisor of 4 instead of 2. */ +# define VGA1_PD_P2_DIV_4	(1 << 15) +/** Overrides the p2 post divisor field */ +# define VGA1_PD_P1_DIV_2	(1 << 13) +# define VGA1_PD_P1_SHIFT	8 +/** P1 value is 2 greater than this field */ +# define VGA1_PD_P1_MASK	(0x1f << 8) +/** Selects a post divisor of 4 instead of 2. */ +# define VGA0_PD_P2_DIV_4	(1 << 7) +/** Overrides the p2 post divisor field */ +# define VGA0_PD_P1_DIV_2	(1 << 5) +# define VGA0_PD_P1_SHIFT	0 +/** P1 value is 2 greater than this field */ +# define VGA0_PD_P1_MASK	(0x1f << 0) + +#define POST_DIV_SELECT        0x70 +#define POST_DIV_1             0x00 +#define POST_DIV_2             0x10 +#define POST_DIV_4             0x20 +#define POST_DIV_8             0x30 +#define POST_DIV_16            0x40 +#define POST_DIV_32            0x50 +#define VCO_LOOP_DIV_BY_4M     0x00 +#define VCO_LOOP_DIV_BY_16M    0x04 +  #define SRX_INDEX		0x3c4  #define SRX_DATA		0x3c5  #define SR01			1 @@ -524,6 +634,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);  #define PPCR			0x61204  #define PPCR_ON			(1<<0) +#define DVOA			0x61120 +#define DVOA_ON			(1<<31)  #define DVOB			0x61140  #define DVOB_ON			(1<<31)  #define DVOC			0x61160 @@ -685,8 +797,14 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);  #define SRC_COPY_BLT_CMD                ((2<<29)|(0x43<<22)|4)  #define XY_SRC_COPY_BLT_CMD		((2<<29)|(0x53<<22)|6) +#define XY_MONO_SRC_COPY_IMM_BLT	((2<<29)|(0x71<<22)|5)  #define XY_SRC_COPY_BLT_WRITE_ALPHA	(1<<21)  #define XY_SRC_COPY_BLT_WRITE_RGB	(1<<20) +#define   BLT_DEPTH_8			(0<<24) +#define   BLT_DEPTH_16_565		(1<<24) +#define   BLT_DEPTH_16_1555		(2<<24) +#define   BLT_DEPTH_32			(3<<24) +#define   BLT_ROP_GXCOPY		(0xcc<<16)  #define MI_BATCH_BUFFER		((0x30<<23)|1)  #define MI_BATCH_BUFFER_START	(0x31<<23) @@ -728,6 +846,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);  #define BACKLIGHT_MODULATION_FREQ_SHIFT		(17)  #define BLC_PWM_CTL2		0x61250 +  /**   * This is the most significant 15 bits of the number of backlight cycles in a   * complete cycle of the modulated backlight control. @@ -1086,6 +1205,579 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);  # define LVDS_B0B3_POWER_DOWN		(0 << 2)  # define LVDS_B0B3_POWER_UP		(3 << 2) +#define TV_CTL			0x68000 +/** Enables the TV encoder */ +# define TV_ENC_ENABLE			(1 << 31) +/** Sources the TV encoder input from pipe B instead of A. */ +# define TV_ENC_PIPEB_SELECT		(1 << 30) +/** Outputs composite video (DAC A only) */ +# define TV_ENC_OUTPUT_COMPOSITE	(0 << 28) +/** Outputs SVideo video (DAC B/C) */ +# define TV_ENC_OUTPUT_SVIDEO		(1 << 28) +/** Outputs Component video (DAC A/B/C) */ +# define TV_ENC_OUTPUT_COMPONENT	(2 << 28) +/** Outputs Composite and SVideo (DAC A/B/C) */ +# define TV_ENC_OUTPUT_SVIDEO_COMPOSITE	(3 << 28) +# define TV_TRILEVEL_SYNC		(1 << 21) +/** Enables slow sync generation (945GM only) */ +# define TV_SLOW_SYNC			(1 << 20) +/** Selects 4x oversampling for 480i and 576p */ +# define TV_OVERSAMPLE_4X		(0 << 18) +/** Selects 2x oversampling for 720p and 1080i */ +# define TV_OVERSAMPLE_2X		(1 << 18) +/** Selects no oversampling for 1080p */ +# define TV_OVERSAMPLE_NONE		(2 << 18) +/** Selects 8x oversampling */ +# define TV_OVERSAMPLE_8X		(3 << 18) +/** Selects progressive mode rather than interlaced */ +# define TV_PROGRESSIVE			(1 << 17) +/** Sets the colorburst to PAL mode.  Required for non-M PAL modes. */ +# define TV_PAL_BURST			(1 << 16) +/** Field for setting delay of Y compared to C */ +# define TV_YC_SKEW_MASK		(7 << 12) +/** Enables a fix for 480p/576p standard definition modes on the 915GM only */ +# define TV_ENC_SDP_FIX			(1 << 11) +/** + * Enables a fix for the 915GM only. + * + * Not sure what it does. + */ +# define TV_ENC_C0_FIX			(1 << 10) +/** Bits that must be preserved by software */ +# define TV_CTL_SAVE			((3 << 8) | (3 << 6)) +# define TV_FUSE_STATE_MASK		(3 << 4) +/** Read-only state that reports all features enabled */ +# define TV_FUSE_STATE_ENABLED		(0 << 4) +/** Read-only state that reports that Macrovision is disabled in hardware*/ +# define TV_FUSE_STATE_NO_MACROVISION	(1 << 4) +/** Read-only state that reports that TV-out is disabled in hardware. */ +# define TV_FUSE_STATE_DISABLED		(2 << 4) +/** Normal operation */ +# define TV_TEST_MODE_NORMAL		(0 << 0) +/** Encoder test pattern 1 - combo pattern */ +# define TV_TEST_MODE_PATTERN_1		(1 << 0) +/** Encoder test pattern 2 - full screen vertical 75% color bars */ +# define TV_TEST_MODE_PATTERN_2		(2 << 0) +/** Encoder test pattern 3 - full screen horizontal 75% color bars */ +# define TV_TEST_MODE_PATTERN_3		(3 << 0) +/** Encoder test pattern 4 - random noise */ +# define TV_TEST_MODE_PATTERN_4		(4 << 0) +/** Encoder test pattern 5 - linear color ramps */ +# define TV_TEST_MODE_PATTERN_5		(5 << 0) +/** + * This test mode forces the DACs to 50% of full output. + * + * This is used for load detection in combination with TVDAC_SENSE_MASK + */ +# define TV_TEST_MODE_MONITOR_DETECT	(7 << 0) +# define TV_TEST_MODE_MASK		(7 << 0) +/** @} */ + +/** @defgroup TV_DAC + * @{ + */ +#define TV_DAC			0x68004 +/** + * Reports that DAC state change logic has reported change (RO). + * + * This gets cleared when TV_DAC_STATE_EN is cleared +*/ +# define TVDAC_STATE_CHG		(1 << 31) +# define TVDAC_SENSE_MASK		(7 << 28) +/** Reports that DAC A voltage is above the detect threshold */ +# define TVDAC_A_SENSE			(1 << 30) +/** Reports that DAC B voltage is above the detect threshold */ +# define TVDAC_B_SENSE			(1 << 29) +/** Reports that DAC C voltage is above the detect threshold */ +# define TVDAC_C_SENSE			(1 << 28) +/** + * Enables DAC state detection logic, for load-based TV detection. + * + * The PLL of the chosen pipe (in TV_CTL) must be running, and the encoder set + * to off, for load detection to work. + */ +# define TVDAC_STATE_CHG_EN		(1 << 27) +/** Sets the DAC A sense value to high */ +# define TVDAC_A_SENSE_CTL		(1 << 26) +/** Sets the DAC B sense value to high */ +# define TVDAC_B_SENSE_CTL		(1 << 25) +/** Sets the DAC C sense value to high */ +# define TVDAC_C_SENSE_CTL		(1 << 24) +/** Overrides the ENC_ENABLE and DAC voltage levels */ +# define DAC_CTL_OVERRIDE		(1 << 7) +/** Sets the slew rate.  Must be preserved in software */ +# define ENC_TVDAC_SLEW_FAST		(1 << 6) +# define DAC_A_1_3_V			(0 << 4) +# define DAC_A_1_1_V			(1 << 4) +# define DAC_A_0_7_V			(2 << 4) +# define DAC_A_OFF			(3 << 4) +# define DAC_B_1_3_V			(0 << 2) +# define DAC_B_1_1_V			(1 << 2) +# define DAC_B_0_7_V			(2 << 2) +# define DAC_B_OFF			(3 << 2) +# define DAC_C_1_3_V			(0 << 0) +# define DAC_C_1_1_V			(1 << 0) +# define DAC_C_0_7_V			(2 << 0) +# define DAC_C_OFF			(3 << 0) +/** @} */ + +/** + * CSC coefficients are stored in a floating point format with 9 bits of + * mantissa and 2 or 3 bits of exponent.  The exponent is represented as 2**-n, + * where 2-bit exponents are unsigned n, and 3-bit exponents are signed n with + * -1 (0x3) being the only legal negative value. + */ +#define TV_CSC_Y		0x68010 +# define TV_RY_MASK			0x07ff0000 +# define TV_RY_SHIFT			16 +# define TV_GY_MASK			0x00000fff +# define TV_GY_SHIFT			0 + +#define TV_CSC_Y2		0x68014 +# define TV_BY_MASK			0x07ff0000 +# define TV_BY_SHIFT			16 +/** + * Y attenuation for component video. + * + * Stored in 1.9 fixed point. + */ +# define TV_AY_MASK			0x000003ff +# define TV_AY_SHIFT			0 + +#define TV_CSC_U		0x68018 +# define TV_RU_MASK			0x07ff0000 +# define TV_RU_SHIFT			16 +# define TV_GU_MASK			0x000007ff +# define TV_GU_SHIFT			0 + +#define TV_CSC_U2		0x6801c +# define TV_BU_MASK			0x07ff0000 +# define TV_BU_SHIFT			16 +/** + * U attenuation for component video. + * + * Stored in 1.9 fixed point. + */ +# define TV_AU_MASK			0x000003ff +# define TV_AU_SHIFT			0 + +#define TV_CSC_V		0x68020 +# define TV_RV_MASK			0x0fff0000 +# define TV_RV_SHIFT			16 +# define TV_GV_MASK			0x000007ff +# define TV_GV_SHIFT			0 + +#define TV_CSC_V2		0x68024 +# define TV_BV_MASK			0x07ff0000 +# define TV_BV_SHIFT			16 +/** + * V attenuation for component video. + * + * Stored in 1.9 fixed point. + */ +# define TV_AV_MASK			0x000007ff +# define TV_AV_SHIFT			0 + +/** @defgroup TV_CSC_KNOBS + * @{ + */ +#define TV_CLR_KNOBS		0x68028 +/** 2s-complement brightness adjustment */ +# define TV_BRIGHTNESS_MASK		0xff000000 +# define TV_BRIGHTNESS_SHIFT		24 +/** Contrast adjustment, as a 2.6 unsigned floating point number */ +# define TV_CONTRAST_MASK		0x00ff0000 +# define TV_CONTRAST_SHIFT		16 +/** Saturation adjustment, as a 2.6 unsigned floating point number */ +# define TV_SATURATION_MASK		0x0000ff00 +# define TV_SATURATION_SHIFT		8 +/** Hue adjustment, as an integer phase angle in degrees */ +# define TV_HUE_MASK			0x000000ff +# define TV_HUE_SHIFT			0 +/** @} */ + +/** @defgroup TV_CLR_LEVEL + * @{ + */ +#define TV_CLR_LEVEL		0x6802c +/** Controls the DAC level for black */ +# define TV_BLACK_LEVEL_MASK		0x01ff0000 +# define TV_BLACK_LEVEL_SHIFT		16 +/** Controls the DAC level for blanking */ +# define TV_BLANK_LEVEL_MASK		0x000001ff +# define TV_BLANK_LEVEL_SHIFT		0 +/* @} */ + +/** @defgroup TV_H_CTL_1 + * @{ + */ +#define TV_H_CTL_1		0x68030 +/** Number of pixels in the hsync. */ +# define TV_HSYNC_END_MASK		0x1fff0000 +# define TV_HSYNC_END_SHIFT		16 +/** Total number of pixels minus one in the line (display and blanking). */ +# define TV_HTOTAL_MASK			0x00001fff +# define TV_HTOTAL_SHIFT		0 +/** @} */ + +/** @defgroup TV_H_CTL_2 + * @{ + */ +#define TV_H_CTL_2		0x68034 +/** Enables the colorburst (needed for non-component color) */ +# define TV_BURST_ENA			(1 << 31) +/** Offset of the colorburst from the start of hsync, in pixels minus one. */ +# define TV_HBURST_START_SHIFT		16 +# define TV_HBURST_START_MASK		0x1fff0000 +/** Length of the colorburst */ +# define TV_HBURST_LEN_SHIFT		0 +# define TV_HBURST_LEN_MASK		0x0001fff +/** @} */ + +/** @defgroup TV_H_CTL_3 + * @{ + */ +#define TV_H_CTL_3		0x68038 +/** End of hblank, measured in pixels minus one from start of hsync */ +# define TV_HBLANK_END_SHIFT		16 +# define TV_HBLANK_END_MASK		0x1fff0000 +/** Start of hblank, measured in pixels minus one from start of hsync */ +# define TV_HBLANK_START_SHIFT		0 +# define TV_HBLANK_START_MASK		0x0001fff +/** @} */ + +/** @defgroup TV_V_CTL_1 + * @{ + */ +#define TV_V_CTL_1		0x6803c +/** XXX */ +# define TV_NBR_END_SHIFT		16 +# define TV_NBR_END_MASK		0x07ff0000 +/** XXX */ +# define TV_VI_END_F1_SHIFT		8 +# define TV_VI_END_F1_MASK		0x00003f00 +/** XXX */ +# define TV_VI_END_F2_SHIFT		0 +# define TV_VI_END_F2_MASK		0x0000003f +/** @} */ + +/** @defgroup TV_V_CTL_2 + * @{ + */ +#define TV_V_CTL_2		0x68040 +/** Length of vsync, in half lines */ +# define TV_VSYNC_LEN_MASK		0x07ff0000 +# define TV_VSYNC_LEN_SHIFT		16 +/** Offset of the start of vsync in field 1, measured in one less than the + * number of half lines. + */ +# define TV_VSYNC_START_F1_MASK		0x00007f00 +# define TV_VSYNC_START_F1_SHIFT	8 +/** + * Offset of the start of vsync in field 2, measured in one less than the + * number of half lines. + */ +# define TV_VSYNC_START_F2_MASK		0x0000007f +# define TV_VSYNC_START_F2_SHIFT	0 +/** @} */ + +/** @defgroup TV_V_CTL_3 + * @{ + */ +#define TV_V_CTL_3		0x68044 +/** Enables generation of the equalization signal */ +# define TV_EQUAL_ENA			(1 << 31) +/** Length of vsync, in half lines */ +# define TV_VEQ_LEN_MASK		0x007f0000 +# define TV_VEQ_LEN_SHIFT		16 +/** Offset of the start of equalization in field 1, measured in one less than + * the number of half lines. + */ +# define TV_VEQ_START_F1_MASK		0x0007f00 +# define TV_VEQ_START_F1_SHIFT		8 +/** + * Offset of the start of equalization in field 2, measured in one less than + * the number of half lines. + */ +# define TV_VEQ_START_F2_MASK		0x000007f +# define TV_VEQ_START_F2_SHIFT		0 +/** @} */ + +/** @defgroup TV_V_CTL_4 + * @{ + */ +#define TV_V_CTL_4		0x68048 +/** + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F1_MASK	0x003f0000 +# define TV_VBURST_START_F1_SHIFT	16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F1_MASK		0x000000ff +# define TV_VBURST_END_F1_SHIFT		0 +/** @} */ + +/** @defgroup TV_V_CTL_5 + * @{ + */ +#define TV_V_CTL_5		0x6804c +/** + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F2_MASK	0x003f0000 +# define TV_VBURST_START_F2_SHIFT	16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F2_MASK		0x000000ff +# define TV_VBURST_END_F2_SHIFT		0 +/** @} */ + +/** @defgroup TV_V_CTL_6 + * @{ + */ +#define TV_V_CTL_6		0x68050 +/** + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F3_MASK	0x003f0000 +# define TV_VBURST_START_F3_SHIFT	16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F3_MASK		0x000000ff +# define TV_VBURST_END_F3_SHIFT		0 +/** @} */ + +/** @defgroup TV_V_CTL_7 + * @{ + */ +#define TV_V_CTL_7		0x68054 +/** + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F4_MASK	0x003f0000 +# define TV_VBURST_START_F4_SHIFT	16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F4_MASK		0x000000ff +# define TV_VBURST_END_F4_SHIFT		0 +/** @} */ + +/** @defgroup TV_SC_CTL_1 + * @{ + */ +#define TV_SC_CTL_1		0x68060 +/** Turns on the first subcarrier phase generation DDA */ +# define TV_SC_DDA1_EN			(1 << 31) +/** Turns on the first subcarrier phase generation DDA */ +# define TV_SC_DDA2_EN			(1 << 30) +/** Turns on the first subcarrier phase generation DDA */ +# define TV_SC_DDA3_EN			(1 << 29) +/** Sets the subcarrier DDA to reset frequency every other field */ +# define TV_SC_RESET_EVERY_2		(0 << 24) +/** Sets the subcarrier DDA to reset frequency every fourth field */ +# define TV_SC_RESET_EVERY_4		(1 << 24) +/** Sets the subcarrier DDA to reset frequency every eighth field */ +# define TV_SC_RESET_EVERY_8		(2 << 24) +/** Sets the subcarrier DDA to never reset the frequency */ +# define TV_SC_RESET_NEVER		(3 << 24) +/** Sets the peak amplitude of the colorburst.*/ +# define TV_BURST_LEVEL_MASK		0x00ff0000 +# define TV_BURST_LEVEL_SHIFT		16 +/** Sets the increment of the first subcarrier phase generation DDA */ +# define TV_SCDDA1_INC_MASK		0x00000fff +# define TV_SCDDA1_INC_SHIFT		0 +/** @} */ + +/** @defgroup TV_SC_CTL_2 + * @{ + */ +#define TV_SC_CTL_2		0x68064 +/** Sets the rollover for the second subcarrier phase generation DDA */ +# define TV_SCDDA2_SIZE_MASK		0x7fff0000 +# define TV_SCDDA2_SIZE_SHIFT		16 +/** Sets the increent of the second subcarrier phase generation DDA */ +# define TV_SCDDA2_INC_MASK		0x00007fff +# define TV_SCDDA2_INC_SHIFT		0 +/** @} */ + +/** @defgroup TV_SC_CTL_3 + * @{ + */ +#define TV_SC_CTL_3		0x68068 +/** Sets the rollover for the third subcarrier phase generation DDA */ +# define TV_SCDDA3_SIZE_MASK		0x7fff0000 +# define TV_SCDDA3_SIZE_SHIFT		16 +/** Sets the increent of the third subcarrier phase generation DDA */ +# define TV_SCDDA3_INC_MASK		0x00007fff +# define TV_SCDDA3_INC_SHIFT		0 +/** @} */ + +/** @defgroup TV_WIN_POS + * @{ + */ +#define TV_WIN_POS		0x68070 +/** X coordinate of the display from the start of horizontal active */ +# define TV_XPOS_MASK			0x1fff0000 +# define TV_XPOS_SHIFT			16 +/** Y coordinate of the display from the start of vertical active (NBR) */ +# define TV_YPOS_MASK			0x00000fff +# define TV_YPOS_SHIFT			0 +/** @} */ + +/** @defgroup TV_WIN_SIZE + * @{ + */ +#define TV_WIN_SIZE		0x68074 +/** Horizontal size of the display window, measured in pixels*/ +# define TV_XSIZE_MASK			0x1fff0000 +# define TV_XSIZE_SHIFT			16 +/** + * Vertical size of the display window, measured in pixels. + * + * Must be even for interlaced modes. + */ +# define TV_YSIZE_MASK			0x00000fff +# define TV_YSIZE_SHIFT			0 +/** @} */ + +/** @defgroup TV_FILTER_CTL_1 + * @{ + */ +#define TV_FILTER_CTL_1		0x68080 +/** + * Enables automatic scaling calculation. + * + * If set, the rest of the registers are ignored, and the calculated values can + * be read back from the register. + */ +# define TV_AUTO_SCALE			(1 << 31) +/** + * Disables the vertical filter. + * + * This is required on modes more than 1024 pixels wide */ +# define TV_V_FILTER_BYPASS		(1 << 29) +/** Enables adaptive vertical filtering */ +# define TV_VADAPT			(1 << 28) +# define TV_VADAPT_MODE_MASK		(3 << 26) +/** Selects the least adaptive vertical filtering mode */ +# define TV_VADAPT_MODE_LEAST		(0 << 26) +/** Selects the moderately adaptive vertical filtering mode */ +# define TV_VADAPT_MODE_MODERATE	(1 << 26) +/** Selects the most adaptive vertical filtering mode */ +# define TV_VADAPT_MODE_MOST		(3 << 26) +/** + * Sets the horizontal scaling factor. + * + * This should be the fractional part of the horizontal scaling factor divided + * by the oversampling rate.  TV_HSCALE should be less than 1, and set to: + * + * (src width - 1) / ((oversample * dest width) - 1) + */ +# define TV_HSCALE_FRAC_MASK		0x00003fff +# define TV_HSCALE_FRAC_SHIFT		0 +/** @} */ + +/** @defgroup TV_FILTER_CTL_2 + * @{ + */ +#define TV_FILTER_CTL_2		0x68084 +/** + * Sets the integer part of the 3.15 fixed-point vertical scaling factor. + * + * TV_VSCALE should be (src height - 1) / ((interlace * dest height) - 1) + */ +# define TV_VSCALE_INT_MASK		0x00038000 +# define TV_VSCALE_INT_SHIFT		15 +/** + * Sets the fractional part of the 3.15 fixed-point vertical scaling factor. + * + * \sa TV_VSCALE_INT_MASK + */ +# define TV_VSCALE_FRAC_MASK		0x00007fff +# define TV_VSCALE_FRAC_SHIFT		0 +/** @} */ + +/** @defgroup TV_FILTER_CTL_3 + * @{ + */ +#define TV_FILTER_CTL_3		0x68088 +/** + * Sets the integer part of the 3.15 fixed-point vertical scaling factor. + * + * TV_VSCALE should be (src height - 1) / (1/4 * (dest height - 1)) + * + * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes. + */ +# define TV_VSCALE_IP_INT_MASK		0x00038000 +# define TV_VSCALE_IP_INT_SHIFT		15 +/** + * Sets the fractional part of the 3.15 fixed-point vertical scaling factor. + * + * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes. + * + * \sa TV_VSCALE_IP_INT_MASK + */ +# define TV_VSCALE_IP_FRAC_MASK		0x00007fff +# define TV_VSCALE_IP_FRAC_SHIFT		0 +/** @} */ + +/** @defgroup TV_CC_CONTROL + * @{ + */ +#define TV_CC_CONTROL		0x68090 +# define TV_CC_ENABLE			(1 << 31) +/** + * Specifies which field to send the CC data in. + * + * CC data is usually sent in field 0. + */ +# define TV_CC_FID_MASK			(1 << 27) +# define TV_CC_FID_SHIFT		27 +/** Sets the horizontal position of the CC data.  Usually 135. */ +# define TV_CC_HOFF_MASK		0x03ff0000 +# define TV_CC_HOFF_SHIFT		16 +/** Sets the vertical position of the CC data.  Usually 21 */ +# define TV_CC_LINE_MASK		0x0000003f +# define TV_CC_LINE_SHIFT		0 +/** @} */ + +/** @defgroup TV_CC_DATA + * @{ + */ +#define TV_CC_DATA		0x68094 +# define TV_CC_RDY			(1 << 31) +/** Second word of CC data to be transmitted. */ +# define TV_CC_DATA_2_MASK		0x007f0000 +# define TV_CC_DATA_2_SHIFT		16 +/** First word of CC data to be transmitted. */ +# define TV_CC_DATA_1_MASK		0x0000007f +# define TV_CC_DATA_1_SHIFT		0 +/** @} + */ + +/** @{ */ +#define TV_H_LUMA_0		0x68100 +#define TV_H_LUMA_59		0x681ec +#define TV_H_CHROMA_0		0x68200 +#define TV_H_CHROMA_59		0x682ec +#define TV_V_LUMA_0		0x68300 +#define TV_V_LUMA_42		0x683a8 +#define TV_V_CHROMA_0		0x68400 +#define TV_V_CHROMA_42		0x684a8 +  #define PIPEACONF 0x70008  #define PIPEACONF_ENABLE	(1<<31)  #define PIPEACONF_DISABLE	0 @@ -1177,13 +1869,17 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);   */  #define SWF0			0x71410 +#define SWF1			0x71414 +#define SWF2			0x71418 +#define SWF3			0x7141c +#define SWF4			0x71420 +#define SWF5			0x71424 +#define SWF6			0x71428 -/* - * 855 scratch registers. - */  #define SWF10			0x70410 -  #define SWF30			0x72414 +#define SWF31			0x72418 +#define SWF32			0x7241c  /*   * Overlay registers.  These are overlay registers accessed via MMIO. @@ -1200,6 +1896,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);  #define OGAMC2			0x3001c  #define OGAMC1			0x30020  #define OGAMC0			0x30024 +  /*   * Palette registers   */ diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c new file mode 100644 index 00000000..c2d8964e --- /dev/null +++ b/shared-core/i915_init.c @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2007 Intel Corporation + *   Jesse Barnes <jesse.barnes@intel.com> + * + * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org> + *                   2004 Sylvain Meyer + * + * GPL/BSD dual license + */ +#include "drmP.h" +#include "drm.h" +#include "drm_sarea.h" +#include "i915_drm.h" +#include "i915_drv.h" + +/** + * i915_probe_agp - get AGP bootup configuration + * @pdev: PCI device + * @aperture_size: returns AGP aperture configured size + * @preallocated_size: returns size of BIOS preallocated AGP space + * + * Since Intel integrated graphics are UMA, the BIOS has to set aside + * some RAM for the framebuffer at early boot.  This code figures out + * how much was set aside so we can use it for our own purposes. + */ +int i915_probe_agp(struct pci_dev *pdev, unsigned long *aperture_size, +		   unsigned long *preallocated_size) +{ +	struct pci_dev *bridge_dev; +	u16 tmp = 0; +	unsigned long overhead; + +	bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); +	if (!bridge_dev) { +		DRM_ERROR("bridge device not found\n"); +		return -1; +	} + +	/* Get the fb aperture size and "stolen" memory amount. */ +	pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp); +	pci_dev_put(bridge_dev); + +	*aperture_size = 1024 * 1024; +	*preallocated_size = 1024 * 1024; + +	switch (pdev->device) { +	case PCI_DEVICE_ID_INTEL_82830_CGC: +	case PCI_DEVICE_ID_INTEL_82845G_IG: +	case PCI_DEVICE_ID_INTEL_82855GM_IG: +	case PCI_DEVICE_ID_INTEL_82865_IG: +		if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M) +			*aperture_size *= 64; +		else +			*aperture_size *= 128; +		break; +	default: +		/* 9xx supports large sizes, just look at the length */ +		*aperture_size = pci_resource_len(pdev, 2); +		break; +	} + +	/* +	 * Some of the preallocated space is taken by the GTT +	 * and popup.  GTT is 1K per MB of aperture size, and popup is 4K. +	 */ +	overhead = (*aperture_size / 1024) + 4096; +	switch (tmp & INTEL_855_GMCH_GMS_MASK) { +	case INTEL_855_GMCH_GMS_STOLEN_1M: +		break; /* 1M already */ +	case INTEL_855_GMCH_GMS_STOLEN_4M: +		*preallocated_size *= 4; +		break; +	case INTEL_855_GMCH_GMS_STOLEN_8M: +		*preallocated_size *= 8; +		break; +	case INTEL_855_GMCH_GMS_STOLEN_16M: +		*preallocated_size *= 16; +		break; +	case INTEL_855_GMCH_GMS_STOLEN_32M: +		*preallocated_size *= 32; +		break; +	case INTEL_915G_GMCH_GMS_STOLEN_48M: +		*preallocated_size *= 48; +		break; +	case INTEL_915G_GMCH_GMS_STOLEN_64M: +		*preallocated_size *= 64; +		break; +	case INTEL_855_GMCH_GMS_DISABLED: +		DRM_ERROR("video memory is disabled\n"); +		return -1; +	default: +		DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n", +			tmp & INTEL_855_GMCH_GMS_MASK); +		return -1; +	} +	*preallocated_size -= overhead; + +	return 0; +} + +/** + * i915_driver_load - setup chip and create an initial config + * @dev: DRM device + * @flags: startup flags + * + * The driver load routine has to do several things: + *   - drive output discovery via intel_modeset_init() + *   - initialize the memory manager + *   - allocate initial config memory + *   - setup the DRM framebuffer with the allocated memory + */ +int i915_driver_load(struct drm_device *dev, unsigned long flags) +{ +	struct drm_i915_private *dev_priv; +	unsigned long agp_size, prealloc_size; +	int size, ret; + +	dev_priv = drm_alloc(sizeof(struct drm_i915_private), DRM_MEM_DRIVER); +	if (dev_priv == NULL) +		return -ENOMEM; + +	memset(dev_priv, 0, sizeof(struct drm_i915_private)); +	dev->dev_private = (void *)dev_priv; +//	dev_priv->flags = flags; + +	/* i915 has 4 more counters */ +	dev->counters += 4; +	dev->types[6] = _DRM_STAT_IRQ; +	dev->types[7] = _DRM_STAT_PRIMARY; +	dev->types[8] = _DRM_STAT_SECONDARY; +	dev->types[9] = _DRM_STAT_DMA; + +	if (IS_I9XX(dev)) { +		pci_read_config_dword(dev->pdev, 0x5C, &dev_priv->stolen_base); +		DRM_DEBUG("stolen base %p\n", (void*)dev_priv->stolen_base); +	} + +	if (IS_I9XX(dev)) { +		dev_priv->mmiobase = drm_get_resource_start(dev, 0); +		dev_priv->mmiolen = drm_get_resource_len(dev, 0); +		dev->mode_config.fb_base = +			drm_get_resource_start(dev, 2) & 0xff000000; +	} else if (drm_get_resource_start(dev, 1)) { +		dev_priv->mmiobase = drm_get_resource_start(dev, 1); +		dev_priv->mmiolen = drm_get_resource_len(dev, 1); +		dev->mode_config.fb_base = +			drm_get_resource_start(dev, 0) & 0xff000000; +	} else { +		DRM_ERROR("Unable to find MMIO registers\n"); +		return -ENODEV; +	} + +	DRM_DEBUG("fb_base: 0x%08lx\n", dev->mode_config.fb_base); + +	ret = drm_addmap(dev, dev_priv->mmiobase, dev_priv->mmiolen, +			 _DRM_REGISTERS, _DRM_READ_ONLY|_DRM_DRIVER, &dev_priv->mmio_map); +	if (ret != 0) { +		DRM_ERROR("Cannot add mapping for MMIO registers\n"); +		return ret; +	} + +	/* +	 * Initialize the memory manager for local and AGP space +	 */ +	drm_bo_driver_init(dev); + +	i915_probe_agp(dev->pdev, &agp_size, &prealloc_size); +	printk("setting up %ld bytes of VRAM space\n", prealloc_size); +	printk("setting up %ld bytes of TT space\n", (agp_size - prealloc_size)); +	drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, prealloc_size >> PAGE_SHIFT); +	drm_bo_init_mm(dev, DRM_BO_MEM_TT, prealloc_size >> PAGE_SHIFT, (agp_size - prealloc_size) >> PAGE_SHIFT); + +	I915_WRITE(LP_RING + RING_LEN, 0); +	I915_WRITE(LP_RING + RING_HEAD, 0); +	I915_WRITE(LP_RING + RING_TAIL, 0); + +	size = PRIMARY_RINGBUFFER_SIZE; +	ret = drm_buffer_object_create(dev, size, drm_bo_type_kernel, +				       DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | +				       DRM_BO_FLAG_MEM_VRAM | +				       DRM_BO_FLAG_NO_EVICT, +				       DRM_BO_HINT_DONT_FENCE, 0x1, 0, +				       &dev_priv->ring_buffer); +	if (ret < 0) { +		DRM_ERROR("Unable to allocate or pin ring buffer\n"); +		return -EINVAL; +	} + +	/* remap the buffer object properly */ +	dev_priv->ring.Start = dev_priv->ring_buffer->offset; +	dev_priv->ring.End = dev_priv->ring.Start + size; +	dev_priv->ring.Size = size; +	dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; + +	/* FIXME: need wrapper with PCI mem checks */ +	ret = drm_mem_reg_ioremap(dev, &dev_priv->ring_buffer->mem, +				  (void **) &dev_priv->ring.virtual_start); +	if (ret) +		DRM_ERROR("error mapping ring buffer: %d\n", ret); + +	DRM_DEBUG("ring start %08lX, %p, %08lX\n", dev_priv->ring.Start, +		  dev_priv->ring.virtual_start, dev_priv->ring.Size); + +	// + +	memset((void *)(dev_priv->ring.virtual_start), 0, dev_priv->ring.Size); + +	I915_WRITE(LP_RING + RING_START, dev_priv->ring.Start); +	I915_WRITE(LP_RING + RING_LEN, +		   ((dev_priv->ring.Size - 4096) & RING_NR_PAGES) | +		   (RING_NO_REPORT | RING_VALID)); + +	/* We are using separate values as placeholders for mechanisms for +	 * private backbuffer/depthbuffer usage. +	 */ +	dev_priv->use_mi_batchbuffer_start = 0; + +	/* Allow hardware batchbuffers unless told otherwise. +	 */ +	dev_priv->allow_batchbuffer = 1; + +	/* Program Hardware Status Page */ +	if (!IS_G33(dev)) { +		dev_priv->status_page_dmah =  +			drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); + +		if (!dev_priv->status_page_dmah) { +			dev->dev_private = (void *)dev_priv; +			i915_dma_cleanup(dev); +			DRM_ERROR("Can not allocate hardware status page\n"); +			return -ENOMEM; +		} +		dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; +		dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; + +		memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + +		I915_WRITE(I915REG_HWS_PGA, dev_priv->dma_status_page); +	} +	DRM_DEBUG("Enabled hardware status page\n"); + +	dev_priv->wq = create_singlethread_workqueue("i915"); +	if (dev_priv == 0) { +		DRM_DEBUG("Error\n"); +	} + + +	intel_modeset_init(dev); +	drm_initial_config(dev, false); + +	drm_mm_print(&dev->bm.man[DRM_BO_MEM_VRAM].manager, "VRAM"); +	drm_mm_print(&dev->bm.man[DRM_BO_MEM_TT].manager, "TT"); + +	drm_irq_install(dev); + +	return 0; +} + +int i915_driver_unload(struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; + +	I915_WRITE(LP_RING + RING_LEN, 0); + +	intel_modeset_cleanup(dev); + +#if 0 +	if (dev_priv->ring.virtual_start) { +		drm_core_ioremapfree(&dev_priv->ring.map, dev); +	} +#endif + +	if (dev_priv->status_page_dmah) { +		drm_pci_free(dev, dev_priv->status_page_dmah); +		dev_priv->status_page_dmah = NULL; +		dev_priv->hw_status_page = NULL; +		dev_priv->dma_status_page = 0; +		/* Need to rewrite hardware status page */ +		I915_WRITE(I915REG_HWS_PGA, 0x1ffff000); +	} + +	if (dev_priv->status_gfx_addr) { +		dev_priv->status_gfx_addr = 0; +		drm_core_ioremapfree(&dev_priv->hws_map, dev); +		I915_WRITE(I915REG_HWS_PGA, 0x1ffff000); +	} + +	drm_mem_reg_iounmap(dev, &dev_priv->ring_buffer->mem, +			    dev_priv->ring.virtual_start); + +	DRM_DEBUG("usage is %d\n", atomic_read(&dev_priv->ring_buffer->usage)); +	mutex_lock(&dev->struct_mutex); +	drm_bo_usage_deref_locked(&dev_priv->ring_buffer); + +	if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT)) { +		DRM_ERROR("Memory manager type 3 not clean. " +			  "Delaying takedown\n"); +	} +	if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM)) { +		DRM_ERROR("Memory manager type 3 not clean. " +			  "Delaying takedown\n"); +	} +	mutex_unlock(&dev->struct_mutex); + +	drm_bo_driver_finish(dev); + +        DRM_DEBUG("%p\n", dev_priv->mmio_map); +        drm_rmmap(dev, dev_priv->mmio_map); + +	drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + +	dev->dev_private = NULL; +	return 0; +} + +int i915_master_create(struct drm_device *dev, struct drm_master *master) +{ +	struct drm_i915_master_private *master_priv; +	unsigned long sareapage; +	int ret; + +	master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER); +	if (!master_priv) +		return -ENOMEM; + +	/* prebuild the SAREA */ +	sareapage = max(SAREA_MAX, PAGE_SIZE); +	ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK|_DRM_DRIVER, +			 &master_priv->sarea); +	if (ret) { +		DRM_ERROR("SAREA setup failed\n"); +		return ret; +	} +	master_priv->sarea_priv = master_priv->sarea->handle + sizeof(struct drm_sarea); +	master_priv->sarea_priv->pf_current_page = 0; + +	master->driver_priv = master_priv; +	return 0; +} + +void i915_master_destroy(struct drm_device *dev, struct drm_master *master) +{ +	struct drm_i915_master_private *master_priv = master->driver_priv; + +	if (!master_priv) +		return; + +        drm_rmmap(dev, master_priv->sarea); +	drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER); + +	master->driver_priv = NULL; +} diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index fd08b6e8..dad6ef86 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -31,9 +31,12 @@  #include "i915_drm.h"  #include "i915_drv.h" +#include "intel_drv.h" +  #define USER_INT_FLAG (1<<1)  #define VSYNC_PIPEB_FLAG (1<<5)  #define VSYNC_PIPEA_FLAG (1<<7) +#define HOTPLUG_FLAG (1 << 17)  #define MAX_NOPID ((u32)~0) @@ -49,7 +52,7 @@  static int  i915_get_pipe(struct drm_device *dev, int plane)  { -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;  	u32 dspcntr;  	dspcntr = plane ? I915_READ(DSPBCNTR) : I915_READ(DSPACNTR); @@ -86,7 +89,7 @@ i915_get_plane(struct drm_device *dev, int pipe)  static int  i915_pipe_enabled(struct drm_device *dev, int pipe)  { -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;  	unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF;  	if (I915_READ(pipeconf) & PIPEACONF_ENABLE) @@ -104,8 +107,8 @@ static void  i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw,  			 int plane)  { -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; -	drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; +	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; +	struct drm_i915_sarea *sarea_priv = master_priv->sarea_priv;  	u16 x1, y1, x2, y2;  	int pf_planes = 1 << plane; @@ -149,19 +152,19 @@ i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw,   */  static void i915_vblank_tasklet(struct drm_device *dev)  { -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; +	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;  	struct list_head *list, *tmp, hits, *hit;  	int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages;  	unsigned counter[2];  	struct drm_drawable_info *drw; -	drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; +	struct drm_i915_sarea *sarea_priv;  	u32 cpp = dev_priv->cpp,  offsets[3];  	u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD |  				XY_SRC_COPY_BLT_WRITE_ALPHA |  				XY_SRC_COPY_BLT_WRITE_RGB)  			     : XY_SRC_COPY_BLT_CMD; -	u32 pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) | -			  (cpp << 23) | (1 << 24); +	u32 pitchropcpp;  	RING_LOCALS;  	counter[0] = drm_vblank_count(dev, 0); @@ -182,13 +185,19 @@ static void i915_vblank_tasklet(struct drm_device *dev)  	/* Find buffer swaps scheduled for this vertical blank */  	list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { -		drm_i915_vbl_swap_t *vbl_swap = -			list_entry(list, drm_i915_vbl_swap_t, head); +		struct drm_i915_vbl_swap *vbl_swap = +			list_entry(list, struct drm_i915_vbl_swap, head);  		int pipe = i915_get_pipe(dev, vbl_swap->plane);  		if ((counter[pipe] - vbl_swap->sequence) > (1<<23))  			continue; +		master_priv = vbl_swap->minor->master->driver_priv; +		sarea_priv = master_priv->sarea_priv; +		 +		pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) | +			(cpp << 23) | (1 << 24); +  		list_del(list);  		dev_priv->swaps_pending--;  		drm_vblank_put(dev, pipe); @@ -206,8 +215,8 @@ static void i915_vblank_tasklet(struct drm_device *dev)  		}  		list_for_each(hit, &hits) { -			drm_i915_vbl_swap_t *swap_cmp = -				list_entry(hit, drm_i915_vbl_swap_t, head); +			struct drm_i915_vbl_swap *swap_cmp = +				list_entry(hit, struct drm_i915_vbl_swap, head);  			struct drm_drawable_info *drw_cmp =  				drm_get_drawable_info(dev, swap_cmp->drw_id); @@ -264,8 +273,8 @@ static void i915_vblank_tasklet(struct drm_device *dev)  			lower[0] = lower[1] = sarea_priv->height;  		list_for_each(hit, &hits) { -			drm_i915_vbl_swap_t *swap_hit = -				list_entry(hit, drm_i915_vbl_swap_t, head); +			struct drm_i915_vbl_swap *swap_hit = +				list_entry(hit, struct drm_i915_vbl_swap, head);  			struct drm_clip_rect *rect;  			int num_rects, plane, front, back;  			unsigned short top, bottom; @@ -303,7 +312,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)  			top = upper[plane];  			bottom = lower[plane]; -			front = (dev_priv->sarea_priv->pf_current_page >> +			front = (master_priv->sarea_priv->pf_current_page >>  				 (2 * plane)) & 0x3;  			back = (front + 1) % num_pages; @@ -333,8 +342,8 @@ static void i915_vblank_tasklet(struct drm_device *dev)  	DRM_SPINUNLOCK(&dev->drw_lock);  	list_for_each_safe(hit, tmp, &hits) { -		drm_i915_vbl_swap_t *swap_hit = -			list_entry(hit, drm_i915_vbl_swap_t, head); +		struct drm_i915_vbl_swap *swap_hit = +			list_entry(hit, struct drm_i915_vbl_swap, head);  		list_del(hit); @@ -344,7 +353,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)  #if 0  static int i915_in_vblank(struct drm_device *dev, int pipe)  { -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;  	unsigned long pipedsl, vblank, vtotal;  	unsigned long vbl_start, vbl_end, cur_line; @@ -365,7 +374,7 @@ static int i915_in_vblank(struct drm_device *dev, int pipe)  #endif  u32 i915_get_vblank_counter(struct drm_device *dev, int plane)  { -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;  	unsigned long high_frame;  	unsigned long low_frame;  	u32 high1, high2, low, count; @@ -409,24 +418,196 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane)  	return count;  } +#define HOTPLUG_CMD_CRT 1 +#define HOTPLUG_CMD_CRT_DIS 2 +#define HOTPLUG_CMD_SDVOB 4 +#define HOTPLUG_CMD_SDVOC 8 + +static struct drm_device *hotplug_dev; +static int hotplug_cmd = 0; +static spinlock_t hotplug_lock = SPIN_LOCK_UNLOCKED; + +static void i915_hotplug_crt(struct drm_device *dev, bool connected) +{ +	struct drm_output *output; +	struct intel_output *iout; + +	mutex_lock(&dev->mode_config.mutex); + +	/* find the crt output */ +	list_for_each_entry(output, &dev->mode_config.output_list, head) { +		iout = output->driver_private; +		if (iout->type == INTEL_OUTPUT_ANALOG) +			break; +		else +			iout = 0; +	} + +	if (iout == 0) +		goto unlock; + +	drm_hotplug_stage_two(dev, output, connected); + +unlock: +	mutex_unlock(&dev->mode_config.mutex); +} + +static void i915_hotplug_sdvo(struct drm_device *dev, int sdvoB) +{ +	struct drm_output *output = 0; +	enum drm_output_status status; + +	mutex_lock(&dev->mode_config.mutex); + +	output = intel_sdvo_find(dev, sdvoB); + +	if (!output) { +		DRM_ERROR("could not find sdvo%s output\n", sdvoB ? "B" : "C"); +		goto unlock; +	} + +	status = output->funcs->detect(output); + +	if (status != output_status_connected) +		drm_hotplug_stage_two(dev, output, false); +	else +		drm_hotplug_stage_two(dev, output, true); + +	/* wierd hw bug, sdvo stop sending interupts */ +	intel_sdvo_set_hotplug(output, 1); + +unlock: +	mutex_unlock(&dev->mode_config.mutex); +} +/* + * This code is called in a more safe envirmoent to handle the hotplugs. + * Add code here for hotplug love to userspace. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void i915_hotplug_work_func(void *work) +#else +static void i915_hotplug_work_func(struct work_struct *work) +#endif +{ +	struct drm_device *dev = hotplug_dev; +	int crt; +	int crtDis; +	int sdvoB; +	int sdvoC; + +	spin_lock(&hotplug_lock); +	crt = hotplug_cmd & HOTPLUG_CMD_CRT; +	crtDis = hotplug_cmd & HOTPLUG_CMD_CRT_DIS; +	sdvoB = hotplug_cmd & HOTPLUG_CMD_SDVOB; +	sdvoC = hotplug_cmd & HOTPLUG_CMD_SDVOC; +	hotplug_cmd = 0; +	spin_unlock(&hotplug_lock); + +	if (crt) +		i915_hotplug_crt(dev, true); +	if (crtDis) +		i915_hotplug_crt(dev, false); + +	if (sdvoB) +		i915_hotplug_sdvo(dev, 1); + +	if (sdvoC) +		i915_hotplug_sdvo(dev, 0); + +} + +static int i915_run_hotplug_tasklet(struct drm_device *dev, uint32_t stat) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +	static DECLARE_WORK(hotplug, i915_hotplug_work_func, NULL); +#else +	static DECLARE_WORK(hotplug, i915_hotplug_work_func); +#endif +	struct drm_i915_private *dev_priv = dev->dev_private; + +	hotplug_dev = dev; + +	if (stat & CRT_HOTPLUG_INT_STATUS) { +		DRM_DEBUG("CRT event\n"); + +		if (stat & CRT_HOTPLUG_MONITOR_MASK) { +			spin_lock(&hotplug_lock); +			hotplug_cmd |= HOTPLUG_CMD_CRT; +			spin_unlock(&hotplug_lock); +		} else { +			spin_lock(&hotplug_lock); +			hotplug_cmd |= HOTPLUG_CMD_CRT_DIS; +			spin_unlock(&hotplug_lock); +		} +	} + +	if (stat & SDVOB_HOTPLUG_INT_STATUS) { +		DRM_DEBUG("sDVOB event\n"); + +		spin_lock(&hotplug_lock); +		hotplug_cmd |= HOTPLUG_CMD_SDVOB; +		spin_unlock(&hotplug_lock); +	} + +	if (stat & SDVOC_HOTPLUG_INT_STATUS) { +		DRM_DEBUG("sDVOC event\n"); + +		spin_lock(&hotplug_lock); +		hotplug_cmd |= HOTPLUG_CMD_SDVOC; +		spin_unlock(&hotplug_lock); +	} + +	queue_work(dev_priv->wq, &hotplug); + +	return 0; +} +  irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)  {  	struct drm_device *dev = (struct drm_device *) arg; -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; -	u16 temp; +	struct drm_i915_master_private *master_priv; +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; +	u32 temp = 0; +	u32 temp2;  	u32 pipea_stats, pipeb_stats;  	pipea_stats = I915_READ(I915REG_PIPEASTAT);  	pipeb_stats = I915_READ(I915REG_PIPEBSTAT); -	temp = I915_READ16(I915REG_INT_IDENTITY_R); +	/* On i8xx hw the IIR and IER are 16bit on i9xx its 32bit */ +	if (IS_I9XX(dev)) +		temp = I915_READ(I915REG_INT_IDENTITY_R); +	else +		temp = I915_READ16(I915REG_INT_IDENTITY_R); + +	temp2 = temp; +	temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG);  #if 0 +	/* ugly despamification of pipeb event irq */ +	if (temp & (0xFFFFFFF ^ ((1 << 5) | (1 << 7)))) { +		DRM_DEBUG("IIR %08x\n", temp2); +		DRM_DEBUG("MSK %08x\n", dev_priv->irq_enable_reg | USER_INT_FLAG); +		DRM_DEBUG("M&I %08x\n", temp); +		DRM_DEBUG("HOT %08x\n", I915_READ(PORT_HOTPLUG_STAT)); +	} +#else +#if 0  	DRM_DEBUG("flag=%08x\n", temp);  #endif +#endif +  	if (temp == 0)  		return IRQ_NONE; +	if (IS_I9XX(dev)) { +		I915_WRITE(I915REG_INT_IDENTITY_R, temp); +		(void) I915_READ(I915REG_INT_IDENTITY_R); +	} else { +		I915_WRITE16(I915REG_INT_IDENTITY_R, temp); +		(void) I915_READ16(I915REG_INT_IDENTITY_R); +	} +  	/*  	 * Clear the PIPE(A|B)STAT regs before the IIR otherwise  	 * we may get extra interrupts. @@ -437,6 +618,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)  			   pipea_stats | I915_VBLANK_INTERRUPT_ENABLE |  			   I915_VBLANK_CLEAR);  	} +  	if (temp & VSYNC_PIPEB_FLAG) {  		drm_handle_vblank(dev, i915_get_plane(dev, 1));  		I915_WRITE(I915REG_PIPEBSTAT, @@ -447,12 +629,15 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)  	I915_WRITE16(I915REG_INT_IDENTITY_R, temp);  	(void) I915_READ16(I915REG_INT_IDENTITY_R); /* Flush posted write */ +	DRM_READMEMORYBARRIER(); +  	temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG | VSYNC_PIPEA_FLAG |  		 VSYNC_PIPEB_FLAG); -	if (dev_priv->sarea_priv) -		dev_priv->sarea_priv->last_dispatch = -			READ_BREADCRUMB(dev_priv); +	if (dev->primary->master) { +		master_priv = dev->primary->master->driver_priv; +		master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); +	}  	if (temp & USER_INT_FLAG) {  		DRM_WAKEUP(&dev_priv->irq_queue); @@ -466,12 +651,23 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)  			drm_locked_tasklet(dev, i915_vblank_tasklet);  	} +	/* for now lest just ack it */ +	if (temp & (1 << 17)) { +		DRM_DEBUG("Hotplug event received\n"); + +		temp2 = I915_READ(PORT_HOTPLUG_STAT); + +		i915_run_hotplug_tasklet(dev, temp2); + +		I915_WRITE(PORT_HOTPLUG_STAT,temp2); +	} +  	return IRQ_HANDLED;  }  int i915_emit_irq(struct drm_device *dev)  { -	drm_i915_private_t *dev_priv = dev->dev_private; +	struct drm_i915_private *dev_priv = dev->dev_private;  	RING_LOCALS;  	i915_kernel_lost_context(dev); @@ -488,7 +684,7 @@ int i915_emit_irq(struct drm_device *dev)  	return dev_priv->counter;  } -void i915_user_irq_on(drm_i915_private_t *dev_priv) +void i915_user_irq_on(struct drm_i915_private *dev_priv)  {  	DRM_SPINLOCK(&dev_priv->user_irq_lock);  	if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){ @@ -498,8 +694,8 @@ void i915_user_irq_on(drm_i915_private_t *dev_priv)  	DRM_SPINUNLOCK(&dev_priv->user_irq_lock);  } - -void i915_user_irq_off(drm_i915_private_t *dev_priv) +		 +void i915_user_irq_off(struct drm_i915_private *dev_priv)  {  	DRM_SPINLOCK(&dev_priv->user_irq_lock);  	if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { @@ -512,7 +708,8 @@ void i915_user_irq_off(drm_i915_private_t *dev_priv)  static int i915_wait_irq(struct drm_device * dev, int irq_nr)  { -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; +	struct drm_i915_master_private *master_priv;  	int ret = 0;  	DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, @@ -530,10 +727,12 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)  		DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",  			  READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);  	} +	 +	if (dev->primary->master) { +		master_priv = dev->primary->master->driver_priv; +		master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); +	} -	if (dev_priv->sarea_priv) -		dev_priv->sarea_priv->last_dispatch = -			READ_BREADCRUMB(dev_priv);  	return ret;  } @@ -542,8 +741,8 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)  int i915_irq_emit(struct drm_device *dev, void *data,  			 struct drm_file *file_priv)  { -	drm_i915_private_t *dev_priv = dev->dev_private; -	drm_i915_irq_emit_t *emit = data; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_i915_irq_emit *emit = data;  	int result;  	LOCK_TEST_WITH_RETURN(dev, file_priv); @@ -568,8 +767,8 @@ int i915_irq_emit(struct drm_device *dev, void *data,  int i915_irq_wait(struct drm_device *dev, void *data,  		  struct drm_file *file_priv)  { -	drm_i915_private_t *dev_priv = dev->dev_private; -	drm_i915_irq_wait_t *irqwait = data; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_i915_irq_wait *irqwait = data;  	if (!dev_priv) {  		DRM_ERROR("called with no initialization\n"); @@ -581,9 +780,9 @@ int i915_irq_wait(struct drm_device *dev, void *data,  int i915_enable_vblank(struct drm_device *dev, int plane)  { -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;  	int pipe = i915_get_pipe(dev, plane); - +	  	switch (pipe) {  	case 0:  		dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG; @@ -604,7 +803,7 @@ int i915_enable_vblank(struct drm_device *dev, int plane)  void i915_disable_vblank(struct drm_device *dev, int plane)  { -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;  	int pipe = i915_get_pipe(dev, plane);  	switch (pipe) { @@ -623,13 +822,48 @@ void i915_disable_vblank(struct drm_device *dev, int plane)  	I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);  } -static void i915_enable_interrupt (struct drm_device *dev) +void i915_enable_interrupt (struct drm_device *dev)  { -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; -	 +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; +	struct drm_output *o; +  	dev_priv->irq_enable_reg |= USER_INT_FLAG; -	I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); +	if (IS_I9XX(dev) && dev->mode_config.num_output) { +		dev_priv->irq_enable_reg |= HOTPLUG_FLAG; + +		/* Activate the CRT */ +		I915_WRITE(PORT_HOTPLUG_EN, CRT_HOTPLUG_INT_EN); + +		/* SDVOB */ +		o = intel_sdvo_find(dev, 1); +		if (o && intel_sdvo_supports_hotplug(o)) { +			intel_sdvo_set_hotplug(o, 1); +			I915_WRITE(PORT_HOTPLUG_EN, SDVOB_HOTPLUG_INT_EN); +		} + +		/* SDVOC */ +		o = intel_sdvo_find(dev, 0); +		if (o && intel_sdvo_supports_hotplug(o)) { +			intel_sdvo_set_hotplug(o, 1); +			I915_WRITE(PORT_HOTPLUG_EN, SDVOC_HOTPLUG_INT_EN); +		} + +	} + +	if (IS_I9XX(dev)) { +		I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); +	} else { +		I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); +	} + +	DRM_DEBUG("HEN %08x\n",I915_READ(PORT_HOTPLUG_EN)); +	DRM_DEBUG("HST %08x\n",I915_READ(PORT_HOTPLUG_STAT)); +	DRM_DEBUG("IER %08x\n",I915_READ(I915REG_INT_ENABLE_R)); +	DRM_DEBUG("SDB %08x\n",I915_READ(SDVOB)); + +	I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); +  	dev_priv->irq_enabled = 1;  } @@ -638,8 +872,8 @@ static void i915_enable_interrupt (struct drm_device *dev)  int i915_vblank_pipe_set(struct drm_device *dev, void *data,  			 struct drm_file *file_priv)  { -	drm_i915_private_t *dev_priv = dev->dev_private; -	drm_i915_vblank_pipe_t *pipe = data; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_i915_vblank_pipe *pipe = data;  	if (!dev_priv) {  		DRM_ERROR("called with no initialization\n"); @@ -659,8 +893,8 @@ int i915_vblank_pipe_set(struct drm_device *dev, void *data,  int i915_vblank_pipe_get(struct drm_device *dev, void *data,  			 struct drm_file *file_priv)  { -	drm_i915_private_t *dev_priv = dev->dev_private; -	drm_i915_vblank_pipe_t *pipe = data; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_i915_vblank_pipe *pipe = data;  	u16 flag;  	if (!dev_priv) { @@ -684,9 +918,10 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data,  int i915_vblank_swap(struct drm_device *dev, void *data,  		     struct drm_file *file_priv)  { -	drm_i915_private_t *dev_priv = dev->dev_private; -	drm_i915_vblank_swap_t *swap = data; -	drm_i915_vbl_swap_t *vbl_swap; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_i915_master_private *master_priv; +	struct drm_i915_vblank_swap *swap = data; +	struct drm_i915_vbl_swap *vbl_swap;  	unsigned int pipe, seqtype, curseq, plane;  	unsigned long irqflags;  	struct list_head *list; @@ -697,7 +932,12 @@ int i915_vblank_swap(struct drm_device *dev, void *data,  		return -EINVAL;  	} -	if (!dev_priv->sarea_priv || dev_priv->sarea_priv->rotation) { +	if (!dev->primary->master) +		return -EINVAL; + +	master_priv = dev->primary->master->driver_priv; + +	if (master_priv->sarea_priv->rotation) {  		DRM_DEBUG("Rotation not supported\n");  		return -EINVAL;  	} @@ -780,7 +1020,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data,  	DRM_SPINLOCK_IRQSAVE(&dev_priv->swaps_lock, irqflags);  	list_for_each(list, &dev_priv->vbl_swaps.head) { -		vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); +		vbl_swap = list_entry(list, struct drm_i915_vbl_swap, head);  		if (vbl_swap->drw_id == swap->drawable &&  		    vbl_swap->plane == plane && @@ -818,6 +1058,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data,  	vbl_swap->plane = plane;  	vbl_swap->sequence = swap->sequence;  	vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP); +	vbl_swap->minor = file_priv->minor;  	if (vbl_swap->flip)  		swap->sequence++; @@ -836,16 +1077,22 @@ int i915_vblank_swap(struct drm_device *dev, void *data,  */  void i915_driver_irq_preinstall(struct drm_device * dev)  { -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;  	I915_WRITE16(I915REG_HWSTAM, 0xeffe); -	I915_WRITE16(I915REG_INT_MASK_R, 0x0); -	I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); +	if (IS_I9XX(dev)) { +		I915_WRITE(I915REG_INT_MASK_R, 0x0); +		I915_WRITE(I915REG_INT_ENABLE_R, 0x0); +	} else { +		I915_WRITE16(I915REG_INT_MASK_R, 0x0); +		I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); +	} +  }  int i915_driver_irq_postinstall(struct drm_device * dev)  { -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;  	int ret, num_pipes = 2;  	DRM_SPININIT(&dev_priv->swaps_lock, "swap"); @@ -875,17 +1122,28 @@ int i915_driver_irq_postinstall(struct drm_device * dev)  void i915_driver_irq_uninstall(struct drm_device * dev)  { -	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; -	u16 temp; +	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; +	u32 temp;  	if (!dev_priv)  		return;  	dev_priv->irq_enabled = 0; -	I915_WRITE16(I915REG_HWSTAM, 0xffff); -	I915_WRITE16(I915REG_INT_MASK_R, 0xffff); -	I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); -	temp = I915_READ16(I915REG_INT_IDENTITY_R); -	I915_WRITE16(I915REG_INT_IDENTITY_R, temp); + +	if(IS_I9XX(dev)) { +		I915_WRITE(I915REG_HWSTAM, 0xffffffff); +		I915_WRITE(I915REG_INT_MASK_R, 0xffffffff); +		I915_WRITE(I915REG_INT_ENABLE_R, 0x0); + +		temp = I915_READ(I915REG_INT_IDENTITY_R); +		I915_WRITE(I915REG_INT_IDENTITY_R, temp); +	} else { +		I915_WRITE16(I915REG_HWSTAM, 0xffff); +		I915_WRITE16(I915REG_INT_MASK_R, 0xffff); +		I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); + +		temp = I915_READ16(I915REG_INT_IDENTITY_R); +		I915_WRITE16(I915REG_INT_IDENTITY_R, temp); +	}  } diff --git a/shared-core/i915_mem.c b/shared-core/i915_mem.c index 6126a60d..15d63dec 100644 --- a/shared-core/i915_mem.c +++ b/shared-core/i915_mem.c @@ -45,8 +45,9 @@   */  static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use)  { -	drm_i915_private_t *dev_priv = dev->dev_private; -	drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; +	struct drm_i915_sarea *sarea_priv = master_priv->sarea_priv;  	struct drm_tex_region *list;  	unsigned shift, nr;  	unsigned start; @@ -256,7 +257,7 @@ void i915_mem_takedown(struct mem_block **heap)  	*heap = NULL;  } -static struct mem_block **get_heap(drm_i915_private_t * dev_priv, int region) +static struct mem_block **get_heap(struct drm_i915_private * dev_priv, int region)  {  	switch (region) {  	case I915_MEM_REGION_AGP: @@ -271,8 +272,8 @@ static struct mem_block **get_heap(drm_i915_private_t * dev_priv, int region)  int i915_mem_alloc(struct drm_device *dev, void *data,  		   struct drm_file *file_priv)  { -	drm_i915_private_t *dev_priv = dev->dev_private; -	drm_i915_mem_alloc_t *alloc = data; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_i915_mem_alloc *alloc = data;  	struct mem_block *block, **heap;  	if (!dev_priv) { @@ -309,8 +310,8 @@ int i915_mem_alloc(struct drm_device *dev, void *data,  int i915_mem_free(struct drm_device *dev, void *data,  		  struct drm_file *file_priv)  { -	drm_i915_private_t *dev_priv = dev->dev_private; -	drm_i915_mem_free_t *memfree = data; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_i915_mem_free *memfree = data;  	struct mem_block *block, **heap;  	if (!dev_priv) { @@ -337,8 +338,8 @@ int i915_mem_free(struct drm_device *dev, void *data,  int i915_mem_init_heap(struct drm_device *dev, void *data,  		       struct drm_file *file_priv)  { -	drm_i915_private_t *dev_priv = dev->dev_private; -	drm_i915_mem_init_heap_t *initheap = data; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_i915_mem_init_heap *initheap = data;  	struct mem_block **heap;  	if (!dev_priv) { @@ -361,8 +362,8 @@ int i915_mem_init_heap(struct drm_device *dev, void *data,  int i915_mem_destroy_heap( struct drm_device *dev, void *data,  			   struct drm_file *file_priv )  { -	drm_i915_private_t *dev_priv = dev->dev_private; -	drm_i915_mem_destroy_heap_t *destroyheap = data; +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_i915_mem_destroy_heap *destroyheap = data;  	struct mem_block **heap;  	if ( !dev_priv ) { diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index ac46da38..f0eda664 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -1518,6 +1518,28 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)  	}  } +void radeon_gart_flush(struct drm_device *dev) +{ +	drm_radeon_private_t *dev_priv = dev->dev_private; +	 +	if (dev_priv->flags & RADEON_IS_IGPGART) { +		RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH); +		RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x1); +		RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH); +		RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x0); +	} else if (dev_priv->flags & RADEON_IS_PCIE) { +		u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL); +		tmp |= RADEON_PCIE_TX_GART_INVALIDATE_TLB; +		RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); +		tmp &= ~RADEON_PCIE_TX_GART_INVALIDATE_TLB; +		RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); +	} else { + + +	} + +} +  static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)  {  	drm_radeon_private_t *dev_priv = dev->dev_private; @@ -2433,6 +2455,9 @@ int radeon_driver_firstopen(struct drm_device *dev)  	if (ret != 0)  		return ret; +#ifdef RADEON_HAVE_BUFFER +	drm_bo_driver_init(dev); +#endif  	return 0;  } diff --git a/shared-core/radeon_drm.h b/shared-core/radeon_drm.h index 0971f970..67536c26 100644 --- a/shared-core/radeon_drm.h +++ b/shared-core/radeon_drm.h @@ -434,8 +434,17 @@ typedef struct {  	int pfCurrentPage;	/* which buffer is being displayed? */  	int crtc2_base;		/* CRTC2 frame offset */  	int tiling_enabled;	/* set by drm, read by 2d + 3d clients */ + +	unsigned int last_fence;  } drm_radeon_sarea_t; +/* The only fence class we support */ +#define DRM_RADEON_FENCE_CLASS_ACCEL 0 +/* Fence type that guarantees read-write flush */ +#define DRM_RADEON_FENCE_TYPE_RW 2 +/* cache flushes programmed just before the fence */ +#define DRM_RADEON_FENCE_FLAG_FLUSHED 0x01000000 +  /* WARNING: If you change any of these defines, make sure to change the   * defines in the Xserver file (xf86drmRadeon.h)   * diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 1cf03415..0c503257 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -104,6 +104,11 @@  #define DRIVER_MINOR		28  #define DRIVER_PATCHLEVEL	0 +#if defined(__linux__) +#define RADEON_HAVE_FENCE +#define RADEON_HAVE_BUFFER +#endif +  /*   * Radeon chip families   */ @@ -291,8 +296,9 @@ typedef struct drm_radeon_private {  	struct mem_block *fb_heap;  	/* SW interrupt */ -	wait_queue_head_t swi_queue; -	atomic_t swi_emitted; +	wait_queue_head_t irq_queue; +	int counter; +  	int vblank_crtc;  	uint32_t irq_enable_reg;  	int irq_enabled; @@ -355,6 +361,7 @@ extern int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file  extern int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);  extern int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv);  extern int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern void radeon_gart_flush(struct drm_device *dev);  extern u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv);  extern void radeon_freelist_reset(struct drm_device * dev); @@ -374,6 +381,7 @@ extern void radeon_mem_release(struct drm_file *file_priv,  				/* radeon_irq.c */  extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv);  extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int radeon_emit_irq(struct drm_device * dev);  extern void radeon_do_release(struct drm_device * dev);  extern u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc); @@ -407,6 +415,30 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,  			     struct drm_file *file_priv,  			     drm_radeon_kcmd_buffer_t *cmdbuf); + +#ifdef RADEON_HAVE_FENCE +/* i915_fence.c */ + + +extern void radeon_fence_handler(struct drm_device *dev); +extern int radeon_fence_emit_sequence(struct drm_device *dev, uint32_t class, +				      uint32_t flags, uint32_t *sequence,  +				    uint32_t *native_type); +extern void radeon_poke_flush(struct drm_device *dev, uint32_t class); +extern int radeon_fence_has_irq(struct drm_device *dev, uint32_t class, uint32_t flags); +#endif + +#ifdef RADEON_HAVE_BUFFER +/* radeon_buffer.c */ +extern struct drm_ttm_backend *radeon_create_ttm_backend_entry(struct drm_device *dev); +extern int radeon_fence_types(struct drm_buffer_object *bo, uint32_t *class, uint32_t *type); +extern int radeon_invalidate_caches(struct drm_device *dev, uint64_t buffer_flags); +extern uint64_t radeon_evict_flags(struct drm_buffer_object *bo); +extern int radeon_init_mem_type(struct drm_device * dev, uint32_t type, +				struct drm_mem_type_manager * man); +extern int radeon_move(struct drm_buffer_object * bo, +		       int evict, int no_wait, struct drm_bo_mem_reg * new_mem); +#endif  /* Flags for stats.boxes   */  #define RADEON_BOX_DMA_IDLE      0x1 @@ -1336,4 +1368,19 @@ do {									\  	write &= mask;						\  } while (0) +/* Breadcrumb - swi irq */ +#define READ_BREADCRUMB(dev_priv) RADEON_READ(RADEON_LAST_SWI_REG) + +static inline int radeon_update_breadcrumb(struct drm_device *dev) +{ +	drm_radeon_private_t *dev_priv = dev->dev_private; + +	dev_priv->sarea_priv->last_fence = ++dev_priv->counter; + +	if (dev_priv->counter > 0x7FFFFFFFUL) +		dev_priv->sarea_priv->last_fence = dev_priv->counter = 1; + +	return dev_priv->counter; +} +  #endif				/* __RADEON_DRV_H__ */ diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c index 79e4e866..3f6ace88 100644 --- a/shared-core/radeon_irq.c +++ b/shared-core/radeon_irq.c @@ -128,9 +128,12 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)  	stat &= dev_priv->irq_enable_reg;  	/* SW interrupt */ -	if (stat & RADEON_SW_INT_TEST) -		DRM_WAKEUP(&dev_priv->swi_queue); - +	if (stat & RADEON_SW_INT_TEST) { +		DRM_WAKEUP(&dev_priv->irq_queue); +#ifdef RADEON_HAVE_FENCE +		radeon_fence_handler(dev); +#endif +	}  	/* VBLANK interrupt */  	if (stat & RADEON_CRTC_VBLANK_STAT)  		drm_handle_vblank(dev, 0); @@ -140,14 +143,13 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)  	return IRQ_HANDLED;  } -static int radeon_emit_irq(struct drm_device * dev) +int radeon_emit_irq(struct drm_device * dev)  {  	drm_radeon_private_t *dev_priv = dev->dev_private;  	unsigned int ret;  	RING_LOCALS; -	atomic_inc(&dev_priv->swi_emitted); -	ret = atomic_read(&dev_priv->swi_emitted); +	ret = radeon_update_breadcrumb(dev);  	BEGIN_RING(4);  	OUT_RING_REG(RADEON_LAST_SWI_REG, ret); @@ -164,13 +166,13 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr)  	    (drm_radeon_private_t *) dev->dev_private;  	int ret = 0; -	if (RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr) +	if (READ_BREADCRUMB(dev_priv) >= swi_nr)  		return 0;  	dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; -	DRM_WAIT_ON(ret, dev_priv->swi_queue, 3 * DRM_HZ, -		    RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr); +	DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, +		    READ_BREADCRUMB(dev_priv) >= swi_nr);  	return ret;  } @@ -258,8 +260,8 @@ int radeon_driver_irq_postinstall(struct drm_device * dev)  	    (drm_radeon_private_t *) dev->dev_private;  	int ret; -	atomic_set(&dev_priv->swi_emitted, 0); -	DRM_INIT_WAITQUEUE(&dev_priv->swi_queue); +	dev_priv->counter = 0; +	DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);  	ret = drm_vblank_init(dev, 2);  	if (ret) diff --git a/shared-core/radeon_ms.h b/shared-core/radeon_ms.h new file mode 100644 index 00000000..903de97d --- /dev/null +++ b/shared-core/radeon_ms.h @@ -0,0 +1,607 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Dave Airlie + * Copyright 2007 Alex Deucher + * All Rights Reserved. + * + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: + *    Jérôme Glisse <glisse@freedesktop.org> + */ +#ifndef __RADEON_MS_H__ +#define __RADEON_MS_H__ + +#include "radeon_ms_drv.h" +#include "radeon_ms_reg.h" +#include "radeon_ms_drm.h" +#include "radeon_ms_rom.h" +#include "radeon_ms_properties.h" + +#define DRIVER_AUTHOR      "Jerome Glisse, Dave Airlie,  Gareth Hughes, "\ +			   "Keith Whitwell, others." +#define DRIVER_NAME        "radeon_ms" +#define DRIVER_DESC        "radeon kernel modesetting" +#define DRIVER_DATE        "20071108" +#define DRIVER_MAJOR        1 +#define DRIVER_MINOR        0 +#define DRIVER_PATCHLEVEL   0 + +enum radeon_bus_type { +	RADEON_PCI = 0x10000, +	RADEON_AGP = 0x20000, +	RADEON_PCIE = 0x30000, +}; + +enum radeon_family { +	CHIP_R100, +	CHIP_RV100, +	CHIP_RS100, +	CHIP_RV200, +	CHIP_RS200, +	CHIP_R200, +	CHIP_RV250, +	CHIP_RS300, +	CHIP_RV280, +	CHIP_R300, +	CHIP_R350, +	CHIP_R360, +	CHIP_RV350, +	CHIP_RV370, +	CHIP_RV380, +	CHIP_RS400, +	CHIP_RV410, +	CHIP_R420, +	CHIP_R430, +	CHIP_R480, +	CHIP_LAST, +}; + +enum radeon_monitor_type { +	MT_UNKNOWN = -1, +	MT_NONE    = 0, +	MT_CRT     = 1, +	MT_LCD     = 2, +	MT_DFP     = 3, +	MT_CTV     = 4, +	MT_STV     = 5 +}; + +enum radeon_connector_type { +	CONNECTOR_NONE, +	CONNECTOR_PROPRIETARY, +	CONNECTOR_VGA, +	CONNECTOR_DVI_I, +	CONNECTOR_DVI_D, +	CONNECTOR_CTV, +	CONNECTOR_STV, +	CONNECTOR_UNSUPPORTED +}; + +enum radeon_output_type { +	OUTPUT_NONE, +	OUTPUT_DAC1, +	OUTPUT_DAC2, +	OUTPUT_TMDS, +	OUTPUT_LVDS +}; + +struct radeon_state; + +struct radeon_ms_crtc { +	int             crtc; +	uint16_t	lut_r[256]; +	uint16_t	lut_g[256]; +	uint16_t	lut_b[256]; +}; + +struct radeon_ms_i2c { +	struct drm_device           *drm_dev; +	uint32_t    	            reg; +	struct i2c_adapter          adapter; +	struct i2c_algo_bit_data    algo; +}; + +struct radeon_ms_connector { +	struct radeon_ms_i2c    *i2c; +	struct edid             *edid; +	struct drm_output       *output; +	int                     type; +	int                     monitor_type; +	int                     crtc; +	uint32_t    	        i2c_reg; +	char                    outputs[RADEON_MAX_OUTPUTS]; +	char                    name[32]; +}; + +struct radeon_ms_output { +	int                         type; +	struct drm_device           *dev; +	struct radeon_ms_connector  *connector; +	int (*initialize)(struct radeon_ms_output *output); +	enum drm_output_status (*detect)(struct radeon_ms_output *output); +	void (*dpms)(struct radeon_ms_output *output, int mode); +	int (*get_modes)(struct radeon_ms_output *output); +	bool (*mode_fixup)(struct radeon_ms_output *output, +			struct drm_display_mode *mode, +			struct drm_display_mode *adjusted_mode); +	int (*mode_set)(struct radeon_ms_output *output, +			struct drm_display_mode *mode, +			struct drm_display_mode *adjusted_mode); +	void (*restore)(struct radeon_ms_output *output, +			struct radeon_state *state); +	void (*save)(struct radeon_ms_output *output, +			struct radeon_state *state); +}; + +struct radeon_state { +	/* memory */ +	uint32_t        config_aper_0_base; +	uint32_t        config_aper_1_base; +	uint32_t        config_aper_size; +	uint32_t        mc_fb_location; +	uint32_t        display_base_addr; +	/* irq */ +	uint32_t	gen_int_cntl; +	/* pci */ +	uint32_t        aic_ctrl; +	uint32_t        aic_pt_base; +	uint32_t        aic_pt_base_lo; +	uint32_t        aic_pt_base_hi; +	uint32_t        aic_lo_addr; +	uint32_t        aic_hi_addr; +	/* agp */ +	uint32_t        agp_cntl; +	uint32_t        agp_command; +	uint32_t        agp_base; +	uint32_t        agp_base_2; +	uint32_t        bus_cntl; +	uint32_t        mc_agp_location; +	/* cp */ +	uint32_t        cp_rb_cntl; +	uint32_t        cp_rb_base; +	uint32_t        cp_rb_rptr_addr; +	uint32_t        cp_rb_wptr; +	uint32_t        cp_rb_wptr_delay; +	uint32_t        scratch_umsk; +	uint32_t        scratch_addr; +	/* pcie */ +	uint32_t        pcie_tx_gart_cntl; +	uint32_t        pcie_tx_gart_discard_rd_addr_lo; +	uint32_t        pcie_tx_gart_discard_rd_addr_hi; +	uint32_t        pcie_tx_gart_base; +	uint32_t        pcie_tx_gart_start_lo; +	uint32_t        pcie_tx_gart_start_hi; +	uint32_t        pcie_tx_gart_end_lo; +	uint32_t        pcie_tx_gart_end_hi; +	/* surface */ +	uint32_t        surface_cntl; +	uint32_t        surface0_info; +	uint32_t        surface0_lower_bound; +	uint32_t        surface0_upper_bound; +	uint32_t        surface1_info; +	uint32_t        surface1_lower_bound; +	uint32_t        surface1_upper_bound; +	uint32_t        surface2_info; +	uint32_t        surface2_lower_bound; +	uint32_t        surface2_upper_bound; +	uint32_t        surface3_info; +	uint32_t        surface3_lower_bound; +	uint32_t        surface3_upper_bound; +	uint32_t        surface4_info; +	uint32_t        surface4_lower_bound; +	uint32_t        surface4_upper_bound; +	uint32_t        surface5_info; +	uint32_t        surface5_lower_bound; +	uint32_t        surface5_upper_bound; +	uint32_t        surface6_info; +	uint32_t        surface6_lower_bound; +	uint32_t        surface6_upper_bound; +	uint32_t        surface7_info; +	uint32_t        surface7_lower_bound; +	uint32_t        surface7_upper_bound; +	/* crtc */ +	uint32_t        crtc_gen_cntl; +	uint32_t        crtc_ext_cntl; +	uint32_t        crtc_h_total_disp; +	uint32_t        crtc_h_sync_strt_wid; +	uint32_t        crtc_v_total_disp; +	uint32_t        crtc_v_sync_strt_wid; +	uint32_t        crtc_offset; +	uint32_t        crtc_offset_cntl; +	uint32_t        crtc_pitch; +	uint32_t        crtc_more_cntl; +	uint32_t        crtc_tile_x0_y0; +	uint32_t        fp_h_sync_strt_wid; +	uint32_t        fp_v_sync_strt_wid; +	uint32_t        fp_crtc_h_total_disp; +	uint32_t        fp_crtc_v_total_disp; +	/* pll */ +	uint32_t        clock_cntl_index; +	uint32_t        ppll_cntl; +	uint32_t        ppll_ref_div; +	uint32_t        ppll_div_0; +	uint32_t        ppll_div_1; +	uint32_t        ppll_div_2; +	uint32_t        ppll_div_3; +	uint32_t        vclk_ecp_cntl; +	uint32_t        htotal_cntl; +	/* dac */ +	uint32_t        dac_cntl; +	uint32_t        dac_cntl2; +	uint32_t        dac_ext_cntl; +	uint32_t        disp_misc_cntl; +	uint32_t        dac_macro_cntl; +	uint32_t        disp_pwr_man; +	uint32_t        disp_merge_cntl; +	uint32_t        disp_output_cntl; +	uint32_t        disp2_merge_cntl; +	uint32_t        dac_embedded_sync_cntl; +	uint32_t        dac_broad_pulse; +	uint32_t        dac_skew_clks; +	uint32_t        dac_incr; +	uint32_t        dac_neg_sync_level; +	uint32_t        dac_pos_sync_level; +	uint32_t        dac_blank_level; +	uint32_t        dac_sync_equalization; +	uint32_t        tv_dac_cntl; +	uint32_t        tv_master_cntl; +}; + +struct drm_radeon_private { +	/* driver family specific functions */ +	int (*bus_finish)(struct drm_device *dev); +	int (*bus_init)(struct drm_device *dev); +	void (*bus_restore)(struct drm_device *dev, struct radeon_state *state); +	void (*bus_save)(struct drm_device *dev, struct radeon_state *state); +	struct drm_ttm_backend *(*create_ttm)(struct drm_device *dev); +	void (*irq_emit)(struct drm_device *dev); +	void (*flush_cache)(struct drm_device *dev); +	/* bus informations */ +	void                        *bus; +	uint32_t                    bus_type; +	/* cp */ +	uint32_t                    ring_buffer_size; +	uint32_t                    ring_rptr; +	uint32_t                    ring_wptr; +	uint32_t                    ring_mask; +	int                         ring_free; +	uint32_t                    ring_tail_mask; +	uint32_t                    write_back_area_size; +	struct drm_buffer_object    *ring_buffer_object; +	struct drm_bo_kmap_obj      ring_buffer_map; +	uint32_t                    *ring_buffer; +	uint32_t                    *write_back_area; +	const uint32_t              *microcode; +	/* card family */ +	uint32_t                    usec_timeout; +	uint32_t                    family; +	struct radeon_ms_output     *outputs[RADEON_MAX_OUTPUTS]; +	struct radeon_ms_connector  *connectors[RADEON_MAX_CONNECTORS]; +	/* drm map (MMIO, FB) */ +	struct drm_map              mmio; +	struct drm_map              vram; +	/* gpu address space */ +	uint32_t                    gpu_vram_size; +	uint32_t                    gpu_vram_start; +	uint32_t                    gpu_vram_end; +	uint32_t                    gpu_gart_size; +	uint32_t                    gpu_gart_start; +	uint32_t                    gpu_gart_end; +	/* state of the card when module was loaded */ +	struct radeon_state         load_state; +	/* state the driver wants */ +	struct radeon_state         driver_state; +	/* last emitted fence */ +	uint32_t                    fence_id_last; +	uint32_t                    fence_reg; +	/* when doing gpu stop we save here current state */ +	uint32_t                    crtc_ext_cntl; +	uint32_t                    crtc_gen_cntl; +	uint32_t                    crtc2_gen_cntl; +	uint32_t                    ov0_scale_cntl; +	/* bool & type on the hw */ +	uint8_t                     crtc1_dpms; +	uint8_t                     crtc2_dpms; +	uint8_t                     restore_state; +	uint8_t                     cp_ready; +	uint8_t                     bus_ready; +	uint8_t                     write_back; +	/* abstract asic specific structures */ +	struct radeon_ms_rom        rom; +	struct radeon_ms_properties properties; +}; + + +/* radeon_ms_bo.c */ +int radeon_ms_bo_get_gpu_addr(struct drm_device *dev, +			      struct drm_bo_mem_reg *mem, +			      uint32_t *gpu_addr); +int radeon_ms_bo_move(struct drm_buffer_object * bo, int evict, +		      int no_wait, struct drm_bo_mem_reg * new_mem); +struct drm_ttm_backend *radeon_ms_create_ttm_backend(struct drm_device * dev); +uint64_t radeon_ms_evict_flags(struct drm_buffer_object *bo); +int radeon_ms_init_mem_type(struct drm_device * dev, uint32_t type, +			    struct drm_mem_type_manager * man); +int radeon_ms_invalidate_caches(struct drm_device * dev, uint64_t flags); +void radeon_ms_ttm_flush(struct drm_ttm *ttm); + +/* radeon_ms_bus.c */ +int radeon_ms_agp_finish(struct drm_device *dev); +int radeon_ms_agp_init(struct drm_device *dev); +void radeon_ms_agp_restore(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_agp_save(struct drm_device *dev, struct radeon_state *state); +struct drm_ttm_backend *radeon_ms_pcie_create_ttm(struct drm_device *dev); +int radeon_ms_pcie_finish(struct drm_device *dev); +int radeon_ms_pcie_init(struct drm_device *dev); +void radeon_ms_pcie_restore(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_pcie_save(struct drm_device *dev, struct radeon_state *state); + +/* radeon_ms_combios.c */ +int radeon_ms_combios_get_properties(struct drm_device *dev); +int radeon_ms_connectors_from_combios(struct drm_device *dev); +int radeon_ms_outputs_from_combios(struct drm_device *dev); + +/* radeon_ms_compat.c */ +long radeon_ms_compat_ioctl(struct file *filp, unsigned int cmd, +			    unsigned long arg); + +/* radeon_ms_cp.c */ +int radeon_ms_cp_finish(struct drm_device *dev); +int radeon_ms_cp_init(struct drm_device *dev); +void radeon_ms_cp_restore(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_cp_save(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_cp_stop(struct drm_device *dev); +int radeon_ms_cp_wait(struct drm_device *dev, int n); +int radeon_ms_ring_emit(struct drm_device *dev, uint32_t *cmd, uint32_t count); + +/* radeon_ms_crtc.c */ +int radeon_ms_crtc_create(struct drm_device *dev, int crtc); +void radeon_ms_crtc1_restore(struct drm_device *dev, +			     struct radeon_state *state); +void radeon_ms_crtc1_save(struct drm_device *dev, struct radeon_state *state); + +/* radeon_ms_dac.c */ +int radeon_ms_dac1_initialize(struct radeon_ms_output *output); +enum drm_output_status radeon_ms_dac1_detect(struct radeon_ms_output *output); +void radeon_ms_dac1_dpms(struct radeon_ms_output *output, int mode); +int radeon_ms_dac1_get_modes(struct radeon_ms_output *output); +bool radeon_ms_dac1_mode_fixup(struct radeon_ms_output *output, +		struct drm_display_mode *mode, +		struct drm_display_mode *adjusted_mode); +int radeon_ms_dac1_mode_set(struct radeon_ms_output *output, +		struct drm_display_mode *mode, +		struct drm_display_mode *adjusted_mode); +void radeon_ms_dac1_restore(struct radeon_ms_output *output, +		struct radeon_state *state); +void radeon_ms_dac1_save(struct radeon_ms_output *output, +		struct radeon_state *state); +int radeon_ms_dac2_initialize(struct radeon_ms_output *output); +enum drm_output_status radeon_ms_dac2_detect(struct radeon_ms_output *output); +void radeon_ms_dac2_dpms(struct radeon_ms_output *output, int mode); +int radeon_ms_dac2_get_modes(struct radeon_ms_output *output); +bool radeon_ms_dac2_mode_fixup(struct radeon_ms_output *output, +		struct drm_display_mode *mode, +		struct drm_display_mode *adjusted_mode); +int radeon_ms_dac2_mode_set(struct radeon_ms_output *output, +		struct drm_display_mode *mode, +		struct drm_display_mode *adjusted_mode); +void radeon_ms_dac2_restore(struct radeon_ms_output *output, +		struct radeon_state *state); +void radeon_ms_dac2_save(struct radeon_ms_output *output, +		struct radeon_state *state); + +/* radeon_ms_drm.c */ +int radeon_ms_driver_dma_ioctl(struct drm_device *dev, void *data, +			       struct drm_file *file_priv); +void radeon_ms_driver_lastclose(struct drm_device * dev); +int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags); +int radeon_ms_driver_open(struct drm_device * dev, struct drm_file *file_priv); +int radeon_ms_driver_unload(struct drm_device *dev); + +/* radeon_ms_exec.c */ +int radeon_ms_execbuffer(struct drm_device *dev, void *data, +			 struct drm_file *file_priv); + +/* radeon_ms_family.c */ +int radeon_ms_family_init(struct drm_device *dev); + +/* radeon_ms_fence.c */ +int radeon_ms_fence_emit_sequence(struct drm_device *dev, uint32_t class, +			 	  uint32_t flags, uint32_t *sequence, +				  uint32_t *native_type); +void radeon_ms_fence_handler(struct drm_device * dev); +int radeon_ms_fence_has_irq(struct drm_device *dev, uint32_t class, +			    uint32_t flags); +int radeon_ms_fence_types(struct drm_buffer_object *bo, +			  uint32_t * class, uint32_t * type); +void radeon_ms_poke_flush(struct drm_device * dev, uint32_t class); + +/* radeon_ms_fb.c */ +int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc); +int radeonfb_remove(struct drm_device *dev, struct drm_crtc *crtc); + +/* radeon_ms_gpu.c */ +int radeon_ms_gpu_initialize(struct drm_device *dev); +void radeon_ms_gpu_dpms(struct drm_device *dev); +void radeon_ms_gpu_flush(struct drm_device *dev); +void radeon_ms_gpu_restore(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_gpu_save(struct drm_device *dev, struct radeon_state *state); +int radeon_ms_wait_for_idle(struct drm_device *dev); + +/* radeon_ms_i2c.c */ +void radeon_ms_i2c_destroy(struct radeon_ms_i2c *i2c); +struct radeon_ms_i2c *radeon_ms_i2c_create(struct drm_device *dev, +					   const uint32_t reg, +					   const char *name); + +/* radeon_ms_irq.c */ +void radeon_ms_irq_emit(struct drm_device *dev); +irqreturn_t radeon_ms_irq_handler(DRM_IRQ_ARGS); +void radeon_ms_irq_preinstall(struct drm_device * dev); +int radeon_ms_irq_postinstall(struct drm_device * dev); +int radeon_ms_irq_init(struct drm_device *dev); +void radeon_ms_irq_restore(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_irq_save(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_irq_uninstall(struct drm_device * dev); + +/* radeon_ms_output.c */ +void radeon_ms_connectors_destroy(struct drm_device *dev); +int radeon_ms_connectors_from_properties(struct drm_device *dev); +int radeon_ms_connectors_from_rom(struct drm_device *dev); +void radeon_ms_outputs_destroy(struct drm_device *dev); +int radeon_ms_outputs_from_properties(struct drm_device *dev); +int radeon_ms_outputs_from_rom(struct drm_device *dev); +void radeon_ms_outputs_restore(struct drm_device *dev, +		struct radeon_state *state); +void radeon_ms_outputs_save(struct drm_device *dev, struct radeon_state *state); + +/* radeon_ms_properties.c */ +int radeon_ms_properties_init(struct drm_device *dev); + +/* radeon_ms_rom.c */ +int radeon_ms_rom_get_properties(struct drm_device *dev); +int radeon_ms_rom_init(struct drm_device *dev); + +/* radeon_ms_state.c */ +void radeon_ms_state_save(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_state_restore(struct drm_device *dev, +			     struct radeon_state *state); + + +/* packect stuff **************************************************************/ +#define RADEON_CP_PACKET0                               0x00000000 +#define CP_PACKET0(reg, n)						\ +	(RADEON_CP_PACKET0 | ((n) << 16) | ((reg) >> 2)) +#define CP_PACKET3_CNTL_BITBLT_MULTI                    0xC0009B00 +#    define GMC_SRC_PITCH_OFFSET_CNTL                       (1    <<  0) +#    define GMC_DST_PITCH_OFFSET_CNTL                       (1    <<  1) +#    define GMC_BRUSH_NONE                                  (15   <<  4) +#    define GMC_SRC_DATATYPE_COLOR                          (3    << 12) +#    define ROP3_S                                          0x00cc0000 +#    define DP_SRC_SOURCE_MEMORY                            (2    << 24) +#    define GMC_CLR_CMP_CNTL_DIS                            (1    << 28) +#    define GMC_WR_MSK_DIS                                  (1    << 30) + +/* helper macro & functions ***************************************************/ +#define REG_S(rn, bn, v)    (((v) << rn##__##bn##__SHIFT) & rn##__##bn##__MASK) +#define REG_G(rn, bn, v)    (((v) & rn##__##bn##__MASK) >> rn##__##bn##__SHIFT) +#define MMIO_R(rid)         mmio_read(dev_priv, rid) +#define MMIO_W(rid, v)      mmio_write(dev_priv, rid, v) +#define PCIE_R(rid)         pcie_read(dev_priv, rid) +#define PCIE_W(rid, v)      pcie_write(dev_priv, rid, v) +#define PPLL_R(rid)         pll_read(dev_priv, rid) +#define PPLL_W(rid, v)      pll_write(dev_priv, rid, v) + +static __inline__ uint32_t mmio_read(struct drm_radeon_private *dev_priv, +				     uint32_t offset) +{ +	return DRM_READ32(&dev_priv->mmio, offset); +} + + +static __inline__ void mmio_write(struct drm_radeon_private *dev_priv, +				  uint32_t offset, uint32_t v) +{ +	DRM_WRITE32(&dev_priv->mmio, offset, v); +} + +static __inline__ uint32_t pcie_read(struct drm_radeon_private *dev_priv, +				     uint32_t offset) +{ +	MMIO_W(PCIE_INDEX, REG_S(PCIE_INDEX, PCIE_INDEX, offset)); +	return MMIO_R(PCIE_DATA); +} + +static __inline__ void pcie_write(struct drm_radeon_private *dev_priv, +				  uint32_t offset, uint32_t v) +{ +	MMIO_W(PCIE_INDEX, REG_S(PCIE_INDEX, PCIE_INDEX, offset)); +	MMIO_W(PCIE_DATA, v); +} + +static __inline__ void pll_index_errata(struct drm_radeon_private *dev_priv) +{ +	uint32_t tmp, save; + +	/* This workaround is necessary on rv200 and RS200 or PLL +	 * reads may return garbage (among others...) +	 */ +	if (dev_priv->properties.pll_dummy_reads) { +		tmp = MMIO_R(CLOCK_CNTL_DATA); +		tmp = MMIO_R(CRTC_GEN_CNTL); +	} +	/* This function is required to workaround a hardware bug in some (all?) +	 * revisions of the R300.  This workaround should be called after every +	 * CLOCK_CNTL_INDEX register access.  If not, register reads afterward +	 * may not be correct. +	 */ +	if (dev_priv->properties.pll_r300_errata) { +		tmp = save = MMIO_R(CLOCK_CNTL_INDEX); +		tmp = tmp & ~CLOCK_CNTL_INDEX__PLL_ADDR__MASK; +		tmp = tmp & ~CLOCK_CNTL_INDEX__PLL_WR_EN; +		MMIO_W(CLOCK_CNTL_INDEX, tmp); +		tmp = MMIO_R(CLOCK_CNTL_DATA); +		MMIO_W(CLOCK_CNTL_INDEX, save); +	} +} + +static __inline__ void pll_data_errata(struct drm_radeon_private *dev_priv) +{ +	/* This workarounds is necessary on RV100, RS100 and RS200 chips +	 * or the chip could hang on a subsequent access +	 */ +	if (dev_priv->properties.pll_delay) { +		/* we can't deal with posted writes here ... */ +		udelay(5000); +	} +} + +static __inline__ uint32_t pll_read(struct drm_radeon_private *dev_priv, +				    uint32_t offset) +{ +	uint32_t clock_cntl_index = dev_priv->driver_state.clock_cntl_index; +	uint32_t data; + +	clock_cntl_index &= ~CLOCK_CNTL_INDEX__PLL_ADDR__MASK; +	clock_cntl_index |= REG_S(CLOCK_CNTL_INDEX, PLL_ADDR, offset); +	MMIO_W(CLOCK_CNTL_INDEX, clock_cntl_index); +	pll_index_errata(dev_priv); +	data = MMIO_R(CLOCK_CNTL_DATA); +	pll_data_errata(dev_priv); +	return data; +} + +static __inline__ void pll_write(struct drm_radeon_private *dev_priv, +				 uint32_t offset, uint32_t value) +{ +	uint32_t clock_cntl_index = dev_priv->driver_state.clock_cntl_index; + +	clock_cntl_index &= ~CLOCK_CNTL_INDEX__PLL_ADDR__MASK; +	clock_cntl_index |= REG_S(CLOCK_CNTL_INDEX, PLL_ADDR, offset); +	clock_cntl_index |= CLOCK_CNTL_INDEX__PLL_WR_EN; +	MMIO_W(CLOCK_CNTL_INDEX, clock_cntl_index); +	pll_index_errata(dev_priv); +	MMIO_W(CLOCK_CNTL_DATA, value); +	pll_data_errata(dev_priv); +} + +#endif diff --git a/shared-core/radeon_ms_bo.c b/shared-core/radeon_ms_bo.c new file mode 100644 index 00000000..6d9a97c1 --- /dev/null +++ b/shared-core/radeon_ms_bo.c @@ -0,0 +1,311 @@ +/* + * Copyright 2007 Dave Airlie + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + *  + * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + *    Dave Airlie <airlied@linux.ie> + *    Jerome Glisse <glisse@freedesktop.org> + */ +#include "drmP.h" +#include "drm.h" + +#include "radeon_ms.h" + +void radeon_ms_bo_copy_blit(struct drm_device *dev, +			    uint32_t src_offset, +			    uint32_t dst_offset, +			    uint32_t pages) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	uint32_t num_pages, stride, c; +	uint32_t offset_inc = 0; +	uint32_t cmd[7]; + +	if (!dev_priv) { +		return; +	} + +	/* radeon limited to 16320=255*64 bytes per row so copy at +	 * most 2 pages */ +	num_pages = 2; +	stride = ((num_pages * PAGE_SIZE) / 64) & 0xff; +	while(pages > 0) { +		if (num_pages > pages) { +			num_pages = pages; +			stride = ((num_pages * PAGE_SIZE) / 64) & 0xff; +		} +		c = pages / num_pages; +		if (c >= 8192) { +			c = 8191; +		} +		cmd[0] = CP_PACKET3_CNTL_BITBLT_MULTI | (5 << 16); +		cmd[1] = GMC_SRC_PITCH_OFFSET_CNTL | +			 GMC_DST_PITCH_OFFSET_CNTL | +			 GMC_BRUSH_NONE | +			 (0x6 << 8) | +			 GMC_SRC_DATATYPE_COLOR | +			 ROP3_S | +			 DP_SRC_SOURCE_MEMORY | +			 GMC_CLR_CMP_CNTL_DIS | +			 GMC_WR_MSK_DIS; +		cmd[2] = (stride << 22) | (src_offset >> 10); +		cmd[3] = (stride << 22) | (dst_offset >> 10); +		cmd[4] = (0 << 16) | 0; +		cmd[5] = (0 << 16) | 0; +		cmd[6] = ((stride * 16) << 16) | c; +		radeon_ms_ring_emit(dev, cmd, 7); +		offset_inc = num_pages * c * PAGE_SIZE; +		src_offset += offset_inc; +		dst_offset += offset_inc; +		pages -= num_pages * c; +	} +	/* wait for 2d engine to go busy so wait_until stall */ +	for (c = 0; c < dev_priv->usec_timeout; c++) { +		uint32_t status = MMIO_R(RBBM_STATUS); +		if ((RBBM_STATUS__E2_BUSY & status) || +		    (RBBM_STATUS__CBA2D_BUSY & status)) { +			DRM_INFO("[radeon_ms] RBBM_STATUS 0x%08X\n", status); +			break; +		} +		DRM_UDELAY(1); +	} +	/* Sync everything up */ +	cmd[0] = CP_PACKET0(WAIT_UNTIL, 0); +	cmd[1] = WAIT_UNTIL__WAIT_2D_IDLECLEAN | +		 WAIT_UNTIL__WAIT_HOST_IDLECLEAN; +	radeon_ms_ring_emit(dev, cmd, 2); +	return; +} + +static int radeon_ms_bo_move_blit(struct drm_buffer_object *bo, +				  int evict, int no_wait, +				  struct drm_bo_mem_reg *new_mem) +{ +	struct drm_device *dev = bo->dev; +	struct drm_bo_mem_reg *old_mem = &bo->mem; +	uint32_t gpu_src_addr; +	uint32_t gpu_dst_addr; +	int ret; + +	ret = radeon_ms_bo_get_gpu_addr(dev, old_mem, &gpu_src_addr); +	if (ret) { +		return ret; +	} +	ret = radeon_ms_bo_get_gpu_addr(dev, new_mem, &gpu_dst_addr); +	if (ret) { +		return ret; +	} + +	radeon_ms_bo_copy_blit(bo->dev, +			       gpu_src_addr, +			       gpu_dst_addr, +			       new_mem->num_pages); +	 +	ret = drm_bo_move_accel_cleanup(bo, evict, no_wait, 0, +					 DRM_FENCE_TYPE_EXE | +					 DRM_RADEON_FENCE_TYPE_RW, +					 DRM_RADEON_FENCE_FLAG_FLUSHED, +					 new_mem); +	return ret; +} + +static int radeon_ms_bo_move_flip(struct drm_buffer_object *bo, +				  int evict, int no_wait, +				  struct drm_bo_mem_reg *new_mem) +{ +	struct drm_device *dev = bo->dev; +	struct drm_bo_mem_reg tmp_mem; +	int ret; + +	tmp_mem = *new_mem; +	tmp_mem.mm_node = NULL; +	tmp_mem.flags = DRM_BO_FLAG_MEM_TT | +		       DRM_BO_FLAG_CACHED | +		       DRM_BO_FLAG_FORCE_CACHING; +	ret = drm_bo_mem_space(bo, &tmp_mem, no_wait); +	if (ret) { +		return ret; +	} + +	ret = drm_ttm_bind(bo->ttm, &tmp_mem); +	if (ret) { +		goto out_cleanup; +	} +	ret = radeon_ms_bo_move_blit(bo, 1, no_wait, &tmp_mem); +	if (ret) { +		goto out_cleanup; +	} +	ret = drm_bo_move_ttm(bo, evict, no_wait, new_mem); +out_cleanup: +	if (tmp_mem.mm_node) { +		mutex_lock(&dev->struct_mutex); +		if (tmp_mem.mm_node != bo->pinned_node) +			drm_mm_put_block(tmp_mem.mm_node); +		tmp_mem.mm_node = NULL; +		mutex_unlock(&dev->struct_mutex); +	} +	return ret; +} + +int radeon_ms_bo_get_gpu_addr(struct drm_device *dev, +			      struct drm_bo_mem_reg *mem, +			      uint32_t *gpu_addr) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	*gpu_addr = mem->mm_node->start << PAGE_SHIFT; +	switch (mem->flags & DRM_BO_MASK_MEM) { +	case DRM_BO_FLAG_MEM_TT: +		*gpu_addr +=  dev_priv->gpu_gart_start; +		DRM_INFO("[radeon_ms] GPU TT: 0x%08X\n", *gpu_addr); +		break; +	case DRM_BO_FLAG_MEM_VRAM: +		*gpu_addr +=  dev_priv->gpu_vram_start; +		DRM_INFO("[radeon_ms] GPU VRAM: 0x%08X\n", *gpu_addr); +		break; +	default: +		DRM_ERROR("[radeon_ms] memory not accessible by GPU\n"); +		return -EINVAL; +	} +	return 0; +} + +int radeon_ms_bo_move(struct drm_buffer_object *bo, int evict, +		   int no_wait, struct drm_bo_mem_reg *new_mem) +{ +	struct drm_bo_mem_reg *old_mem = &bo->mem; +	if (old_mem->mem_type == DRM_BO_MEM_LOCAL) { +		return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); +	} else if (new_mem->mem_type == DRM_BO_MEM_LOCAL) { +		if (radeon_ms_bo_move_flip(bo, evict, no_wait, new_mem)) +			return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); +	} else { +		if (radeon_ms_bo_move_blit(bo, evict, no_wait, new_mem)) +			return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); +	} +	return 0; +} + +struct drm_ttm_backend *radeon_ms_create_ttm_backend(struct drm_device * dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	if (dev_priv && dev_priv->create_ttm) +		return dev_priv->create_ttm(dev); +	return NULL; +} + +uint64_t radeon_ms_evict_flags(struct drm_buffer_object *bo) +{ +	switch (bo->mem.mem_type) { +	case DRM_BO_MEM_LOCAL: +	case DRM_BO_MEM_TT: +		return DRM_BO_FLAG_MEM_LOCAL; +	case DRM_BO_MEM_VRAM: +		if (bo->mem.num_pages > 128) +			return DRM_BO_MEM_TT; +		else +			return DRM_BO_MEM_LOCAL; +	default: +		return DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_CACHED; +	} +} + +int radeon_ms_init_mem_type(struct drm_device * dev, uint32_t type, +			    struct drm_mem_type_manager * man) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	switch (type) { +	case DRM_BO_MEM_LOCAL: +		man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | +		    _DRM_FLAG_MEMTYPE_CACHED; +		man->drm_bus_maptype = 0; +		break; +	case DRM_BO_MEM_VRAM: +		man->flags =  _DRM_FLAG_MEMTYPE_FIXED | +			      _DRM_FLAG_MEMTYPE_MAPPABLE | +			      _DRM_FLAG_NEEDS_IOREMAP; +		man->io_addr = NULL; +		man->drm_bus_maptype = _DRM_FRAME_BUFFER; +		man->io_offset = dev_priv->vram.offset; +		man->io_size = dev_priv->vram.size; +		break; +	case DRM_BO_MEM_TT: +		if (!dev_priv->bus_ready) { +			DRM_ERROR("Bus isn't initialized while " +				  "intializing TT memory type\n"); +			return -EINVAL; +		} +		switch(dev_priv->bus_type) { +		case RADEON_AGP: +			if (!(drm_core_has_AGP(dev) && dev->agp)) { +				DRM_ERROR("AGP is not enabled for memory " +					  "type %u\n", (unsigned)type); +				return -EINVAL; +			} +			man->io_offset = dev->agp->agp_info.aper_base; +			man->io_size = dev->agp->agp_info.aper_size * +				       1024 * 1024; +			man->io_addr = NULL; +			man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | +				     _DRM_FLAG_MEMTYPE_CSELECT | +				     _DRM_FLAG_NEEDS_IOREMAP; +			man->drm_bus_maptype = _DRM_AGP; +			man->gpu_offset = 0; +			break; +		default: +			man->io_offset = dev_priv->gpu_gart_start; +			man->io_size = dev_priv->gpu_gart_size; +			man->io_addr = NULL; +			man->flags = _DRM_FLAG_MEMTYPE_CSELECT | +				     _DRM_FLAG_MEMTYPE_MAPPABLE | +				     _DRM_FLAG_MEMTYPE_CMA; +			man->drm_bus_maptype = _DRM_SCATTER_GATHER; +			break; +		} +		break; +	default: +		DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); +		return -EINVAL; +	} +	return 0; +} + +int radeon_ms_invalidate_caches(struct drm_device * dev, uint64_t flags) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	dev_priv->flush_cache(dev); +	return 0; +} + +void radeon_ms_ttm_flush(struct drm_ttm *ttm) +{ +	if (!ttm) +		return; + +	DRM_MEMORYBARRIER(); +} diff --git a/shared-core/radeon_ms_bus.c b/shared-core/radeon_ms_bus.c new file mode 100644 index 00000000..ed8fb211 --- /dev/null +++ b/shared-core/radeon_ms_bus.c @@ -0,0 +1,460 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * All Rights Reserved. + *  + * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + *    Dave Airlie <airlied@linux.ie> + *    Jerome Glisse <glisse@freedesktop.org> + */ +#include "drmP.h" +#include "drm.h" +#include "radeon_ms.h" + +struct radeon_pcie { +	uint32_t                    gart_table_size; +	struct drm_buffer_object    *gart_table_object; +	volatile uint32_t           *gart_table; +	struct drm_device           *dev; +	unsigned long               page_last; +}; + +struct radeon_pcie_gart { +	struct drm_ttm_backend  backend; +	struct radeon_pcie      *pcie; +	unsigned long           page_first; +	struct page             **pages; +	struct page             *dummy_read_page; +	unsigned long           num_pages; +	int                     populated; +	int                     bound; +}; + +static int pcie_ttm_bind(struct drm_ttm_backend *backend, +			 struct drm_bo_mem_reg *bo_mem); +static void pcie_ttm_clear(struct drm_ttm_backend *backend); +static void pcie_ttm_destroy(struct drm_ttm_backend *backend); +static int pcie_ttm_needs_ub_cache_adjust(struct drm_ttm_backend *backend); +static int pcie_ttm_populate(struct drm_ttm_backend *backend, +			     unsigned long num_pages, struct page **pages, +			     struct page *dummy_read_page); +static int pcie_ttm_unbind(struct drm_ttm_backend *backend); + +static struct drm_ttm_backend_func radeon_pcie_gart_ttm_backend =  +{ +	.needs_ub_cache_adjust = pcie_ttm_needs_ub_cache_adjust, +	.populate = pcie_ttm_populate, +	.clear = pcie_ttm_clear, +	.bind = pcie_ttm_bind, +	.unbind = pcie_ttm_unbind, +	.destroy =  pcie_ttm_destroy, +}; + +static void pcie_gart_flush(struct radeon_pcie *pcie) +{ +	struct drm_device *dev; +	struct drm_radeon_private *dev_priv; +	uint32_t flush; + +	if (pcie == NULL) { +		return; +	} +	dev = pcie->dev; +	dev_priv = dev->dev_private; +	flush = dev_priv->driver_state.pcie_tx_gart_cntl; +	flush |= PCIE_TX_GART_CNTL__GART_INVALIDATE_TLB; +	PCIE_W(PCIE_TX_GART_CNTL, flush); +	PCIE_W(PCIE_TX_GART_CNTL, dev_priv->driver_state.pcie_tx_gart_cntl); +} + +static __inline__ uint32_t pcie_gart_get_page_base(struct radeon_pcie *pcie, +						   unsigned long page) +{ +	if (pcie == NULL || pcie->gart_table == NULL) { +		return 0; +	} +	return ((pcie->gart_table[page] & (~0xC)) << 8); +} + +static __inline__ void pcie_gart_set_page_base(struct radeon_pcie *pcie, +					       unsigned long page, +					       uint32_t page_base) +{ +	if (pcie == NULL || pcie->gart_table == NULL) { +		return; +	} +	pcie->gart_table[page] = cpu_to_le32((page_base >> 8) | 0xC); +} + +static int pcie_ttm_bind(struct drm_ttm_backend *backend, +			 struct drm_bo_mem_reg *bo_mem) +{ +	struct radeon_pcie_gart *pcie_gart; +	unsigned long page_first; +	unsigned long page_last; +	unsigned long page, i; +	uint32_t page_base; + +	pcie_gart = container_of(backend, struct radeon_pcie_gart, backend); +	page = page_first = bo_mem->mm_node->start; +	page_last = page_first + pcie_gart->num_pages; +	if (page_first >= pcie_gart->pcie->page_last || +	    page_last >= pcie_gart->pcie->page_last) +	    return -EINVAL; +        while (page < page_last) { +		if (pcie_gart_get_page_base(pcie_gart->pcie, page)) { +			return -EBUSY; +		} +                page++; +        } + +        for (i = 0, page = page_first; i < pcie_gart->num_pages; i++, page++) { +		struct page *cur_page = pcie_gart->pages[i]; + +		if (!page) { +			cur_page = pcie_gart->dummy_read_page; +		} +                /* write value */ +		page_base = page_to_phys(cur_page); +		pcie_gart_set_page_base(pcie_gart->pcie, page, page_base); +        } +	DRM_MEMORYBARRIER(); +	pcie_gart_flush(pcie_gart->pcie); +	pcie_gart->bound = 1; +	pcie_gart->page_first = page_first; +	return 0; +} + +static void pcie_ttm_clear(struct drm_ttm_backend *backend) +{ +	struct radeon_pcie_gart *pcie_gart; + +	pcie_gart = container_of(backend, struct radeon_pcie_gart, backend); +	if (pcie_gart->pages) { +		backend->func->unbind(backend); +		pcie_gart->pages = NULL; +	} +	pcie_gart->num_pages = 0; +} + +static void pcie_ttm_destroy(struct drm_ttm_backend *backend) +{ +	struct radeon_pcie_gart *pcie_gart; + +	if (backend == NULL) { +		return; +	} +	pcie_gart = container_of(backend, struct radeon_pcie_gart, backend); +	if (pcie_gart->pages) { +		backend->func->clear(backend); +	} +	drm_ctl_free(pcie_gart, sizeof(*pcie_gart), DRM_MEM_TTM); +} + +static int pcie_ttm_needs_ub_cache_adjust(struct drm_ttm_backend *backend) +{ +	return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 0 : 1); +} + +static int pcie_ttm_populate(struct drm_ttm_backend *backend, +			     unsigned long num_pages, struct page **pages, +			     struct page *dummy_read_page) +{ +	struct radeon_pcie_gart *pcie_gart; + +	pcie_gart = container_of(backend, struct radeon_pcie_gart, backend); +	pcie_gart->pages = pages; +	pcie_gart->num_pages = num_pages; +	pcie_gart->populated = 1; +	return 0; +} + +static int pcie_ttm_unbind(struct drm_ttm_backend *backend) +{ +	struct radeon_pcie_gart *pcie_gart; +	unsigned long page, i; + +	pcie_gart = container_of(backend, struct radeon_pcie_gart, backend); +	if (pcie_gart->bound != 1 || pcie_gart->pcie->gart_table == NULL) { +		return -EINVAL; +	} +	for (i = 0, page = pcie_gart->page_first; i < pcie_gart->num_pages; +	     i++, page++) { +	     	pcie_gart->pcie->gart_table[page] = 0; +	} +	pcie_gart_flush(pcie_gart->pcie); +	pcie_gart->bound = 0; +	pcie_gart->page_first = 0; +	return 0; +} + +int radeon_ms_agp_finish(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	if (!dev_priv->bus_ready) { +		return 0; +	} +	dev_priv->bus_ready = 0; +	drm_agp_release(dev); +	return 0; +} + +int radeon_ms_agp_init(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_state *state = &dev_priv->driver_state; +	struct drm_agp_mode mode; +	uint32_t agp_status; +	int ret; + +	dev_priv->bus_ready = -1; +	if (dev->agp == NULL) { +		DRM_ERROR("[radeon_ms] can't initialize AGP\n"); +		return -EINVAL; +	} +	ret = drm_agp_acquire(dev); +	if (ret) { +		DRM_ERROR("[radeon_ms] error failed to acquire agp\n"); +		return ret; +	} +	agp_status = MMIO_R(AGP_STATUS); +	if ((AGP_STATUS__MODE_AGP30 & agp_status)) { +		mode.mode = AGP_STATUS__RATE4X; +	} else { +		mode.mode = AGP_STATUS__RATE2X_8X; +	} +	ret = drm_agp_enable(dev, mode); +	if (ret) { +		DRM_ERROR("[radeon_ms] error failed to enable agp\n"); +		return ret; +	} +	state->agp_command = MMIO_R(AGP_COMMAND) | AGP_COMMAND__AGP_EN; +	state->agp_command &= ~AGP_COMMAND__FW_EN; +	state->agp_command &= ~AGP_COMMAND__MODE_4G_EN; +	state->aic_ctrl = 0; +	state->agp_base = REG_S(AGP_BASE, AGP_BASE_ADDR, dev->agp->base); +	state->agp_base_2 = 0; +	state->bus_cntl = MMIO_R(BUS_CNTL); +	state->bus_cntl &= ~BUS_CNTL__BUS_MASTER_DIS; +	state->mc_agp_location = +		REG_S(MC_AGP_LOCATION, MC_AGP_START, +				dev_priv->gpu_gart_start >> 16) | +		REG_S(MC_AGP_LOCATION, MC_AGP_TOP, +				dev_priv->gpu_gart_end >> 16); +	DRM_INFO("[radeon_ms] gpu agp base 0x%08X\n", MMIO_R(AGP_BASE)); +	DRM_INFO("[radeon_ms] gpu agp location 0x%08X\n", +		 MMIO_R(MC_AGP_LOCATION)); +	DRM_INFO("[radeon_ms] gpu agp location 0x%08X\n", +		 state->mc_agp_location); +	DRM_INFO("[radeon_ms] bus ready\n"); +	dev_priv->bus_ready = 1; +	return 0; +} + +void radeon_ms_agp_restore(struct drm_device *dev, struct radeon_state *state) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	MMIO_W(MC_AGP_LOCATION, state->mc_agp_location); +	MMIO_W(AGP_BASE, state->agp_base); +	MMIO_W(AGP_BASE_2, state->agp_base_2); +	MMIO_W(AGP_COMMAND, state->agp_command); +} + +void radeon_ms_agp_save(struct drm_device *dev, struct radeon_state *state) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	state->agp_command = MMIO_R(AGP_COMMAND); +	state->agp_base = MMIO_R(AGP_BASE); +	state->agp_base_2 = MMIO_R(AGP_BASE_2); +	state->mc_agp_location = MMIO_R(MC_AGP_LOCATION); +} + +struct drm_ttm_backend *radeon_ms_pcie_create_ttm(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_pcie_gart *pcie_gart; + +	pcie_gart = drm_ctl_calloc(1, sizeof (*pcie_gart), DRM_MEM_TTM); +	if (pcie_gart == NULL) { +		return NULL; +	} +	memset(pcie_gart, 0, sizeof(struct radeon_pcie_gart)); +	pcie_gart->populated = 0; +	pcie_gart->pcie = dev_priv->bus; +	pcie_gart->backend.func = &radeon_pcie_gart_ttm_backend; + +	return &pcie_gart->backend; +} + +int radeon_ms_pcie_finish(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_pcie *pcie = dev_priv->bus; + +	if (!dev_priv->bus_ready || pcie == NULL) { +		dev_priv->bus_ready = 0; +		return 0; +	} +	dev_priv->bus_ready = 0; +	if (pcie->gart_table) { +		drm_mem_reg_iounmap(dev, &pcie->gart_table_object->mem, +				    (void *)pcie->gart_table); +	} +	pcie->gart_table = NULL; +	if (pcie->gart_table_object) { +		mutex_lock(&dev->struct_mutex); +		drm_bo_usage_deref_locked(&pcie->gart_table_object); +		mutex_unlock(&dev->struct_mutex); +	} +	dev_priv->bus = NULL; +	drm_free(pcie, sizeof(*pcie), DRM_MEM_DRIVER); +	return 0; +} + +int radeon_ms_pcie_init(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_state *state = &dev_priv->driver_state; +	struct radeon_pcie *pcie; +	int ret = 0; + +	dev_priv->bus_ready = -1; +	/* allocate and clear device private structure */ +	pcie = drm_alloc(sizeof(struct radeon_pcie), DRM_MEM_DRIVER); +	if (pcie == NULL) { +		return -ENOMEM; +	} +	memset(pcie, 0, sizeof(struct radeon_pcie)); +	pcie->dev = dev; +	dev_priv->bus = (void *)pcie; +	pcie->gart_table_size = (dev_priv->gpu_gart_size / RADEON_PAGE_SIZE) * +				4; +	/* gart table start must be aligned on 16bytes, align it on one page */ +	ret = drm_buffer_object_create(dev, +				       pcie->gart_table_size, +				       drm_bo_type_kernel, +				       DRM_BO_FLAG_READ | +				       DRM_BO_FLAG_WRITE | +				       DRM_BO_FLAG_MEM_VRAM | +				       DRM_BO_FLAG_NO_EVICT, +				       DRM_BO_HINT_DONT_FENCE, +				       1, +				       0, +				       &pcie->gart_table_object); +	if (ret) { +		return ret; +	} +	ret = drm_mem_reg_ioremap(dev, &pcie->gart_table_object->mem, +				  (void **) &pcie->gart_table); +	if (ret) { +		DRM_ERROR("[radeon_ms] error mapping gart table: %d\n", ret); +		return ret; +	} +	DRM_INFO("[radeon_ms] gart table in vram at 0x%08lX\n", +		 pcie->gart_table_object->offset); +	memset((void *)pcie->gart_table, 0, pcie->gart_table_size); +	pcie->page_last = pcie->gart_table_size >> 2; +	state->pcie_tx_gart_discard_rd_addr_lo = +		REG_S(PCIE_TX_GART_DISCARD_RD_ADDR_LO, +				GART_DISCARD_RD_ADDR_LO, +				dev_priv->gpu_gart_start); +	state->pcie_tx_gart_discard_rd_addr_hi = +		REG_S(PCIE_TX_GART_DISCARD_RD_ADDR_HI, +				GART_DISCARD_RD_ADDR_HI, 0); +	state->pcie_tx_gart_base = +		REG_S(PCIE_TX_GART_BASE, GART_BASE, +				pcie->gart_table_object->offset); +	state->pcie_tx_gart_start_lo = +		REG_S(PCIE_TX_GART_START_LO, GART_START_LO, +				dev_priv->gpu_gart_start); +	state->pcie_tx_gart_start_hi = +		REG_S(PCIE_TX_GART_START_HI, GART_START_HI, 0); +	state->pcie_tx_gart_end_lo = +		REG_S(PCIE_TX_GART_END_LO, GART_END_LO, dev_priv->gpu_gart_end); +	state->pcie_tx_gart_end_hi = +		REG_S(PCIE_TX_GART_END_HI, GART_END_HI, 0); +	/* FIXME: why this ? */ +	state->aic_ctrl = 0; +	state->agp_base = 0;  +	state->agp_base_2 = 0;  +	state->bus_cntl = MMIO_R(BUS_CNTL); +	state->mc_agp_location = REG_S(MC_AGP_LOCATION, MC_AGP_START, 0xffc0) | +				 REG_S(MC_AGP_LOCATION, MC_AGP_TOP, 0xffff); +	state->pcie_tx_gart_cntl = +		PCIE_TX_GART_CNTL__GART_EN | +		REG_S(PCIE_TX_GART_CNTL, GART_UNMAPPED_ACCESS, +				GART_UNMAPPED_ACCESS__DISCARD) | +		REG_S(PCIE_TX_GART_CNTL, GART_MODE, GART_MODE__CACHE_32x128) | +		REG_S(PCIE_TX_GART_CNTL, GART_RDREQPATH_SEL, +				GART_RDREQPATH_SEL__HDP); +	DRM_INFO("[radeon_ms] gpu gart start 0x%08X\n", +		 PCIE_R(PCIE_TX_GART_START_LO)); +	DRM_INFO("[radeon_ms] gpu gart end   0x%08X\n", +		 PCIE_R(PCIE_TX_GART_END_LO)); +	DRM_INFO("[radeon_ms] bus ready\n"); +	dev_priv->bus_ready = 1; +	return 0; +} + +void radeon_ms_pcie_restore(struct drm_device *dev, struct radeon_state *state) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	/* disable gart before programing other registers */ +	radeon_ms_agp_restore(dev, state); +	PCIE_W(PCIE_TX_GART_CNTL, 0); +	PCIE_W(PCIE_TX_GART_BASE, state->pcie_tx_gart_base); +	PCIE_W(PCIE_TX_GART_BASE, state->pcie_tx_gart_base); +	PCIE_W(PCIE_TX_GART_DISCARD_RD_ADDR_HI, +	       state->pcie_tx_gart_discard_rd_addr_hi); +	PCIE_W(PCIE_TX_GART_DISCARD_RD_ADDR_LO, +	       state->pcie_tx_gart_discard_rd_addr_lo); +	PCIE_W(PCIE_TX_GART_START_HI, state->pcie_tx_gart_start_hi); +	PCIE_W(PCIE_TX_GART_START_LO, state->pcie_tx_gart_start_lo); +	PCIE_W(PCIE_TX_GART_END_HI, state->pcie_tx_gart_end_hi); +	PCIE_W(PCIE_TX_GART_END_LO, state->pcie_tx_gart_end_lo); +	PCIE_W(PCIE_TX_GART_CNTL, state->pcie_tx_gart_cntl); +} + +void radeon_ms_pcie_save(struct drm_device *dev, struct radeon_state *state) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	radeon_ms_agp_save(dev, state); +	state->pcie_tx_gart_base = PCIE_R(PCIE_TX_GART_BASE); +	state->pcie_tx_gart_base = PCIE_R(PCIE_TX_GART_BASE); +	state->pcie_tx_gart_discard_rd_addr_hi = +		PCIE_R(PCIE_TX_GART_DISCARD_RD_ADDR_HI); +	state->pcie_tx_gart_discard_rd_addr_lo = +		PCIE_R(PCIE_TX_GART_DISCARD_RD_ADDR_LO); +	state->pcie_tx_gart_start_hi = PCIE_R(PCIE_TX_GART_START_HI); +	state->pcie_tx_gart_start_lo = PCIE_R(PCIE_TX_GART_START_LO); +	state->pcie_tx_gart_end_hi = PCIE_R(PCIE_TX_GART_END_HI); +	state->pcie_tx_gart_end_lo = PCIE_R(PCIE_TX_GART_END_LO); +	state->pcie_tx_gart_cntl = PCIE_R(PCIE_TX_GART_CNTL); +} diff --git a/shared-core/radeon_ms_combios.c b/shared-core/radeon_ms_combios.c new file mode 100644 index 00000000..65609af9 --- /dev/null +++ b/shared-core/radeon_ms_combios.c @@ -0,0 +1,411 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: + *    Jérôme Glisse <glisse@freedesktop.org> + */ +#include "radeon_ms.h" + +extern struct radeon_ms_output radeon_ms_dac1; +extern struct radeon_ms_output radeon_ms_dac2; +extern const struct drm_output_funcs radeon_ms_output_funcs; + +static struct combios_connector_chip_info * +radeon_ms_combios_get_connector_chip_info(struct drm_device *dev, int chip_num) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_ms_rom *rom = &dev_priv->rom; +	struct combios_header *header; +	struct combios_connector_table *connector_table; +	struct combios_connector_chip_info *connector_chip_info; +	uint32_t offset; +	int numof_chips, i; + +	if (rom->type != ROM_COMBIOS || rom->rom_image == NULL) { +		return NULL; +	} +	header = rom->rom.combios_header; +	offset = header->usPointerToExtendedInitTable2; +	if ((offset + sizeof(struct combios_connector_table)) > rom->rom_size) { +		DRM_INFO("[radeon_ms] wrong COMBIOS connector offset\n"); +		return NULL; +	} +	if (!offset) { +		return NULL; +	} +	connector_table = (struct combios_connector_table *) +	                  &rom->rom_image[offset]; +	numof_chips = (connector_table->ucConnectorHeader & +		       BIOS_CONNECTOR_HEADER__NUMBER_OF_CHIPS__MASK) >> +		      BIOS_CONNECTOR_HEADER__NUMBER_OF_CHIPS__SHIFT; +	DRM_INFO("[radeon_ms] COMBIOS number of chip: %d (table rev: %d)\n", +		 numof_chips, +		 (connector_table->ucConnectorHeader & +		  BIOS_CONNECTOR_HEADER__TABLE_REVISION__MASK) >> +		 BIOS_CONNECTOR_HEADER__TABLE_REVISION__SHIFT); +	for (i = 0; i < numof_chips; i++) { +		int chip; + +		connector_chip_info = &connector_table->sChipConnectorInfo[i]; +		chip = (connector_chip_info->ucChipHeader & +			BIOS_CHIPINFO_HEADER__CHIP_NUMBER__MASK) >> +		       BIOS_CHIPINFO_HEADER__CHIP_NUMBER__SHIFT; +		DRM_INFO("[radeon_ms] COMBIOS chip: %d (asked for: %d)\n", +		         chip, chip_num); +		if (chip == chip_num) { +			return connector_chip_info; +		} +	} +	return NULL; +} + +static int radeon_combios_get_connector_infos(struct drm_device *dev, +					      int connector_info,  +					      int *connector_type,  +					      int *ddc_line, +					      int *tmds_type, +					      int *dac_type) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	*connector_type = (connector_info & BIOS_CONNECTOR_INFO__TYPE__MASK) >> +			  BIOS_CONNECTOR_INFO__TYPE__SHIFT; +	*ddc_line = (connector_info & BIOS_CONNECTOR_INFO__DDC_LINE__MASK) >> +		    BIOS_CONNECTOR_INFO__DDC_LINE__SHIFT; +	*tmds_type = (connector_info & BIOS_CONNECTOR_INFO__TMDS_TYPE__MASK) >> +		     BIOS_CONNECTOR_INFO__TMDS_TYPE__SHIFT; +	*dac_type = (connector_info & BIOS_CONNECTOR_INFO__DAC_TYPE__MASK) >> +		    BIOS_CONNECTOR_INFO__DAC_TYPE__SHIFT; + +	/* most XPRESS chips seem to specify DDC_CRT2 for their  +	 * VGA DDC port, however DDC never seems to work on that +	 * port.  Some have reported success on DDC_MONID, so  +	 * lets see what happens with that. +	 */ +	if (dev_priv->family == CHIP_RS400 && +	    *connector_type == BIOS_CONNECTOR_TYPE__CRT && +	    *ddc_line == BIOS_DDC_LINE__CRT2) { +		*ddc_line = BIOS_DDC_LINE__MONID01; +	} +	/* XPRESS desktop chips seem to have a proprietary +	 * connector listed for DVI-D, try and do the right +	 * thing here. +	 */ +	if (dev_priv->family == CHIP_RS400 && +	    *connector_type == BIOS_CONNECTOR_TYPE__PROPRIETARY) { +		DRM_INFO("[radeon_ms] COMBIOS Proprietary connector " +		         "found, assuming DVI-D\n"); +		*dac_type = 2; +	        *tmds_type = BIOS_TMDS_TYPE__EXTERNAL; +		*connector_type = BIOS_CONNECTOR_TYPE__DVI_D; +	} +	return 0; +} + +static int radeon_ms_combios_connector_add(struct drm_device *dev, +					   int connector_number, +					   int connector_type, +					   uint32_t i2c_reg) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_ms_connector *connector = NULL; +	struct drm_output *output = NULL; + +	connector = drm_alloc(sizeof(struct radeon_ms_connector), +			      DRM_MEM_DRIVER); +	if (connector == NULL) { +		radeon_ms_connectors_destroy(dev); +		return -ENOMEM; +	} +	memset(connector, 0, sizeof(struct radeon_ms_connector)); +	connector->monitor_type = MT_NONE; +	connector->type = connector_type; +	connector->i2c_reg = i2c_reg; + +	switch (connector->type) { +	case CONNECTOR_VGA: +		sprintf(connector->name, "VGA"); +		break; +	case CONNECTOR_DVI_I: +		sprintf(connector->name, "DVI-I"); +		break; +	case CONNECTOR_DVI_D: +		sprintf(connector->name, "DVI-D"); +		break; +	default: +		sprintf(connector->name, "UNKNOWN-CONNECTOR"); +		break; +	} + +	if (i2c_reg) { +		connector->i2c = radeon_ms_i2c_create(dev, +						      connector->i2c_reg, +						      connector->name); +		if (connector->i2c == NULL) { +			radeon_ms_connectors_destroy(dev); +			return -ENOMEM; +		} +	} else { +		connector->i2c = NULL; +	} + +	output = drm_output_create(dev, &radeon_ms_output_funcs, +				   connector->type); +	if (output == NULL) { +		radeon_ms_connectors_destroy(dev); +		return -EINVAL; +	} +	connector->output = output; +	output->driver_private = connector; +	output->possible_crtcs = 0x3; +	dev_priv->connectors[connector_number] = connector; +	return 0; +} + +int radeon_ms_combios_get_properties(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_ms_rom *rom = &dev_priv->rom; +	struct combios_pll_block *pll_block; +	struct combios_header *header; +	uint32_t offset; + +	if (rom->type != ROM_COMBIOS || rom->rom_image == NULL) { +		return 0; +	} +	header = rom->rom.combios_header; +	offset = header->usPointerToPllInfoBlock; +	if ((offset + sizeof(struct combios_pll_block)) > rom->rom_size) { +		DRM_INFO("[radeon_ms] wrong COMBIOS pll block offset\n"); +		return 0; +	} +	if (!offset) { +		return 0; +	} +	pll_block = (struct combios_pll_block *)&rom->rom_image[offset]; +	dev_priv->properties.pll_reference_freq = pll_block->usDotClockRefFreq; +	dev_priv->properties.pll_reference_div = pll_block->usDotClockRefDiv; +	dev_priv->properties.pll_min_pll_freq = pll_block->ulDotClockMinFreq; +	dev_priv->properties.pll_max_pll_freq = pll_block->ulDotClockMaxFreq; +	dev_priv->properties.pll_reference_freq *= 10; +	dev_priv->properties.pll_min_pll_freq *= 10; +	dev_priv->properties.pll_max_pll_freq *= 10; +	DRM_INFO("[radeon_ms] COMBIOS pll reference frequency : %d\n", +		 dev_priv->properties.pll_reference_freq); +	DRM_INFO("[radeon_ms] COMBIOS pll reference divider   : %d\n", +		 dev_priv->properties.pll_reference_div); +	DRM_INFO("[radeon_ms] COMBIOS pll minimum frequency   : %d\n", +		 dev_priv->properties.pll_min_pll_freq); +	DRM_INFO("[radeon_ms] COMBIOS pll maximum frequency   : %d\n", +		 dev_priv->properties.pll_max_pll_freq); +	return 1; +} + +int radeon_ms_connectors_from_combios(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct combios_connector_chip_info *connector_chip_info; +	int connector_type, ddc_line, tmds_type, dac_type; +	int dac1, dac2, tmdsint, tmdsext; +	int numof_connector, i, c = 0, added, j; +	uint32_t i2c_reg; +	int ret; + +	dac1 = dac2 = tmdsint = tmdsext = -1; +	connector_chip_info = radeon_ms_combios_get_connector_chip_info(dev, 1); +	if (connector_chip_info == NULL) { +		return -1; +	} +	numof_connector = (connector_chip_info->ucChipHeader & +			   BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__MASK) >> +			  BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__SHIFT; +	DRM_INFO("[radeon_ms] COMBIOS number of connector: %d\n", +	         numof_connector); +	for (i = 0; i < numof_connector; i++) { +		int connector_info = connector_chip_info->sConnectorInfo[i]; + +		ret = radeon_combios_get_connector_infos(dev, +							 connector_info,  +							 &connector_type,  +							 &ddc_line, +							 &tmds_type, +							 &dac_type); + +		switch (ddc_line) { +		case BIOS_DDC_LINE__MONID01: +			i2c_reg = GPIO_MONID; +			break; +		case BIOS_DDC_LINE__DVI: +			i2c_reg =  GPIO_DVI_DDC; +			break; +		case BIOS_DDC_LINE__VGA: +			i2c_reg = GPIO_DDC1; +			break; +		case BIOS_DDC_LINE__CRT2: +			i2c_reg = GPIO_CRT2_DDC; +			break; +		case BIOS_DDC_LINE__GPIOPAD: +			i2c_reg = VIPPAD_EN; +			break; +		case BIOS_DDC_LINE__ZV_LCDPAD: +			i2c_reg = VIPPAD1_EN; +			break; +		default: +			i2c_reg = 0; +			break; +		} +		added = 0; +		switch (connector_type) { +		case BIOS_CONNECTOR_TYPE__CRT: +			ret = radeon_ms_combios_connector_add(dev, c, +							      CONNECTOR_VGA, +							      i2c_reg); +			if (ret) { +				return ret; +			} +			added = 1; +			break; +		case BIOS_CONNECTOR_TYPE__DVI_I: +			ret = radeon_ms_combios_connector_add(dev, c, +							      CONNECTOR_DVI_I, +							      i2c_reg); +			if (ret) { +				return ret; +			} +			added = 1; +			break; +		case BIOS_CONNECTOR_TYPE__DVI_D: +			ret = radeon_ms_combios_connector_add(dev, c, +							      CONNECTOR_DVI_D, +							      i2c_reg); +			if (ret) { +				return ret; +			} +			added = 1; +			break; +		default: +			break; +		} +		if (added) { +			j = 0; +			/* find to which output this connector is associated  +			 * by following same algo as in: +			 * radeon_ms_outputs_from_combios*/ +			switch (dac_type) { +			case BIOS_DAC_TYPE__CRT: +				if (dac1 == -1) { +					dac1 = c; +				} +				dev_priv->connectors[c]->outputs[j++] = dac1; +				break; +			case BIOS_DAC_TYPE__NON_CRT: +				if (dac2 == -1) { +					dac2 = c; +				} +				dev_priv->connectors[c]->outputs[j++] = dac2; +				break; +			} +#if 0 +			switch (tmds_type) { +			case BIOS_TMDS_TYPE__INTERNAL: +				if (tmdsint == -1) { +					tmdsint = c; +				} +				dev_priv->connectors[c]->outputs[j++] = tmdsint; +				break; +			case BIOS_TMDS_TYPE__EXTERNAL: +				if (tmdsext == -1) { +					tmdsext = c; +				} +				dev_priv->connectors[c]->outputs[j++] = tmdsext; +				break; +			} +#endif +			c++; +		} +	} +	return c; +} + +int radeon_ms_outputs_from_combios(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct combios_connector_chip_info *connector_chip_info; +	int connector_type, ddc_line, tmds_type, dac_type; +	int numof_connector, i, dac1_present, dac2_present, c = 0; +	int ret; + +	dac1_present = dac2_present = 0; +	connector_chip_info = radeon_ms_combios_get_connector_chip_info(dev, 1); +	if (connector_chip_info == NULL) { +		return -1; +	} +	numof_connector = (connector_chip_info->ucChipHeader & +			   BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__MASK) >> +			  BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__SHIFT; +	DRM_INFO("[radeon_ms] COMBIOS number of connector: %d\n", +	         numof_connector); +	for (i = 0; i < numof_connector; i++) { +		int connector_info = connector_chip_info->sConnectorInfo[i]; + +		ret = radeon_combios_get_connector_infos(dev, +							 connector_info,  +							 &connector_type,  +							 &ddc_line, +							 &tmds_type, +							 &dac_type); + +		if (!dac1_present && dac_type == BIOS_DAC_TYPE__CRT) { +			dev_priv->outputs[c] = +				drm_alloc(sizeof(struct radeon_ms_output), +					  DRM_MEM_DRIVER); +			if (dev_priv->outputs[c] == NULL) { +				radeon_ms_outputs_destroy(dev); +				return -ENOMEM; +			} +			memcpy(dev_priv->outputs[c], &radeon_ms_dac1, +			       sizeof(struct radeon_ms_output)); +			dev_priv->outputs[c]->dev = dev; +			dev_priv->outputs[c]->initialize(dev_priv->outputs[c]); +			dac1_present = 1; +			c++; +		} +		if (!dac2_present && dac_type == BIOS_DAC_TYPE__NON_CRT) { +			dev_priv->outputs[c] = +				drm_alloc(sizeof(struct radeon_ms_output), +					  DRM_MEM_DRIVER); +			if (dev_priv->outputs[c] == NULL) { +				radeon_ms_outputs_destroy(dev); +				return -ENOMEM; +			} +			memcpy(dev_priv->outputs[c], &radeon_ms_dac2, +			       sizeof(struct radeon_ms_output)); +			dev_priv->outputs[c]->dev = dev; +			dev_priv->outputs[c]->initialize(dev_priv->outputs[c]); +			dac1_present = 1; +			c++; +		} +	} +	return c; +} diff --git a/shared-core/radeon_ms_combios.h b/shared-core/radeon_ms_combios.h new file mode 100644 index 00000000..fbceadf2 --- /dev/null +++ b/shared-core/radeon_ms_combios.h @@ -0,0 +1,385 @@ +/* + * Copyright 2006-2007 Advanced Micro Devices, Inc. + * Copyright 2007 Jérôme Glisse + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: + *    Jérôme Glisse <glisse@freedesktop.org> + */ +#ifndef __RADEON_MS_COMBIOS_H__ +#define __RADEON_MS_COMBIOS_H__ + +#pragma pack(1) + +#define ROM_HEADER                      0x48 + +struct combios_header +{ +    uint8_t  ucTypeDefinition; +    uint8_t  ucExtFunctionCode; +    uint8_t  ucOemID1; +    uint8_t  ucOemID2; +    uint8_t  ucBiosMajorRev; +    uint8_t  ucBiosMinorRev; +    uint16_t usStructureSize; +    uint16_t usPointerToSmi; +    uint16_t usPointerToPmid; +    uint16_t usPointerToInitTable; +    uint16_t usPointerToCrcChecksumBlock; +    uint16_t usPointerToConfigFilename; +    uint16_t usPointerToLogonMessage; +    uint16_t usPointerToMiscInfo; +    uint16_t usPciBusDevInitCode; +    uint16_t usBiosRuntimeSegmentAddress; +    uint16_t usIoBaseAddress; +    uint16_t usSubsystemVendorID; +    uint16_t usSubsystemID; +    uint16_t usPostVendorID; +    uint16_t usInt10Offset; +    uint16_t usInt10Segment; +    uint16_t usMonitorInfo; +    uint16_t usPointerToConfigBlock; +    uint16_t usPointerToDacDelayInfo; +    uint16_t usPointerToCapDataStruct; +    uint16_t usPointerToInternalCrtTables; +    uint16_t usPointerToPllInfoBlock; +    uint16_t usPointerToTVInfoTable; +    uint16_t usPointerToDFPInfoTable; +    uint16_t usPointerToHWConfigTable; +    uint16_t usPointerToMMConfigTable; +    uint32_t ulTVStdPatchTableSignature; +    uint16_t usPointerToTVStdPatchTable; +    uint16_t usPointerToPanelInfoTable; +    uint16_t usPointerToAsicInfoTable; +    uint16_t usPointerToAuroraInfoTable; +    uint16_t usPointerToPllInitTable; +    uint16_t usPointerToMemoryConfigTable; +    uint16_t usPointerToSaveMaskTable; +    uint16_t usPointerHardCodedEdid; +    uint16_t usPointerToExtendedInitTable1; +    uint16_t usPointerToExtendedInitTable2; +    uint16_t usPointerToDynamicClkTable; +    uint16_t usPointerToReservedMemoryTable; +    uint16_t usPointerToBridgetInitTable; +    uint16_t usPointerToExtTMDSInitTable; +    uint16_t usPointerToMemClkInfoTable; +    uint16_t usPointerToExtDACTable; +    uint16_t usPointerToMiscInfoTable; +}; + +struct combios_pll_block +{ +    /* Usually 6 */ +    uint8_t  ucPLLBiosVersion; +    /* Size in bytes */ +    uint8_t  ucStructureSize; +    /* Dot clock entry used for accelerated modes */ +    uint8_t  ucDotClockEntry; +    /* Dot clock entry used for extended VGA modes */ +    uint8_t  ucDotClockEntryVga; +    /* Offset into internal clock table used for by VGA parameter table */ +    uint16_t usPointerToInternalClock; +    /* Offset into actual programmed frequency table at POST */ +    uint16_t usPointerToFreqTable; +    /* XCLK setting, (memory clock in 10 KHz units) */ +    uint16_t usXclkSetting; +    /* MCLK setting, (engine clock in 10 KHz units) */ +    uint16_t usMclkSetting; +    /* Number of PLL information block to follow, currently value is 3 */ +    uint8_t  ucPllInfoBlockNumber; +    /* Size of each PLL information block */ +    uint8_t  ucPllInfoBlockSize; +    /* Reference frequency of the dot clock */ +    uint16_t usDotClockRefFreq; +    /* Reference Divider of the dot clock */ +    uint16_t usDotClockRefDiv; +    /* Min Frequency supported before post divider for the dot clock */ +    uint32_t ulDotClockMinFreq; +    /* Max Frequency can be supported for the dot clock */ +    uint32_t ulDotClockMaxFreq; +    /* Reference frequency of the MCLK, engine clock */ +    uint16_t usMclkRefFreq; +    /* Reference Divider of the MCLK, engine clock */ +    uint16_t usMclkRefDiv; +    /* Min Frequency supported before post divider for MCLK, engine clock */ +    uint32_t ulMclkMinFreq; +    /* Max Frequency can be supported for the MCLK, engine clock */ +    uint32_t ulMclkMaxFreq; +    /* Reference frequency of the XCLK, memory clock */ +    uint16_t usXclkRefFreq; +    /* Reference Divider of the XCLK, memory clock */ +    uint16_t usXclkRefDiv; +    /* Min Frequency supported before post divider for XCLK, memory clock */ +    uint32_t ulXclkMinFreq; +    /* Max Frequency can be supported for the XCLK, memory clock */ +    uint32_t ulXclkMaxFreq; + +    /*this is the PLL Information Table Extended structure version 10 */ +    uint8_t  ucNumberOfExtendedPllBlocks; +    uint8_t  ucSizePLLDefinition; +    uint16_t ulCrystalFrequencyPixelClock_pll; +    uint32_t ulMinInputPixelClockPLLFrequency; +    uint32_t ulMaxInputPixelClockPLLFrequency; +    uint32_t ulMinOutputPixelClockPLLFrequency; +    uint32_t ulMaxOutputPixelClockPLLFrequency; + +    /*version 11 */ +    uint16_t ulCrystalFrequencyEngineClock_pll; +    uint32_t ulMinInputFrequencyEngineClock_pll; +    uint32_t ulMaxInputFrequencyEngineClock_pll; +    uint32_t ulMinOutputFrequencyEngineClock_pll; +    uint32_t ulMaxOutputFrequencyEngineClock_pll; +    uint16_t ulCrystalFrequencyMemoryClock_pll; +    uint32_t ulMinInputFrequencyMemoryClock_pll; +    uint32_t ulMaxInputFrequencyMemoryClock_pll; +    uint32_t ulMinOutputFrequencyMemoryClock_pll; +    uint32_t ulMaxOutputFrequencyMemoryClock_pll; +    uint32_t ulMaximumDACOutputFrequency; +}; + +#define MAX_NO_OF_LCD_RES_TIMING                25 + +struct panel_information_table +{ +    uint8_t  ucPanelIdentification; +    uint8_t  ucPanelIDString[24]; +    uint16_t usHorizontalSize; +    uint16_t usVerticalSize; +    uint16_t usFlatPanelType; +    uint8_t  ucRedBitsPerPrimary; +    uint8_t  ucGreenBitsPerPrimary; +    uint8_t  ucBlueBitsPerPrimary; +    uint8_t  ucReservedBitsPerPrimary; +    uint8_t  ucPanelCaps; +    uint8_t  ucPowerSequenceDelayStepsInMS; +    uint8_t  ucSupportedRefreshRateExtended; +    uint16_t usExtendedPanelInfoTable; +    uint16_t usPtrToHalfFrameBufferInformationTable; +    uint16_t usVccOntoBlOn; +    uint16_t usOffDelay; +    uint16_t usRefDiv; +    uint8_t  ucPostDiv; +    uint16_t usFeedBackDiv; +    uint8_t  ucSpreadSpectrumType; +    uint16_t usSpreadSpectrumPercentage; +    uint8_t  ucBackLightLevel; +    uint8_t  ucBiasLevel; +    uint8_t  ucPowerSequenceDelay; +    uint32_t ulPanelData; +    uint8_t  ucPanelRefreshRateData; +    uint16_t usSupportedRefreshRate; +    uint16_t usModeTableOffset[MAX_NO_OF_LCD_RES_TIMING]; +}; + +struct extended_panel_info_table +{ +    uint8_t  ucExtendedPanelInfoTableVer; +    uint8_t  ucSSDelay; +    uint8_t  ucSSStepSizeIndex; +}; + +struct lcd_mode_table_center +{ +    uint16_t usHorizontalRes; +    uint16_t usVerticalRes; +    uint8_t  ucModeType; +    uint16_t usOffset2ExpParamTable; +    uint16_t usOffset2TvParamTable; +    uint16_t usPixelClock; +    uint16_t usPixelClockAdjustment; +    uint16_t usFpPos; +    uint8_t  ucReserved; +    uint8_t  ucMiscBits; +    uint16_t usCrtcHTotal; +    uint16_t usCrtcHDisp; +    uint16_t usCrtcHSyncStrt; +    uint8_t  ucCrtcHSyncWid; +    uint16_t usCrtcVTotal; +    uint16_t usCrtcVDisp; +    uint16_t usCrtcVSyncStrt; +    uint8_t  ucOvrWidTop; +}; + +struct lcd_mode_table_exp +{ +    uint16_t usPixelClock; +    uint16_t usPixelClockAdjustment; +    uint16_t usFpPos; +    uint8_t  ucReserved; +    uint8_t  ucMiscBits; +    uint16_t usCrtcHTotal; +    uint16_t usCrtcHDisp; +    uint16_t usCrtcHSyncStrt; +    uint8_t  ucCrtcHSyncWid; +    uint16_t usCrtcVTotal; +    uint16_t usCrtcVDisp; +    uint16_t usCrtcVSyncStrt; +    uint8_t  ucOvrWidTop; +    uint16_t usHorizontalBlendRatio; +    uint32_t ulVgaVertStretching; +    uint16_t usCopVertStretching; +    uint16_t usVgaExtVertStretching; +}; + +struct tmds_pll_cntl_block +{ +    uint16_t usClockUpperRange; +    uint32_t ulPllSetting; +}; + +#define MAX_PLL_CNTL_ENTRIES                    8 + +struct combios_dfp_info_table +{ +    uint8_t                     ucDFPInfoTableRev; +    uint8_t                     ucDFPInfoTableSize; +    uint16_t                    usOffsetDetailedTimingTable; +    uint8_t                     ucReserved; +    uint8_t                     ucNumberOfClockRanges; +    uint16_t                    usMaxPixelClock; +    uint32_t                    ulInitValueTmdsPllCntl; +    uint32_t                    ulFinalValueTmdsPllCntl; +    struct tmds_pll_cntl_block  sTmdsPllCntlBlock[MAX_PLL_CNTL_ENTRIES]; +}; + +struct combios_exttmds_table_header +{ +    uint8_t  ucTableRev; +    uint16_t usTableSize; +    uint8_t  ucNoBlocks; +}; + +struct combios_exttmds_block_header +{ +    uint16_t usMaxFreq; +    uint8_t  ucI2CSlaveAddr; +    uint8_t  ucI2CLine; +    uint8_t  ucConnectorId; +    uint8_t  ucFlags; +}; + +/* Connector table - applicable from Piglet and later ASICs +    byte 0     (embedded revision) +        [7:4]    = number of chips (valid number 1 - 15) +        [3:0]    = revision number of table (valid number 1 - 15) + +    byte 1 (Chip info) +        [7:4]    = chip number, max. 15 (valid number 1 - 15) +        [3:0]    = number of connectors for that chip, (valid number 1 - 15) +                   (number of connectors = number of 'Connector info' entries +                    for that chip) + +    byte 2,3 (Connector info) +        [15:12]    - connector type +            = 0     - no connector +            = 1     - proprietary +            = 2     - CRT +            = 3     - DVI-I +            = 4      - DVI-D +            = 5-15    - reserved for future expansion +        [11:8]    - DDC line pair used for that connector +            = 0     - no DDC +            = 1     - MONID 0/1 +            = 2     - DVI_DDC +            = 3     - VGA_DDC +            = 4     - CRT2_DDC +            = 5-15    - reserved for future expansion +        [5] - bit indicating presence of multiplexer for TV,CRT2 +        [7:6]    - reserved for future expansion +        [4]    - TMDS type +            = 0     - internal TMDS +            = 1      - external TMDS +        [3:1]    - reserved for future expansion +        [0]    - DAC associated with that connector +            = 0    - CRT DAC +            = 1    - non-CRT DAC (e.g. TV DAC, external DAC ..) + +    byte 4,5,6...     - byte 4,5 can be another "Connector info" word +                      describing another connector +                     - or byte 5 is a "Chip info" byte for anther chip, +                      then start with byte 5,6 to describe connectors +                      for that chip +                    - or byte 5 = 0 if all connectors for all chips on +                      board have been described, no more connector left +                      to describe. +*/ +#define BIOS_CONNECTOR_INFO__TYPE__MASK                   0xF000 +#define BIOS_CONNECTOR_INFO__TYPE__SHIFT                  0x0000000C +#define BIOS_CONNECTOR_TYPE__NONE                         0x00000000 +#define BIOS_CONNECTOR_TYPE__PROPRIETARY                  0x00000001 +#define BIOS_CONNECTOR_TYPE__CRT                          0x00000002 +#define BIOS_CONNECTOR_TYPE__DVI_I                        0x00000003 +#define BIOS_CONNECTOR_TYPE__DVI_D                        0x00000004 + +#define BIOS_CONNECTOR_INFO__DDC_LINE__MASK               0x0F00 +#define BIOS_CONNECTOR_INFO__DDC_LINE__SHIFT              0x00000008 +#define BIOS_DDC_LINE__NONE                               0x00000000 +#define BIOS_DDC_LINE__MONID01                            0x00000001 +#define BIOS_DDC_LINE__DVI                                0x00000002 +#define BIOS_DDC_LINE__VGA                                0x00000003 +#define BIOS_DDC_LINE__CRT2                               0x00000004 +#define BIOS_DDC_LINE__GPIOPAD                            0x00000005 +#define BIOS_DDC_LINE__ZV_LCDPAD                          0x00000006 + +#define BIOS_CONNECTOR_INFO__TMDS_TYPE__MASK              0x0010 +#define BIOS_CONNECTOR_INFO__TMDS_TYPE__SHIFT             0x00000004 +#define BIOS_TMDS_TYPE__INTERNAL                          0x00000000 +#define BIOS_TMDS_TYPE__EXTERNAL                          0x00000001 + +#define BIOS_CONNECTOR_INFO__DAC_TYPE__MASK               0x0001 +#define BIOS_CONNECTOR_INFO__DAC_TYPE__SHIFT              0x00000000 +#define BIOS_DAC_TYPE__CRT                                0x00000000 +#define BIOS_DAC_TYPE__NON_CRT                            0x00000001 + +#define BIOS_CONNECTOR_INFO__MUX_MASK                     0x00000020 +#define BIOS_CONNECTOR_INFO__MUX_SHIFT                    0x00000005 + +#define BIOS_CHIPINFO_HEADER__CHIP_NUMBER__MASK           0xF0 +#define BIOS_CHIPINFO_HEADER__CHIP_NUMBER__SHIFT          0x00000004 + +#define BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__MASK  0x0F +#define BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__SHIFT 0x00000000 + +#define BIOS_CHIPINFO__MAX_NUMBER_OF_CONNECTORS           0x00000010 + +struct combios_connector_chip_info +{ +    uint8_t  ucChipHeader; +    uint16_t sConnectorInfo[BIOS_CHIPINFO__MAX_NUMBER_OF_CONNECTORS]; +}; + +#define BIOS_CONNECTOR_HEADER__NUMBER_OF_CHIPS__MASK      0xF0 +#define BIOS_CONNECTOR_HEADER__NUMBER_OF_CHIPS__SHIFT     0x00000004 + +#define BIOS_CONNECTOR_HEADER__TABLE_REVISION__MASK       0x0F +#define BIOS_CONNECTOR_HEADER__TABLE_REVISION__SHIFT      0x00000000 + +struct combios_connector_table +{ +    uint8_t                            ucConnectorHeader; +    struct combios_connector_chip_info sChipConnectorInfo[0x10]; +}; + +#pragma pack() + +int combios_parse(unsigned char *rom, struct combios_header *header); + +#endif diff --git a/shared-core/radeon_ms_cp.c b/shared-core/radeon_ms_cp.c new file mode 100644 index 00000000..c01769bd --- /dev/null +++ b/shared-core/radeon_ms_cp.c @@ -0,0 +1,345 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Dave Airlie + * Copyright 2007 Alex Deucher + * All Rights Reserved. + * + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: + *    Jerome Glisse <glisse@freedesktop.org> + */ +#include "radeon_ms.h" + +static int radeon_ms_test_ring_buffer(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	int i, ret; +	uint32_t cmd[4]; + +	MMIO_W(SCRATCH_REG4, 0); +	cmd[0] = CP_PACKET0(SCRATCH_REG4, 0); +	cmd[1] = 0xdeadbeef; +	cmd[2] = CP_PACKET0(WAIT_UNTIL, 0); +	cmd[3] = WAIT_UNTIL__WAIT_2D_IDLECLEAN | +		WAIT_UNTIL__WAIT_HOST_IDLECLEAN; +	DRM_MEMORYBARRIER(); +	ret = radeon_ms_ring_emit(dev, cmd, 4); +	if (ret) { +		return 0; +	} +	DRM_UDELAY(100); + +	for (i = 0; i < dev_priv->usec_timeout; i++) { +		if (MMIO_R(SCRATCH_REG4) == 0xdeadbeef) { +			DRM_INFO("[radeon_ms] cp test succeeded in %d usecs\n", +				 i); +			return 1; +		} +		DRM_UDELAY(1); +	} +	DRM_INFO("[radeon_ms] cp test failed\n"); +	return 0; +} + +static int radeon_ms_test_write_back(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	uint32_t tmp; + +	if (dev_priv->ring_buffer_object == NULL || +	    dev_priv->ring_buffer == NULL) +	    return 0; +	dev_priv->write_back_area[0] = 0x0; +	MMIO_W(SCRATCH_REG0, 0xdeadbeef); +	for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) { +		if (dev_priv->write_back_area[0] == 0xdeadbeef) +			break; +		DRM_UDELAY(1); +	} +	if (tmp < dev_priv->usec_timeout) { +		DRM_INFO("[radeon_ms] writeback test succeeded in %d usecs\n", +			 tmp); +		return 1; +	} +	MMIO_W(SCRATCH_UMSK, 0x0); +	DRM_INFO("[radeon_ms] writeback test failed\n"); +	return 0; +} + +static __inline__ void radeon_ms_load_mc(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	int i; + +	MMIO_W(CP_ME_RAM_ADDR, 0); +	for (i = 0; i < 256; i++) { +		MMIO_W(CP_ME_RAM_DATAH, dev_priv->microcode[(i * 2) + 1]); +		MMIO_W(CP_ME_RAM_DATAL, dev_priv->microcode[(i * 2) + 0]); +	} +} + +int radeon_ms_cp_finish(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	if (!dev_priv->cp_ready) { +		return 0; +	} +	dev_priv->cp_ready = 0; +	radeon_ms_wait_for_idle(dev); +	DRM_INFO("[radeon_ms] cp idle\n"); +	radeon_ms_cp_stop(dev); + +	DRM_INFO("[radeon_ms] ring buffer %p\n", dev_priv->ring_buffer); +	if (dev_priv->ring_buffer) { +		drm_bo_kunmap(&dev_priv->ring_buffer_map); +	} +	dev_priv->ring_buffer = NULL; +	DRM_INFO("[radeon_ms] ring buffer object %p\n", dev_priv->ring_buffer_object); +	if (dev_priv->ring_buffer_object) { +		mutex_lock(&dev->struct_mutex); +		drm_bo_usage_deref_locked(&dev_priv->ring_buffer_object); +		mutex_unlock(&dev->struct_mutex); +	} +	return 0; +} + +int radeon_ms_cp_init(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_state *state = &dev_priv->driver_state; +	int ret = 0; + +	dev_priv->cp_ready = -1; +	if (dev_priv->microcode == NULL) { +		DRM_INFO("[radeon_ms] no microcode not starting cp"); +		return 0; +	} +	/* we allocate an extra page for all write back stuff */ +	ret = drm_buffer_object_create(dev, +			dev_priv->ring_buffer_size + +			dev_priv->write_back_area_size, +			drm_bo_type_kernel, +			DRM_BO_FLAG_READ | +			DRM_BO_FLAG_WRITE | +			DRM_BO_FLAG_MEM_TT | +			DRM_BO_FLAG_NO_EVICT, +			DRM_BO_HINT_DONT_FENCE, +			1, +			0, +			&dev_priv->ring_buffer_object); +	if (ret) { +		return ret; +	} +	memset(&dev_priv->ring_buffer_map, 0, sizeof(struct drm_bo_kmap_obj)); +	ret = drm_bo_kmap(dev_priv->ring_buffer_object, +			dev_priv->ring_buffer_object->mem.mm_node->start, +			dev_priv->ring_buffer_object->mem.num_pages, +			&dev_priv->ring_buffer_map); +	if (ret) { +		DRM_ERROR("[radeon_ms] error mapping ring buffer: %d\n", ret); +		return ret; +	} +	dev_priv->ring_buffer = dev_priv->ring_buffer_map.virtual;  +	dev_priv->write_back_area = +		&dev_priv->ring_buffer[dev_priv->ring_buffer_size >> 2]; +	/* setup write back offset */ +	state->scratch_umsk = 0x7;  +	state->scratch_addr =  +		REG_S(SCRATCH_ADDR, SCRATCH_ADDR, +				(dev_priv->ring_buffer_object->offset + +				 dev_priv->ring_buffer_size + +				 dev_priv->gpu_gart_start) >> 5); +	MMIO_W(SCRATCH_ADDR, state->scratch_addr); +	MMIO_W(SCRATCH_UMSK, REG_S(SCRATCH_UMSK, SCRATCH_UMSK, 0x7)); +	DRM_INFO("[radeon_ms] write back at 0x%08X in gpu space\n", +		 MMIO_R(SCRATCH_ADDR)); +	dev_priv->write_back = radeon_ms_test_write_back(dev); + +	/* stop cp so it's in know state */ +	radeon_ms_cp_stop(dev); +	if (dev_priv->ring_rptr) { +		DRM_INFO("[radeon_ms] failed to set cp read ptr to 0\n"); +	} else { +		DRM_INFO("[radeon_ms] set cp read ptr to 0\n"); +	} +	dev_priv->ring_mask = (dev_priv->ring_buffer_size / 4) - 1; + +	/* load microcode */ +	DRM_INFO("[radeon_ms] load microcode\n"); +	radeon_ms_load_mc(dev); +	/* initialize CP registers */ +	state->cp_rb_cntl = +		REG_S(CP_RB_CNTL, RB_BUFSZ, +				drm_order(dev_priv->ring_buffer_size / 8)) | +		REG_S(CP_RB_CNTL, RB_BLKSZ, drm_order(4096 / 8)) | +		REG_S(CP_RB_CNTL, MAX_FETCH, 2); +	if (!dev_priv->write_back) { +		state->cp_rb_cntl |= CP_RB_CNTL__RB_NO_UPDATE; +	} +	state->cp_rb_base = +		REG_S(CP_RB_BASE, RB_BASE, +				(dev_priv->ring_buffer_object->offset + +				 dev_priv->gpu_gart_start) >> 2); +	/* read ptr writeback just after the +	 * 8 scratch registers 32 = 8*4 */ +	state->cp_rb_rptr_addr = +		REG_S(CP_RB_RPTR_ADDR, RB_RPTR_ADDR, +				(dev_priv->ring_buffer_object->offset + +				 dev_priv->ring_buffer_size + 32 + +				 dev_priv->gpu_gart_start) >> 2); +	state->cp_rb_wptr = dev_priv->ring_wptr; +	state->cp_rb_wptr_delay = +		REG_S(CP_RB_WPTR_DELAY, PRE_WRITE_TIMER, 64) | +		REG_S(CP_RB_WPTR_DELAY, PRE_WRITE_LIMIT, 8); +	state->cp_rb_wptr_delay = 0;  + +	radeon_ms_cp_restore(dev, state); +	DRM_INFO("[radeon_ms] ring buffer at 0x%08X in gpu space\n", +		 MMIO_R(CP_RB_BASE)); + +	/* compute free space */ +	dev_priv->ring_free = 0; +	ret = radeon_ms_cp_wait(dev, 64); +	if (ret) { +		/* we shouldn't fail here */ +		DRM_INFO("[radeon_ms] failed to get ring free space\n"); +		return ret; +	} +	DRM_INFO("[radeon_ms] free ring size: %d\n", dev_priv->ring_free * 4); + +	MMIO_W(CP_CSQ_CNTL, REG_S(CP_CSQ_CNTL, CSQ_MODE, +				CSQ_MODE__CSQ_PRIBM_INDBM)); +	if (!radeon_ms_test_ring_buffer(dev)) { +		DRM_INFO("[radeon_ms] cp doesn't work\n"); +		/* disable ring should wait idle before */ +		radeon_ms_cp_stop(dev); +		return -EBUSY; +	} +	/* waaooo the cp is ready & working */ +	DRM_INFO("[radeon_ms] cp ready, enjoy\n"); +	dev_priv->cp_ready = 1; +	return 0; +} + +void radeon_ms_cp_restore(struct drm_device *dev, struct radeon_state *state) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	radeon_ms_wait_for_idle(dev); +	MMIO_W(SCRATCH_ADDR, state->scratch_addr); +	MMIO_W(SCRATCH_UMSK, state->scratch_umsk); +	MMIO_W(CP_RB_BASE, state->cp_rb_base); +	MMIO_W(CP_RB_RPTR_ADDR, state->cp_rb_rptr_addr); +	MMIO_W(CP_RB_WPTR_DELAY, state->cp_rb_wptr_delay); +	MMIO_W(CP_RB_CNTL, state->cp_rb_cntl); +	/* Sync everything up */ +	MMIO_W(ISYNC_CNTL, ISYNC_CNTL__ISYNC_ANY2D_IDLE3D | +			   ISYNC_CNTL__ISYNC_ANY3D_IDLE2D | +			   ISYNC_CNTL__ISYNC_WAIT_IDLEGUI | +			   ISYNC_CNTL__ISYNC_CPSCRATCH_IDLEGUI); +} + +void radeon_ms_cp_save(struct drm_device *dev, struct radeon_state *state) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	state->scratch_addr = MMIO_R(SCRATCH_ADDR); +	state->scratch_umsk = MMIO_R(SCRATCH_UMSK); +	state->cp_rb_base = MMIO_R(CP_RB_BASE); +	state->cp_rb_rptr_addr = MMIO_R(CP_RB_RPTR_ADDR); +	state->cp_rb_wptr_delay = MMIO_R(CP_RB_WPTR_DELAY); +	state->cp_rb_wptr = MMIO_R(CP_RB_WPTR); +	state->cp_rb_cntl = MMIO_R(CP_RB_CNTL); +} + +void radeon_ms_cp_stop(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	MMIO_W(CP_CSQ_CNTL, REG_S(CP_CSQ_CNTL, CSQ_MODE, +				CSQ_MODE__CSQ_PRIDIS_INDDIS)); +	MMIO_W(CP_RB_CNTL, CP_RB_CNTL__RB_RPTR_WR_ENA); +	MMIO_W(CP_RB_RPTR_WR, 0); +	MMIO_W(CP_RB_WPTR, 0); +	DRM_UDELAY(5); +	dev_priv->ring_wptr = dev_priv->ring_rptr = MMIO_R(CP_RB_RPTR); +	MMIO_W(CP_RB_WPTR, dev_priv->ring_wptr); +} + +int radeon_ms_cp_wait(struct drm_device *dev, int n) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	uint32_t i, last_rptr, p = 0; + +	last_rptr = MMIO_R(CP_RB_RPTR); +	for (i = 0; i < dev_priv->usec_timeout; i++) { +		dev_priv->ring_rptr = MMIO_R(CP_RB_RPTR); +		if (last_rptr != dev_priv->ring_rptr) { +			/* the ring is progressing no lockup */ +			p = 1; +		} +		dev_priv->ring_free = (((int)dev_priv->ring_rptr) - +				       ((int)dev_priv->ring_wptr)); +		if (dev_priv->ring_free <= 0) +			dev_priv->ring_free += (dev_priv->ring_buffer_size / 4); +		if (dev_priv->ring_free > n) +			return 0; +		last_rptr = dev_priv->ring_rptr; +		DRM_UDELAY(1); +	} +	if (p) { +		DRM_INFO("[radeon_ms] timed out waiting free slot\n"); +	} else { +		DRM_INFO("[radeon_ms] cp have lickely locked up\n"); +	} +	return -EBUSY; +} + +int radeon_ms_ring_emit(struct drm_device *dev, uint32_t *cmd, uint32_t count) +{ +	static spinlock_t ring_lock = SPIN_LOCK_UNLOCKED; +	struct drm_radeon_private *dev_priv = dev->dev_private; +	uint32_t i = 0; + +	if (!count) +		return -EINVAL; + +	spin_lock(&ring_lock); +	if (dev_priv->ring_free <= (count)) { +		spin_unlock(&ring_lock); +		return -EBUSY; +	} +	dev_priv->ring_free -= count; +	for (i = 0; i < count; i++) { +		dev_priv->ring_buffer[dev_priv->ring_wptr] = cmd[i]; +		dev_priv->ring_wptr++; +		dev_priv->ring_wptr &= dev_priv->ring_mask; +	} +	/* commit ring */ +	DRM_MEMORYBARRIER(); +	MMIO_W(CP_RB_WPTR, REG_S(CP_RB_WPTR, RB_WPTR, dev_priv->ring_wptr)); +	/* read from PCI bus to ensure correct posting */ +	MMIO_R(CP_RB_WPTR); +	spin_unlock(&ring_lock); +	return 0; +} diff --git a/shared-core/radeon_ms_cp_mc.c b/shared-core/radeon_ms_cp_mc.c new file mode 100644 index 00000000..f0397d87 --- /dev/null +++ b/shared-core/radeon_ms_cp_mc.c @@ -0,0 +1,801 @@ +/* + * Copyright 2007  Advanced Micro Devices, Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ +#include "radeon_ms.h" + +/* CP microcode (from ATI) */ + +const uint32_t radeon_cp_microcode[] = { +	0x21007000, 0000000000, +	0x20007000, 0000000000, +	0x000000b4, 0x00000004, +	0x000000b8, 0x00000004, +	0x6f5b4d4c, 0000000000, +	0x4c4c427f, 0000000000, +	0x5b568a92, 0000000000, +	0x4ca09c6d, 0000000000, +	0xad4c4c4c, 0000000000, +	0x4ce1af3d, 0000000000, +	0xd8afafaf, 0000000000, +	0xd64c4cdc, 0000000000, +	0x4cd10d10, 0000000000, +	0x000f0000, 0x00000016, +	0x362f242d, 0000000000, +	0x00000012, 0x00000004, +	0x000f0000, 0x00000016, +	0x362f282d, 0000000000, +	0x000380e7, 0x00000002, +	0x04002c97, 0x00000002, +	0x000f0001, 0x00000016, +	0x333a3730, 0000000000, +	0x000077ef, 0x00000002, +	0x00061000, 0x00000002, +	0x00000021, 0x0000001a, +	0x00004000, 0x0000001e, +	0x00061000, 0x00000002, +	0x00000021, 0x0000001a, +	0x00004000, 0x0000001e, +	0x00061000, 0x00000002, +	0x00000021, 0x0000001a, +	0x00004000, 0x0000001e, +	0x00000017, 0x00000004, +	0x0003802b, 0x00000002, +	0x040067e0, 0x00000002, +	0x00000017, 0x00000004, +	0x000077e0, 0x00000002, +	0x00065000, 0x00000002, +	0x000037e1, 0x00000002, +	0x040067e1, 0x00000006, +	0x000077e0, 0x00000002, +	0x000077e1, 0x00000002, +	0x000077e1, 0x00000006, +	0xffffffff, 0000000000, +	0x10000000, 0000000000, +	0x0003802b, 0x00000002, +	0x040067e0, 0x00000006, +	0x00007675, 0x00000002, +	0x00007676, 0x00000002, +	0x00007677, 0x00000002, +	0x00007678, 0x00000006, +	0x0003802c, 0x00000002, +	0x04002676, 0x00000002, +	0x00007677, 0x00000002, +	0x00007678, 0x00000006, +	0x0000002f, 0x00000018, +	0x0000002f, 0x00000018, +	0000000000, 0x00000006, +	0x00000030, 0x00000018, +	0x00000030, 0x00000018, +	0000000000, 0x00000006, +	0x01605000, 0x00000002, +	0x00065000, 0x00000002, +	0x00098000, 0x00000002, +	0x00061000, 0x00000002, +	0x64c0603e, 0x00000004, +	0x000380e6, 0x00000002, +	0x040025c5, 0x00000002, +	0x00080000, 0x00000016, +	0000000000, 0000000000, +	0x0400251d, 0x00000002, +	0x00007580, 0x00000002, +	0x00067581, 0x00000002, +	0x04002580, 0x00000002, +	0x00067581, 0x00000002, +	0x00000049, 0x00000004, +	0x00005000, 0000000000, +	0x000380e6, 0x00000002, +	0x040025c5, 0x00000002, +	0x00061000, 0x00000002, +	0x0000750e, 0x00000002, +	0x00019000, 0x00000002, +	0x00011055, 0x00000014, +	0x00000055, 0x00000012, +	0x0400250f, 0x00000002, +	0x0000504f, 0x00000004, +	0x000380e6, 0x00000002, +	0x040025c5, 0x00000002, +	0x00007565, 0x00000002, +	0x00007566, 0x00000002, +	0x00000058, 0x00000004, +	0x000380e6, 0x00000002, +	0x040025c5, 0x00000002, +	0x01e655b4, 0x00000002, +	0x4401b0e4, 0x00000002, +	0x01c110e4, 0x00000002, +	0x26667066, 0x00000018, +	0x040c2565, 0x00000002, +	0x00000066, 0x00000018, +	0x04002564, 0x00000002, +	0x00007566, 0x00000002, +	0x0000005d, 0x00000004, +	0x00401069, 0x00000008, +	0x00101000, 0x00000002, +	0x000d80ff, 0x00000002, +	0x0080006c, 0x00000008, +	0x000f9000, 0x00000002, +	0x000e00ff, 0x00000002, +	0000000000, 0x00000006, +	0x0000008f, 0x00000018, +	0x0000005b, 0x00000004, +	0x000380e6, 0x00000002, +	0x040025c5, 0x00000002, +	0x00007576, 0x00000002, +	0x00065000, 0x00000002, +	0x00009000, 0x00000002, +	0x00041000, 0x00000002, +	0x0c00350e, 0x00000002, +	0x00049000, 0x00000002, +	0x00051000, 0x00000002, +	0x01e785f8, 0x00000002, +	0x00200000, 0x00000002, +	0x0060007e, 0x0000000c, +	0x00007563, 0x00000002, +	0x006075f0, 0x00000021, +	0x20007073, 0x00000004, +	0x00005073, 0x00000004, +	0x000380e6, 0x00000002, +	0x040025c5, 0x00000002, +	0x00007576, 0x00000002, +	0x00007577, 0x00000002, +	0x0000750e, 0x00000002, +	0x0000750f, 0x00000002, +	0x00a05000, 0x00000002, +	0x00600083, 0x0000000c, +	0x006075f0, 0x00000021, +	0x000075f8, 0x00000002, +	0x00000083, 0x00000004, +	0x000a750e, 0x00000002, +	0x000380e6, 0x00000002, +	0x040025c5, 0x00000002, +	0x0020750f, 0x00000002, +	0x00600086, 0x00000004, +	0x00007570, 0x00000002, +	0x00007571, 0x00000002, +	0x00007572, 0x00000006, +	0x000380e6, 0x00000002, +	0x040025c5, 0x00000002, +	0x00005000, 0x00000002, +	0x00a05000, 0x00000002, +	0x00007568, 0x00000002, +	0x00061000, 0x00000002, +	0x00000095, 0x0000000c, +	0x00058000, 0x00000002, +	0x0c607562, 0x00000002, +	0x00000097, 0x00000004, +	0x000380e6, 0x00000002, +	0x040025c5, 0x00000002, +	0x00600096, 0x00000004, +	0x400070e5, 0000000000, +	0x000380e6, 0x00000002, +	0x040025c5, 0x00000002, +	0x000380e5, 0x00000002, +	0x000000a8, 0x0000001c, +	0x000650aa, 0x00000018, +	0x040025bb, 0x00000002, +	0x000610ab, 0x00000018, +	0x040075bc, 0000000000, +	0x000075bb, 0x00000002, +	0x000075bc, 0000000000, +	0x00090000, 0x00000006, +	0x00090000, 0x00000002, +	0x000d8002, 0x00000006, +	0x00007832, 0x00000002, +	0x00005000, 0x00000002, +	0x000380e7, 0x00000002, +	0x04002c97, 0x00000002, +	0x00007820, 0x00000002, +	0x00007821, 0x00000002, +	0x00007800, 0000000000, +	0x01200000, 0x00000002, +	0x20077000, 0x00000002, +	0x01200000, 0x00000002, +	0x20007000, 0x00000002, +	0x00061000, 0x00000002, +	0x0120751b, 0x00000002, +	0x8040750a, 0x00000002, +	0x8040750b, 0x00000002, +	0x00110000, 0x00000002, +	0x000380e5, 0x00000002, +	0x000000c6, 0x0000001c, +	0x000610ab, 0x00000018, +	0x844075bd, 0x00000002, +	0x000610aa, 0x00000018, +	0x840075bb, 0x00000002, +	0x000610ab, 0x00000018, +	0x844075bc, 0x00000002, +	0x000000c9, 0x00000004, +	0x804075bd, 0x00000002, +	0x800075bb, 0x00000002, +	0x804075bc, 0x00000002, +	0x00108000, 0x00000002, +	0x01400000, 0x00000002, +	0x006000cd, 0x0000000c, +	0x20c07000, 0x00000020, +	0x000000cf, 0x00000012, +	0x00800000, 0x00000006, +	0x0080751d, 0x00000006, +	0000000000, 0000000000, +	0x0000775c, 0x00000002, +	0x00a05000, 0x00000002, +	0x00661000, 0x00000002, +	0x0460275d, 0x00000020, +	0x00004000, 0000000000, +	0x01e00830, 0x00000002, +	0x21007000, 0000000000, +	0x6464614d, 0000000000, +	0x69687420, 0000000000, +	0x00000073, 0000000000, +	0000000000, 0000000000, +	0x00005000, 0x00000002, +	0x000380d0, 0x00000002, +	0x040025e0, 0x00000002, +	0x000075e1, 0000000000, +	0x00000001, 0000000000, +	0x000380e0, 0x00000002, +	0x04002394, 0x00000002, +	0x00005000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0x00000008, 0000000000, +	0x00000004, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +}; + +const uint32_t r200_cp_microcode[] = { +	0x21007000, 0000000000, +	0x20007000, 0000000000, +	0x000000ab, 0x00000004, +	0x000000af, 0x00000004, +	0x66544a49, 0000000000, +	0x49494174, 0000000000, +	0x54517d83, 0000000000, +	0x498d8b64, 0000000000, +	0x49494949, 0000000000, +	0x49da493c, 0000000000, +	0x49989898, 0000000000, +	0xd34949d5, 0000000000, +	0x9dc90e11, 0000000000, +	0xce9b9b9b, 0000000000, +	0x000f0000, 0x00000016, +	0x352e232c, 0000000000, +	0x00000013, 0x00000004, +	0x000f0000, 0x00000016, +	0x352e272c, 0000000000, +	0x000f0001, 0x00000016, +	0x3239362f, 0000000000, +	0x000077ef, 0x00000002, +	0x00061000, 0x00000002, +	0x00000020, 0x0000001a, +	0x00004000, 0x0000001e, +	0x00061000, 0x00000002, +	0x00000020, 0x0000001a, +	0x00004000, 0x0000001e, +	0x00061000, 0x00000002, +	0x00000020, 0x0000001a, +	0x00004000, 0x0000001e, +	0x00000016, 0x00000004, +	0x0003802a, 0x00000002, +	0x040067e0, 0x00000002, +	0x00000016, 0x00000004, +	0x000077e0, 0x00000002, +	0x00065000, 0x00000002, +	0x000037e1, 0x00000002, +	0x040067e1, 0x00000006, +	0x000077e0, 0x00000002, +	0x000077e1, 0x00000002, +	0x000077e1, 0x00000006, +	0xffffffff, 0000000000, +	0x10000000, 0000000000, +	0x0003802a, 0x00000002, +	0x040067e0, 0x00000006, +	0x00007675, 0x00000002, +	0x00007676, 0x00000002, +	0x00007677, 0x00000002, +	0x00007678, 0x00000006, +	0x0003802b, 0x00000002, +	0x04002676, 0x00000002, +	0x00007677, 0x00000002, +	0x00007678, 0x00000006, +	0x0000002e, 0x00000018, +	0x0000002e, 0x00000018, +	0000000000, 0x00000006, +	0x0000002f, 0x00000018, +	0x0000002f, 0x00000018, +	0000000000, 0x00000006, +	0x01605000, 0x00000002, +	0x00065000, 0x00000002, +	0x00098000, 0x00000002, +	0x00061000, 0x00000002, +	0x64c0603d, 0x00000004, +	0x00080000, 0x00000016, +	0000000000, 0000000000, +	0x0400251d, 0x00000002, +	0x00007580, 0x00000002, +	0x00067581, 0x00000002, +	0x04002580, 0x00000002, +	0x00067581, 0x00000002, +	0x00000046, 0x00000004, +	0x00005000, 0000000000, +	0x00061000, 0x00000002, +	0x0000750e, 0x00000002, +	0x00019000, 0x00000002, +	0x00011055, 0x00000014, +	0x00000055, 0x00000012, +	0x0400250f, 0x00000002, +	0x0000504a, 0x00000004, +	0x00007565, 0x00000002, +	0x00007566, 0x00000002, +	0x00000051, 0x00000004, +	0x01e655b4, 0x00000002, +	0x4401b0dc, 0x00000002, +	0x01c110dc, 0x00000002, +	0x2666705d, 0x00000018, +	0x040c2565, 0x00000002, +	0x0000005d, 0x00000018, +	0x04002564, 0x00000002, +	0x00007566, 0x00000002, +	0x00000054, 0x00000004, +	0x00401060, 0x00000008, +	0x00101000, 0x00000002, +	0x000d80ff, 0x00000002, +	0x00800063, 0x00000008, +	0x000f9000, 0x00000002, +	0x000e00ff, 0x00000002, +	0000000000, 0x00000006, +	0x00000080, 0x00000018, +	0x00000054, 0x00000004, +	0x00007576, 0x00000002, +	0x00065000, 0x00000002, +	0x00009000, 0x00000002, +	0x00041000, 0x00000002, +	0x0c00350e, 0x00000002, +	0x00049000, 0x00000002, +	0x00051000, 0x00000002, +	0x01e785f8, 0x00000002, +	0x00200000, 0x00000002, +	0x00600073, 0x0000000c, +	0x00007563, 0x00000002, +	0x006075f0, 0x00000021, +	0x20007068, 0x00000004, +	0x00005068, 0x00000004, +	0x00007576, 0x00000002, +	0x00007577, 0x00000002, +	0x0000750e, 0x00000002, +	0x0000750f, 0x00000002, +	0x00a05000, 0x00000002, +	0x00600076, 0x0000000c, +	0x006075f0, 0x00000021, +	0x000075f8, 0x00000002, +	0x00000076, 0x00000004, +	0x000a750e, 0x00000002, +	0x0020750f, 0x00000002, +	0x00600079, 0x00000004, +	0x00007570, 0x00000002, +	0x00007571, 0x00000002, +	0x00007572, 0x00000006, +	0x00005000, 0x00000002, +	0x00a05000, 0x00000002, +	0x00007568, 0x00000002, +	0x00061000, 0x00000002, +	0x00000084, 0x0000000c, +	0x00058000, 0x00000002, +	0x0c607562, 0x00000002, +	0x00000086, 0x00000004, +	0x00600085, 0x00000004, +	0x400070dd, 0000000000, +	0x000380dd, 0x00000002, +	0x00000093, 0x0000001c, +	0x00065095, 0x00000018, +	0x040025bb, 0x00000002, +	0x00061096, 0x00000018, +	0x040075bc, 0000000000, +	0x000075bb, 0x00000002, +	0x000075bc, 0000000000, +	0x00090000, 0x00000006, +	0x00090000, 0x00000002, +	0x000d8002, 0x00000006, +	0x00005000, 0x00000002, +	0x00007821, 0x00000002, +	0x00007800, 0000000000, +	0x00007821, 0x00000002, +	0x00007800, 0000000000, +	0x01665000, 0x00000002, +	0x000a0000, 0x00000002, +	0x000671cc, 0x00000002, +	0x0286f1cd, 0x00000002, +	0x000000a3, 0x00000010, +	0x21007000, 0000000000, +	0x000000aa, 0x0000001c, +	0x00065000, 0x00000002, +	0x000a0000, 0x00000002, +	0x00061000, 0x00000002, +	0x000b0000, 0x00000002, +	0x38067000, 0x00000002, +	0x000a00a6, 0x00000004, +	0x20007000, 0000000000, +	0x01200000, 0x00000002, +	0x20077000, 0x00000002, +	0x01200000, 0x00000002, +	0x20007000, 0000000000, +	0x00061000, 0x00000002, +	0x0120751b, 0x00000002, +	0x8040750a, 0x00000002, +	0x8040750b, 0x00000002, +	0x00110000, 0x00000002, +	0x000380dd, 0x00000002, +	0x000000bd, 0x0000001c, +	0x00061096, 0x00000018, +	0x844075bd, 0x00000002, +	0x00061095, 0x00000018, +	0x840075bb, 0x00000002, +	0x00061096, 0x00000018, +	0x844075bc, 0x00000002, +	0x000000c0, 0x00000004, +	0x804075bd, 0x00000002, +	0x800075bb, 0x00000002, +	0x804075bc, 0x00000002, +	0x00108000, 0x00000002, +	0x01400000, 0x00000002, +	0x006000c4, 0x0000000c, +	0x20c07000, 0x00000020, +	0x000000c6, 0x00000012, +	0x00800000, 0x00000006, +	0x0080751d, 0x00000006, +	0x000025bb, 0x00000002, +	0x000040c0, 0x00000004, +	0x0000775c, 0x00000002, +	0x00a05000, 0x00000002, +	0x00661000, 0x00000002, +	0x0460275d, 0x00000020, +	0x00004000, 0000000000, +	0x00007999, 0x00000002, +	0x00a05000, 0x00000002, +	0x00661000, 0x00000002, +	0x0460299b, 0x00000020, +	0x00004000, 0000000000, +	0x01e00830, 0x00000002, +	0x21007000, 0000000000, +	0x00005000, 0x00000002, +	0x00038042, 0x00000002, +	0x040025e0, 0x00000002, +	0x000075e1, 0000000000, +	0x00000001, 0000000000, +	0x000380d9, 0x00000002, +	0x04007394, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +	0000000000, 0000000000, +}; + +const uint32_t r300_cp_microcode[] = { +	 0x4200e000, 0000000000, +	 0x4000e000, 0000000000, +	 0x000000af, 0x00000008, +	 0x000000b3, 0x00000008, +	 0x6c5a504f, 0000000000, +	 0x4f4f497a, 0000000000, +	 0x5a578288, 0000000000, +	 0x4f91906a, 0000000000, +	 0x4f4f4f4f, 0000000000, +	 0x4fe24f44, 0000000000, +	 0x4f9c9c9c, 0000000000, +	 0xdc4f4fde, 0000000000, +	 0xa1cd4f4f, 0000000000, +	 0xd29d9d9d, 0000000000, +	 0x4f0f9fd7, 0000000000, +	 0x000ca000, 0x00000004, +	 0x000d0012, 0x00000038, +	 0x0000e8b4, 0x00000004, +	 0x000d0014, 0x00000038, +	 0x0000e8b6, 0x00000004, +	 0x000d0016, 0x00000038, +	 0x0000e854, 0x00000004, +	 0x000d0018, 0x00000038, +	 0x0000e855, 0x00000004, +	 0x000d001a, 0x00000038, +	 0x0000e856, 0x00000004, +	 0x000d001c, 0x00000038, +	 0x0000e857, 0x00000004, +	 0x000d001e, 0x00000038, +	 0x0000e824, 0x00000004, +	 0x000d0020, 0x00000038, +	 0x0000e825, 0x00000004, +	 0x000d0022, 0x00000038, +	 0x0000e830, 0x00000004, +	 0x000d0024, 0x00000038, +	 0x0000f0c0, 0x00000004, +	 0x000d0026, 0x00000038, +	 0x0000f0c1, 0x00000004, +	 0x000d0028, 0x00000038, +	 0x0000f041, 0x00000004, +	 0x000d002a, 0x00000038, +	 0x0000f184, 0x00000004, +	 0x000d002c, 0x00000038, +	 0x0000f185, 0x00000004, +	 0x000d002e, 0x00000038, +	 0x0000f186, 0x00000004, +	 0x000d0030, 0x00000038, +	 0x0000f187, 0x00000004, +	 0x000d0032, 0x00000038, +	 0x0000f180, 0x00000004, +	 0x000d0034, 0x00000038, +	 0x0000f393, 0x00000004, +	 0x000d0036, 0x00000038, +	 0x0000f38a, 0x00000004, +	 0x000d0038, 0x00000038, +	 0x0000f38e, 0x00000004, +	 0x0000e821, 0x00000004, +	 0x0140a000, 0x00000004, +	 0x00000043, 0x00000018, +	 0x00cce800, 0x00000004, +	 0x001b0001, 0x00000004, +	 0x08004800, 0x00000004, +	 0x001b0001, 0x00000004, +	 0x08004800, 0x00000004, +	 0x001b0001, 0x00000004, +	 0x08004800, 0x00000004, +	 0x0000003a, 0x00000008, +	 0x0000a000, 0000000000, +	 0x02c0a000, 0x00000004, +	 0x000ca000, 0x00000004, +	 0x00130000, 0x00000004, +	 0x000c2000, 0x00000004, +	 0xc980c045, 0x00000008, +	 0x2000451d, 0x00000004, +	 0x0000e580, 0x00000004, +	 0x000ce581, 0x00000004, +	 0x08004580, 0x00000004, +	 0x000ce581, 0x00000004, +	 0x0000004c, 0x00000008, +	 0x0000a000, 0000000000, +	 0x000c2000, 0x00000004, +	 0x0000e50e, 0x00000004, +	 0x00032000, 0x00000004, +	 0x00022056, 0x00000028, +	 0x00000056, 0x00000024, +	 0x0800450f, 0x00000004, +	 0x0000a050, 0x00000008, +	 0x0000e565, 0x00000004, +	 0x0000e566, 0x00000004, +	 0x00000057, 0x00000008, +	 0x03cca5b4, 0x00000004, +	 0x05432000, 0x00000004, +	 0x00022000, 0x00000004, +	 0x4ccce063, 0x00000030, +	 0x08274565, 0x00000004, +	 0x00000063, 0x00000030, +	 0x08004564, 0x00000004, +	 0x0000e566, 0x00000004, +	 0x0000005a, 0x00000008, +	 0x00802066, 0x00000010, +	 0x00202000, 0x00000004, +	 0x001b00ff, 0x00000004, +	 0x01000069, 0x00000010, +	 0x001f2000, 0x00000004, +	 0x001c00ff, 0x00000004, +	 0000000000, 0x0000000c, +	 0x00000085, 0x00000030, +	 0x0000005a, 0x00000008, +	 0x0000e576, 0x00000004, +	 0x000ca000, 0x00000004, +	 0x00012000, 0x00000004, +	 0x00082000, 0x00000004, +	 0x1800650e, 0x00000004, +	 0x00092000, 0x00000004, +	 0x000a2000, 0x00000004, +	 0x000f0000, 0x00000004, +	 0x00400000, 0x00000004, +	 0x00000079, 0x00000018, +	 0x0000e563, 0x00000004, +	 0x00c0e5f9, 0x000000c2, +	 0x0000006e, 0x00000008, +	 0x0000a06e, 0x00000008, +	 0x0000e576, 0x00000004, +	 0x0000e577, 0x00000004, +	 0x0000e50e, 0x00000004, +	 0x0000e50f, 0x00000004, +	 0x0140a000, 0x00000004, +	 0x0000007c, 0x00000018, +	 0x00c0e5f9, 0x000000c2, +	 0x0000007c, 0x00000008, +	 0x0014e50e, 0x00000004, +	 0x0040e50f, 0x00000004, +	 0x00c0007f, 0x00000008, +	 0x0000e570, 0x00000004, +	 0x0000e571, 0x00000004, +	 0x0000e572, 0x0000000c, +	 0x0000a000, 0x00000004, +	 0x0140a000, 0x00000004, +	 0x0000e568, 0x00000004, +	 0x000c2000, 0x00000004, +	 0x00000089, 0x00000018, +	 0x000b0000, 0x00000004, +	 0x18c0e562, 0x00000004, +	 0x0000008b, 0x00000008, +	 0x00c0008a, 0x00000008, +	 0x000700e4, 0x00000004, +	 0x00000097, 0x00000038, +	 0x000ca099, 0x00000030, +	 0x080045bb, 0x00000004, +	 0x000c209a, 0x00000030, +	 0x0800e5bc, 0000000000, +	 0x0000e5bb, 0x00000004, +	 0x0000e5bc, 0000000000, +	 0x00120000, 0x0000000c, +	 0x00120000, 0x00000004, +	 0x001b0002, 0x0000000c, +	 0x0000a000, 0x00000004, +	 0x0000e821, 0x00000004, +	 0x0000e800, 0000000000, +	 0x0000e821, 0x00000004, +	 0x0000e82e, 0000000000, +	 0x02cca000, 0x00000004, +	 0x00140000, 0x00000004, +	 0x000ce1cc, 0x00000004, +	 0x050de1cd, 0x00000004, +	 0x000000a7, 0x00000020, +	 0x4200e000, 0000000000, +	 0x000000ae, 0x00000038, +	 0x000ca000, 0x00000004, +	 0x00140000, 0x00000004, +	 0x000c2000, 0x00000004, +	 0x00160000, 0x00000004, +	 0x700ce000, 0x00000004, +	 0x001400aa, 0x00000008, +	 0x4000e000, 0000000000, +	 0x02400000, 0x00000004, +	 0x400ee000, 0x00000004, +	 0x02400000, 0x00000004, +	 0x4000e000, 0000000000, +	 0x000c2000, 0x00000004, +	 0x0240e51b, 0x00000004, +	 0x0080e50a, 0x00000005, +	 0x0080e50b, 0x00000005, +	 0x00220000, 0x00000004, +	 0x000700e4, 0x00000004, +	 0x000000c1, 0x00000038, +	 0x000c209a, 0x00000030, +	 0x0880e5bd, 0x00000005, +	 0x000c2099, 0x00000030, +	 0x0800e5bb, 0x00000005, +	 0x000c209a, 0x00000030, +	 0x0880e5bc, 0x00000005, +	 0x000000c4, 0x00000008, +	 0x0080e5bd, 0x00000005, +	 0x0000e5bb, 0x00000005, +	 0x0080e5bc, 0x00000005, +	 0x00210000, 0x00000004, +	 0x02800000, 0x00000004, +	 0x00c000c8, 0x00000018, +	 0x4180e000, 0x00000040, +	 0x000000ca, 0x00000024, +	 0x01000000, 0x0000000c, +	 0x0100e51d, 0x0000000c, +	 0x000045bb, 0x00000004, +	 0x000080c4, 0x00000008, +	 0x0000f3ce, 0x00000004, +	 0x0140a000, 0x00000004, +	 0x00cc2000, 0x00000004, +	 0x08c053cf, 0x00000040, +	 0x00008000, 0000000000, +	 0x0000f3d2, 0x00000004, +	 0x0140a000, 0x00000004, +	 0x00cc2000, 0x00000004, +	 0x08c053d3, 0x00000040, +	 0x00008000, 0000000000, +	 0x0000f39d, 0x00000004, +	 0x0140a000, 0x00000004, +	 0x00cc2000, 0x00000004, +	 0x08c0539e, 0x00000040, +	 0x00008000, 0000000000, +	 0x03c00830, 0x00000004, +	 0x4200e000, 0000000000, +	 0x0000a000, 0x00000004, +	 0x200045e0, 0x00000004, +	 0x0000e5e1, 0000000000, +	 0x00000001, 0000000000, +	 0x000700e1, 0x00000004, +	 0x0800e394, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +	 0000000000, 0000000000, +}; diff --git a/shared-core/radeon_ms_crtc.c b/shared-core/radeon_ms_crtc.c new file mode 100644 index 00000000..0da5a5a4 --- /dev/null +++ b/shared-core/radeon_ms_crtc.c @@ -0,0 +1,803 @@ +/* + * Copyright © 2007 Alex Deucher + * Copyright © 2007 Dave Airlie + * Copyright © 2007 Michel Dänzer + * Copyright © 2007 Jerome Glisse + * + * All Rights Reserved. + * + * 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 on 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 + * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS 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. + */ +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "radeon_ms.h" + +static void radeon_pll1_init(struct drm_radeon_private *dev_priv, +			     struct radeon_state *state); +static void radeon_pll1_restore(struct drm_radeon_private *dev_priv, +				struct radeon_state *state); +static void radeon_pll1_save(struct drm_radeon_private *dev_priv, +			     struct radeon_state *state); +static void radeon_ms_crtc_load_lut(struct drm_crtc *crtc); + +/** + * radeon_ms_crtc1_init - initialize CRTC state + * @dev_priv: radeon private structure + * @state: state structure to initialize to default value + * + * Initialize CRTC state to default values + */ +static void radeon_ms_crtc1_init(struct drm_radeon_private *dev_priv, +				 struct radeon_state *state) +{ +	state->surface_cntl = SURFACE_CNTL__SURF_TRANSLATION_DIS; +	state->surface0_info = 0; +	state->surface0_lower_bound = 0; +	state->surface0_upper_bound = 0; +	state->surface1_info = 0; +	state->surface1_lower_bound = 0; +	state->surface1_upper_bound = 0; +	state->surface2_info = 0; +	state->surface2_lower_bound = 0; +	state->surface2_upper_bound = 0; +	state->surface3_info = 0; +	state->surface3_lower_bound = 0; +	state->surface3_upper_bound = 0; +	state->surface4_info = 0; +	state->surface4_lower_bound = 0; +	state->surface4_upper_bound = 0; +	state->surface5_info = 0; +	state->surface5_lower_bound = 0; +	state->surface5_upper_bound = 0; +	state->surface6_info = 0; +	state->surface6_lower_bound = 0; +	state->surface6_upper_bound = 0; +	state->surface7_info = 0; +	state->surface7_lower_bound = 0; +	state->surface7_upper_bound = 0; +	state->crtc_gen_cntl = CRTC_GEN_CNTL__CRTC_EXT_DISP_EN | +			       CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B; +	state->crtc_ext_cntl = CRTC_EXT_CNTL__VGA_ATI_LINEAR | +			       CRTC_EXT_CNTL__VGA_XCRT_CNT_EN | +			       CRTC_EXT_CNTL__CRT_ON; +	state->crtc_h_total_disp = 0; +	state->crtc_h_sync_strt_wid = 0; +	state->crtc_v_total_disp = 0; +	state->crtc_v_sync_strt_wid = 0; +	state->crtc_offset = 0; +	state->crtc_pitch = 0; +	state->crtc_more_cntl = 0; +	state->crtc_tile_x0_y0 = 0; +	state->crtc_offset_cntl = 0; +	switch (dev_priv->family) { +	case CHIP_R100: +	case CHIP_R200: +	case CHIP_RV200: +	case CHIP_RV250: +	case CHIP_RV280: +	case CHIP_RS300: +		break; +	case CHIP_R300: +	case CHIP_R350: +	case CHIP_R360: +	case CHIP_RV350: +	case CHIP_RV370: +	case CHIP_RV380: +	case CHIP_RS400: +	case CHIP_RV410: +	case CHIP_R420: +	case CHIP_R430: +	case CHIP_R480: +		state->crtc_offset_cntl |= REG_S(CRTC_OFFSET_CNTL, +				CRTC_MICRO_TILE_BUFFER_MODE, +				CRTC_MICRO_TILE_BUFFER_MODE__DIS); +		break; +	default: +		DRM_ERROR("Unknown radeon family, aborting\n"); +		return; +	} +	radeon_pll1_init(dev_priv, state); +} + +/** + * radeon_pll1_init - initialize PLL1 state + * @dev_priv: radeon private structure + * @state: state structure to initialize to default value + * + * Initialize PLL1 state to default values + */ +static void radeon_pll1_init(struct drm_radeon_private *dev_priv, +			     struct radeon_state *state) +{ +	state->clock_cntl_index = 0; +	state->ppll_cntl = PPLL_R(PPLL_CNTL); +	state->ppll_cntl |= PPLL_CNTL__PPLL_ATOMIC_UPDATE_EN | +		PPLL_CNTL__PPLL_ATOMIC_UPDATE_SYNC | +		PPLL_CNTL__PPLL_VGA_ATOMIC_UPDATE_EN; +	state->ppll_cntl &= ~PPLL_CNTL__PPLL_TST_EN; +	state->ppll_cntl &= ~PPLL_CNTL__PPLL_TCPOFF; +	state->ppll_cntl &= ~PPLL_CNTL__PPLL_TVCOMAX; +	state->ppll_cntl &= ~PPLL_CNTL__PPLL_DISABLE_AUTO_RESET; +	state->ppll_ref_div = 0; +	state->ppll_ref_div = REG_S(PPLL_REF_DIV, PPLL_REF_DIV, 12) | +		REG_S(PPLL_REF_DIV, PPLL_REF_DIV_SRC, PPLL_REF_DIV_SRC__XTALIN); +	state->ppll_div_0 = 0; +	state->ppll_div_1 = 0; +	state->ppll_div_2 = 0; +	state->ppll_div_3 = 0; +	state->vclk_ecp_cntl = 0; +	state->htotal_cntl = 0; +} + +/** + * radeon_ms_crtc1_restore - restore CRTC state + * @dev_priv: radeon private structure + * @state: CRTC state to restore + */ +void radeon_ms_crtc1_restore(struct drm_device *dev, struct radeon_state *state) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	/* We prevent the CRTC from hitting the memory controller until +	 * fully programmed +	 */ +	MMIO_W(CRTC_GEN_CNTL, ~CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B & +			state->crtc_gen_cntl); +	MMIO_W(CRTC_EXT_CNTL, CRTC_EXT_CNTL__CRTC_VSYNC_DIS | +			CRTC_EXT_CNTL__CRTC_HSYNC_DIS | +			CRTC_EXT_CNTL__CRTC_DISPLAY_DIS | +			state->crtc_ext_cntl); +	MMIO_W(SURFACE_CNTL, state->surface_cntl); +	MMIO_W(SURFACE0_INFO, state->surface0_info); +	MMIO_W(SURFACE0_LOWER_BOUND, state->surface0_lower_bound); +	MMIO_W(SURFACE0_UPPER_BOUND, state->surface0_upper_bound); +	MMIO_W(SURFACE1_INFO, state->surface1_info); +	MMIO_W(SURFACE1_LOWER_BOUND, state->surface1_lower_bound); +	MMIO_W(SURFACE1_UPPER_BOUND, state->surface1_upper_bound); +	MMIO_W(SURFACE2_INFO, state->surface2_info); +	MMIO_W(SURFACE2_LOWER_BOUND, state->surface2_lower_bound); +	MMIO_W(SURFACE2_UPPER_BOUND, state->surface2_upper_bound); +	MMIO_W(SURFACE3_INFO, state->surface3_info); +	MMIO_W(SURFACE3_LOWER_BOUND, state->surface3_lower_bound); +	MMIO_W(SURFACE3_UPPER_BOUND, state->surface3_upper_bound); +	MMIO_W(SURFACE4_INFO, state->surface4_info); +	MMIO_W(SURFACE4_LOWER_BOUND, state->surface4_lower_bound); +	MMIO_W(SURFACE4_UPPER_BOUND, state->surface4_upper_bound); +	MMIO_W(SURFACE5_INFO, state->surface5_info); +	MMIO_W(SURFACE5_LOWER_BOUND, state->surface5_lower_bound); +	MMIO_W(SURFACE5_UPPER_BOUND, state->surface5_upper_bound); +	MMIO_W(SURFACE6_INFO, state->surface6_info); +	MMIO_W(SURFACE6_LOWER_BOUND, state->surface6_lower_bound); +	MMIO_W(SURFACE6_UPPER_BOUND, state->surface6_upper_bound); +	MMIO_W(SURFACE7_INFO, state->surface7_info); +	MMIO_W(SURFACE7_LOWER_BOUND, state->surface7_lower_bound); +	MMIO_W(SURFACE7_UPPER_BOUND, state->surface7_upper_bound); +	MMIO_W(CRTC_H_TOTAL_DISP, state->crtc_h_total_disp); +	MMIO_W(CRTC_H_SYNC_STRT_WID, state->crtc_h_sync_strt_wid); +	MMIO_W(CRTC_V_TOTAL_DISP, state->crtc_v_total_disp); +	MMIO_W(CRTC_V_SYNC_STRT_WID, state->crtc_v_sync_strt_wid); +	MMIO_W(FP_H_SYNC_STRT_WID, state->fp_h_sync_strt_wid); +	MMIO_W(FP_V_SYNC_STRT_WID, state->fp_v_sync_strt_wid); +	MMIO_W(FP_CRTC_H_TOTAL_DISP, state->fp_crtc_h_total_disp); +	MMIO_W(FP_CRTC_V_TOTAL_DISP, state->fp_crtc_v_total_disp); +	MMIO_W(CRTC_TILE_X0_Y0, state->crtc_tile_x0_y0); +	MMIO_W(CRTC_OFFSET_CNTL, state->crtc_offset_cntl); +	MMIO_W(CRTC_OFFSET, state->crtc_offset); +	MMIO_W(CRTC_PITCH, state->crtc_pitch); +	radeon_pll1_restore(dev_priv, state); +	MMIO_W(CRTC_MORE_CNTL, state->crtc_more_cntl); +	MMIO_W(CRTC_GEN_CNTL, state->crtc_gen_cntl); +	MMIO_W(CRTC_EXT_CNTL, state->crtc_ext_cntl); +} + +/** + * radeon_pll1_restore - restore PLL1 state + * @dev_priv: radeon private structure + * @state: PLL1 state to restore + */ +static void radeon_pll1_restore(struct drm_radeon_private *dev_priv, +				struct radeon_state *state) +{ +	uint32_t tmp; + +	/* switch to gpu clock while programing new clock */ +	MMIO_W(CLOCK_CNTL_INDEX, state->clock_cntl_index); +	tmp = state->vclk_ecp_cntl; +	tmp = REG_S(VCLK_ECP_CNTL, VCLK_SRC_SEL, VCLK_SRC_SEL__CPUCLK); +	PPLL_W(VCLK_ECP_CNTL, tmp); +	/* reset PLL and update atomicly */ +	state->ppll_cntl |= PPLL_CNTL__PPLL_ATOMIC_UPDATE_EN | +		PPLL_CNTL__PPLL_ATOMIC_UPDATE_SYNC;  + +	PPLL_W(PPLL_CNTL, state->ppll_cntl | PPLL_CNTL__PPLL_RESET); +	PPLL_W(PPLL_REF_DIV, state->ppll_ref_div); +	PPLL_W(PPLL_DIV_0, state->ppll_div_0); +	PPLL_W(PPLL_DIV_1, state->ppll_div_1); +	PPLL_W(PPLL_DIV_2, state->ppll_div_2); +	PPLL_W(PPLL_DIV_3, state->ppll_div_3); +	PPLL_W(HTOTAL_CNTL, state->htotal_cntl); + +	/* update */ +	PPLL_W(PPLL_REF_DIV, state->ppll_ref_div | +			PPLL_REF_DIV__PPLL_ATOMIC_UPDATE_W); +	for (tmp = 0; tmp < 100; tmp++) { +		if (!(PPLL_REF_DIV__PPLL_ATOMIC_UPDATE_R & +					PPLL_R(PPLL_REF_DIV))) { +		      break; +		} +		DRM_UDELAY(10); +	} +	state->ppll_cntl &= ~PPLL_CNTL__PPLL_RESET; +	PPLL_W(PPLL_CNTL, state->ppll_cntl); +	PPLL_W(VCLK_ECP_CNTL, state->vclk_ecp_cntl); +} + +/** + * radeon_ms_crtc1_save - save CRTC state + * @dev_priv: radeon private structure + * @state: state where saving current CRTC state + */ +void radeon_ms_crtc1_save(struct drm_device *dev, struct radeon_state *state) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	state->surface_cntl = MMIO_R(SURFACE_CNTL); +	state->surface0_info = MMIO_R(SURFACE0_INFO); +	state->surface0_lower_bound = MMIO_R(SURFACE0_LOWER_BOUND); +	state->surface0_upper_bound = MMIO_R(SURFACE0_UPPER_BOUND); +	state->surface1_info = MMIO_R(SURFACE1_INFO); +	state->surface1_lower_bound = MMIO_R(SURFACE1_LOWER_BOUND); +	state->surface1_upper_bound = MMIO_R(SURFACE1_UPPER_BOUND); +	state->surface2_info = MMIO_R(SURFACE2_INFO); +	state->surface2_lower_bound = MMIO_R(SURFACE2_LOWER_BOUND); +	state->surface2_upper_bound = MMIO_R(SURFACE2_UPPER_BOUND); +	state->surface3_info = MMIO_R(SURFACE3_INFO); +	state->surface3_lower_bound = MMIO_R(SURFACE3_LOWER_BOUND); +	state->surface3_upper_bound = MMIO_R(SURFACE3_UPPER_BOUND); +	state->surface4_info = MMIO_R(SURFACE4_INFO); +	state->surface4_lower_bound = MMIO_R(SURFACE4_LOWER_BOUND); +	state->surface4_upper_bound = MMIO_R(SURFACE4_UPPER_BOUND); +	state->surface5_info = MMIO_R(SURFACE5_INFO); +	state->surface5_lower_bound = MMIO_R(SURFACE5_LOWER_BOUND); +	state->surface5_upper_bound = MMIO_R(SURFACE5_UPPER_BOUND); +	state->surface6_info = MMIO_R(SURFACE6_INFO); +	state->surface6_lower_bound = MMIO_R(SURFACE6_LOWER_BOUND); +	state->surface6_upper_bound = MMIO_R(SURFACE6_UPPER_BOUND); +	state->surface7_info = MMIO_R(SURFACE7_INFO); +	state->surface7_lower_bound = MMIO_R(SURFACE7_LOWER_BOUND); +	state->surface7_upper_bound = MMIO_R(SURFACE7_UPPER_BOUND); +	state->crtc_gen_cntl = MMIO_R(CRTC_GEN_CNTL); +	state->crtc_ext_cntl = MMIO_R(CRTC_EXT_CNTL); +	state->crtc_h_total_disp = MMIO_R(CRTC_H_TOTAL_DISP); +	state->crtc_h_sync_strt_wid = MMIO_R(CRTC_H_SYNC_STRT_WID); +	state->crtc_v_total_disp = MMIO_R(CRTC_V_TOTAL_DISP); +	state->crtc_v_sync_strt_wid = MMIO_R(CRTC_V_SYNC_STRT_WID); +	state->fp_h_sync_strt_wid = MMIO_R(FP_H_SYNC_STRT_WID); +	state->fp_v_sync_strt_wid = MMIO_R(FP_V_SYNC_STRT_WID); +	state->fp_crtc_h_total_disp = MMIO_R(FP_CRTC_H_TOTAL_DISP); +	state->fp_crtc_v_total_disp = MMIO_R(FP_CRTC_V_TOTAL_DISP); +	state->crtc_offset = MMIO_R(CRTC_OFFSET); +	state->crtc_offset_cntl = MMIO_R(CRTC_OFFSET_CNTL); +	state->crtc_pitch = MMIO_R(CRTC_PITCH); +	state->crtc_more_cntl = MMIO_R(CRTC_MORE_CNTL); +	state->crtc_tile_x0_y0 =  MMIO_R(CRTC_TILE_X0_Y0); +	radeon_pll1_save(dev_priv,state); +} + +/** + * radeon_pll1_save - save PLL1 state + * @dev_priv: radeon private structure + * @state: state where saving current PLL1 state + */ +static void radeon_pll1_save(struct drm_radeon_private *dev_priv, +			     struct radeon_state *state) +{ +	state->clock_cntl_index = MMIO_R(CLOCK_CNTL_INDEX); +	state->ppll_cntl = PPLL_R(PPLL_CNTL); +	state->ppll_ref_div = PPLL_R(PPLL_REF_DIV); +	state->ppll_div_0 = PPLL_R(PPLL_DIV_0); +	state->ppll_div_1 = PPLL_R(PPLL_DIV_1); +	state->ppll_div_2 = PPLL_R(PPLL_DIV_2); +	state->ppll_div_3 = PPLL_R(PPLL_DIV_3); +	state->vclk_ecp_cntl = PPLL_R(VCLK_ECP_CNTL); +	state->htotal_cntl = PPLL_R(HTOTAL_CNTL); +} + +static void radeon_ms_crtc1_dpms(struct drm_crtc *crtc, int mode) +{ +	struct drm_radeon_private *dev_priv = crtc->dev->dev_private; +	struct radeon_state *state = &dev_priv->driver_state; + +	state->crtc_gen_cntl &= ~CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B; +	state->crtc_ext_cntl &= ~CRTC_EXT_CNTL__CRTC_DISPLAY_DIS; +	state->crtc_ext_cntl &= ~CRTC_EXT_CNTL__CRTC_HSYNC_DIS; +	state->crtc_ext_cntl &= ~CRTC_EXT_CNTL__CRTC_VSYNC_DIS; +	switch(mode) { +	case DPMSModeOn: +		break; +	case DPMSModeStandby: +		state->crtc_ext_cntl |= +			CRTC_EXT_CNTL__CRTC_DISPLAY_DIS | +			CRTC_EXT_CNTL__CRTC_HSYNC_DIS; +		break; +	case DPMSModeSuspend: +		state->crtc_ext_cntl |= +			CRTC_EXT_CNTL__CRTC_DISPLAY_DIS | +			CRTC_EXT_CNTL__CRTC_VSYNC_DIS; +		break; +	case DPMSModeOff: +		state->crtc_ext_cntl |= +			CRTC_EXT_CNTL__CRTC_DISPLAY_DIS | +			CRTC_EXT_CNTL__CRTC_HSYNC_DIS | +			CRTC_EXT_CNTL__CRTC_VSYNC_DIS; +		state->crtc_gen_cntl |= +			CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B; +		break; +	} +	MMIO_W(CRTC_GEN_CNTL, state->crtc_gen_cntl); +	MMIO_W(CRTC_EXT_CNTL, state->crtc_ext_cntl); + +	dev_priv->crtc1_dpms = mode; +	/* FIXME: once adding crtc2 remove this */ +	dev_priv->crtc2_dpms = mode; +	radeon_ms_gpu_dpms(crtc->dev); + +	if (mode != DPMSModeOff) { +		radeon_ms_crtc_load_lut(crtc); +	} +} + +static bool radeon_ms_crtc_mode_fixup(struct drm_crtc *crtc, +				      struct drm_display_mode *mode, +				      struct drm_display_mode *adjusted_mode) +{ +	return true; +} + +static void radeon_ms_crtc_mode_prepare(struct drm_crtc *crtc) +{ +	crtc->funcs->dpms(crtc, DPMSModeOff); +} + +/* compute PLL registers values for requested video mode */ +static int radeon_pll1_constraint(struct drm_device *dev, +				  int clock, int rdiv, +                                  int fdiv, int pdiv, +                                  int rfrq, int pfrq) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	int dfrq; + +	if (rdiv < 2 || fdiv < 4) { +		return 0; +	} +	dfrq = rfrq / rdiv; +	if (dfrq < 2000 || dfrq > 3300) { +		return 0; +	} +	if (pfrq < dev_priv->properties.pll_min_pll_freq || +	    pfrq > dev_priv->properties.pll_max_pll_freq) { +		return 0; +	} +	return 1; +} + +static void radeon_pll1_compute(struct drm_crtc *crtc, +				struct drm_display_mode *mode) +{ +	struct { +		int divider; +		int divider_id; +	} *post_div, post_divs[] = { +		/* From RAGE 128 VR/RAGE 128 GL Register +		 * Reference Manual (Technical Reference +		 * Manual P/N RRG-G04100-C Rev. 0.04), page +		 * 3-17 (PLL_DIV_[3:0]). +		 */ +		{  1, 0 },              /* VCLK_SRC                 */ +		{  2, 1 },              /* VCLK_SRC/2               */ +		{  4, 2 },              /* VCLK_SRC/4               */ +		{  8, 3 },              /* VCLK_SRC/8               */ +		{  3, 4 },              /* VCLK_SRC/3               */ +		{ 16, 5 },              /* VCLK_SRC/16              */ +		{  6, 6 },              /* VCLK_SRC/6               */ +		{ 12, 7 },              /* VCLK_SRC/12              */ +		{  0, 0 } +	}; +	struct drm_radeon_private *dev_priv = crtc->dev->dev_private; +	struct radeon_state *state = &dev_priv->driver_state; +	int clock = mode->clock; +	int rfrq = dev_priv->properties.pll_reference_freq; +	int pdiv = 1; +	int pdiv_id = 0; +	int rdiv_best = 2; +	int fdiv_best = 4; +	int tfrq_best = 0; +	int pfrq_best = 0; +	int diff_cpfrq_best = 350000; +	int vco_freq; +	int vco_gain; +	int rdiv = 0; +	int fdiv = 0; +	int tfrq = 35000; +	int pfrq = 35000; +	int diff_cpfrq = 350000; + +	/* clamp frequency into pll [min; max] frequency range */ +	if (clock > dev_priv->properties.pll_max_pll_freq) { +		clock = dev_priv->properties.pll_max_pll_freq; +	} +	if ((clock * 12) < dev_priv->properties.pll_min_pll_freq) { +		clock = dev_priv->properties.pll_min_pll_freq / 12; +	} + +	/* maximize pll_ref_div while staying in boundary and minimizing +	 * the difference btw target frequency and programmed frequency */ +	for (post_div = &post_divs[0]; post_div->divider; ++post_div) { +		if (post_div->divider == 0) { +			break; +		} +		tfrq = clock * post_div->divider; +		for (fdiv = 1023; fdiv >= 4; fdiv--) { +			rdiv = (fdiv * rfrq) / tfrq; +			if (radeon_pll1_constraint(crtc->dev, clock, rdiv, +						   fdiv, pdiv, rfrq, tfrq)) { +				pfrq = (fdiv * rfrq) / rdiv; +				diff_cpfrq = pfrq - tfrq; +				if ((diff_cpfrq >= 0 && +				     diff_cpfrq < diff_cpfrq_best) || +				    (diff_cpfrq == diff_cpfrq_best && +				     rdiv > rdiv_best)) { +					rdiv_best = rdiv; +					fdiv_best = fdiv; +					tfrq_best = tfrq; +					pfrq_best = pfrq; +					pdiv = post_div->divider; +					pdiv_id = post_div->divider_id; +					diff_cpfrq_best = diff_cpfrq; +				} +			} +		} +	} +	state->ppll_ref_div = +		REG_S(PPLL_REF_DIV, PPLL_REF_DIV, rdiv_best) | +		REG_S(PPLL_REF_DIV, PPLL_REF_DIV_ACC, rdiv_best); +	state->ppll_div_0 = REG_S(PPLL_DIV_0, PPLL_FB0_DIV, fdiv_best) | +		REG_S(PPLL_DIV_0, PPLL_POST0_DIV, pdiv_id); + +	vco_freq = (fdiv_best * rfrq) / rdiv_best; +	/* This is horribly crude: the VCO frequency range is divided into +	 * 3 parts, each part having a fixed PLL gain value. +	 */ +        if (vco_freq >= 300000) { +		/* [300..max] MHz : 7 */ +		vco_gain = 7; +	} else if (vco_freq >= 180000) { +		/* [180..300) MHz : 4 */ +		vco_gain = 4; +	} else { +		/* [0..180) MHz : 1 */ +		vco_gain = 1; +	} +	state->ppll_cntl |= REG_S(PPLL_CNTL, PPLL_PVG, vco_gain); +	state->vclk_ecp_cntl |= REG_S(VCLK_ECP_CNTL, VCLK_SRC_SEL, +			VCLK_SRC_SEL__PPLLCLK); +	state->htotal_cntl = 0; +	DRM_INFO("rdiv: %d\n", rdiv_best); +	DRM_INFO("fdiv: %d\n", fdiv_best); +	DRM_INFO("pdiv: %d\n", pdiv); +	DRM_INFO("pdiv: %d\n", pdiv_id); +	DRM_INFO("tfrq: %d\n", tfrq_best); +	DRM_INFO("pfrq: %d\n", pfrq_best); +	DRM_INFO("PPLL_REF_DIV:  0x%08X\n", state->ppll_ref_div); +	DRM_INFO("PPLL_DIV_0:    0x%08X\n", state->ppll_div_0); +	DRM_INFO("PPLL_CNTL:     0x%08X\n", state->ppll_cntl); +	DRM_INFO("VCLK_ECP_CNTL: 0x%08X\n", state->vclk_ecp_cntl); +} + +static void radeon_ms_crtc1_mode_set(struct drm_crtc *crtc, +				     struct drm_display_mode *mode, +				     struct drm_display_mode *adjusted_mode, +				     int x, int y) +{ +	struct drm_device *dev = crtc->dev; +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_state *state = &dev_priv->driver_state; +	int format, hsync_wid, vsync_wid, pitch; + +	DRM_INFO("[radeon_ms] set modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x\n", +		  mode->mode_id, mode->name, mode->vrefresh, mode->clock, +		  mode->hdisplay, mode->hsync_start, +		  mode->hsync_end, mode->htotal, +		  mode->vdisplay, mode->vsync_start, +		  mode->vsync_end, mode->vtotal, mode->type); +	DRM_INFO("[radeon_ms] set modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x (adjusted)\n", +		  adjusted_mode->mode_id, adjusted_mode->name, adjusted_mode->vrefresh, adjusted_mode->clock, +		  adjusted_mode->hdisplay, adjusted_mode->hsync_start, +		  adjusted_mode->hsync_end, adjusted_mode->htotal, +		  adjusted_mode->vdisplay, adjusted_mode->vsync_start, +		  adjusted_mode->vsync_end, adjusted_mode->vtotal, adjusted_mode->type); + +	/* only support RGB555,RGB565,ARGB8888 should satisfy all users */ +	switch (crtc->fb->bits_per_pixel) { +	case 16: +		if (crtc->fb->depth == 15) { +			format = 3; +		} else { +			format = 4; +		} +		break; +	case 32: +		format = 6; +		break; +	default: +		DRM_ERROR("Unknown color depth\n"); +		return; +	} +	radeon_pll1_compute(crtc, adjusted_mode); + +	state->crtc_offset = REG_S(CRTC_OFFSET, CRTC_OFFSET, crtc->fb->offset); +	state->crtc_gen_cntl = CRTC_GEN_CNTL__CRTC_EXT_DISP_EN | +		CRTC_GEN_CNTL__CRTC_EN | +		REG_S(CRTC_GEN_CNTL, CRTC_PIX_WIDTH, format); +	if (adjusted_mode->flags & V_DBLSCAN) { +		state->crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_DBL_SCAN_EN; +	} +	if (adjusted_mode->flags & V_CSYNC) { +		state->crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_C_SYNC_EN; +	} +	if (adjusted_mode->flags & V_INTERLACE) { +		state->crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_INTERLACE_EN; +	} +	state->crtc_more_cntl = 0; +	state->crtc_h_total_disp = +		REG_S(CRTC_H_TOTAL_DISP, +				CRTC_H_TOTAL, +				(adjusted_mode->crtc_htotal/8) - 1) | +		REG_S(CRTC_H_TOTAL_DISP, +				CRTC_H_DISP, +				(adjusted_mode->crtc_hdisplay/8) - 1); +	hsync_wid = (adjusted_mode->crtc_hsync_end - +		     adjusted_mode->crtc_hsync_start) / 8; +	if (!hsync_wid) { +		hsync_wid = 1; +	} +	if (hsync_wid > 0x3f) { +		hsync_wid = 0x3f; +	} +	state->crtc_h_sync_strt_wid = +		REG_S(CRTC_H_SYNC_STRT_WID, +				CRTC_H_SYNC_WID, hsync_wid) | +		REG_S(CRTC_H_SYNC_STRT_WID, +				CRTC_H_SYNC_STRT_PIX, +				adjusted_mode->crtc_hsync_start) | +		REG_S(CRTC_H_SYNC_STRT_WID, +				CRTC_H_SYNC_STRT_CHAR, +				adjusted_mode->crtc_hsync_start/8); +	if (adjusted_mode->flags & V_NHSYNC) { +		state->crtc_h_sync_strt_wid |= +			CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_POL; +	} + +	state->crtc_v_total_disp = +		REG_S(CRTC_V_TOTAL_DISP, CRTC_V_TOTAL, +				adjusted_mode->crtc_vtotal - 1) | +		REG_S(CRTC_V_TOTAL_DISP, CRTC_V_DISP, +				adjusted_mode->crtc_vdisplay - 1); +	vsync_wid = adjusted_mode->crtc_vsync_end - +		    adjusted_mode->crtc_vsync_start; +	if (!vsync_wid) { +		vsync_wid = 1; +	} +	if (vsync_wid > 0x1f) { +		vsync_wid = 0x1f; +	} +	state->crtc_v_sync_strt_wid = +		REG_S(CRTC_V_SYNC_STRT_WID, +				CRTC_V_SYNC_WID, +				vsync_wid) | +		REG_S(CRTC_V_SYNC_STRT_WID, +				CRTC_V_SYNC_STRT, +				adjusted_mode->crtc_vsync_start); +	if (adjusted_mode->flags & V_NVSYNC) { +		state->crtc_v_sync_strt_wid |= +			CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_POL; +	} + +	pitch = (crtc->fb->width * crtc->fb->bits_per_pixel + +		 ((crtc->fb->bits_per_pixel * 8)- 1)) / +		(crtc->fb->bits_per_pixel * 8); +	state->crtc_pitch = REG_S(CRTC_PITCH, CRTC_PITCH, pitch) | +		REG_S(CRTC_PITCH, CRTC_PITCH_RIGHT, pitch); + +	state->fp_h_sync_strt_wid = state->crtc_h_sync_strt_wid; +	state->fp_v_sync_strt_wid = state->crtc_v_sync_strt_wid; +	state->fp_crtc_h_total_disp = state->crtc_h_total_disp; +	state->fp_crtc_v_total_disp = state->crtc_v_total_disp; + +	radeon_ms_crtc1_restore(dev, state); +} + +static void radeon_ms_crtc_mode_commit(struct drm_crtc *crtc) +{ +	crtc->funcs->dpms(crtc, DPMSModeOn); +} + +static void radeon_ms_crtc_gamma_set(struct drm_crtc *crtc, u16 r, +				     u16 g, u16 b, int regno) +{ +	struct drm_radeon_private *dev_priv = crtc->dev->dev_private; +	struct radeon_ms_crtc *radeon_ms_crtc = crtc->driver_private; +	struct radeon_state *state = &dev_priv->driver_state; +	uint32_t color; + +	switch(radeon_ms_crtc->crtc) { +	case 1: +		state->dac_cntl2 &= ~DAC_CNTL2__PALETTE_ACCESS_CNTL; +		break; +	case 2: +		state->dac_cntl2 |= DAC_CNTL2__PALETTE_ACCESS_CNTL; +		break; +	} +	MMIO_W(DAC_CNTL2, state->dac_cntl2); +	if (crtc->fb->bits_per_pixel == 16 && crtc->fb->depth == 16) { +		if (regno >= 64) { +			return; +		} +		MMIO_W(PALETTE_INDEX, +				REG_S(PALETTE_INDEX, PALETTE_W_INDEX, +					regno * 4)); +		color = 0; +		color = REG_S(PALETTE_DATA, PALETTE_DATA_R, r >> 8) | +			REG_S(PALETTE_DATA, PALETTE_DATA_G, g >> 8) | +			REG_S(PALETTE_DATA, PALETTE_DATA_B, b >> 8); +		MMIO_W(PALETTE_DATA, color); +		MMIO_W(PALETTE_INDEX, +		       REG_S(PALETTE_INDEX, PALETTE_W_INDEX, regno * 4)); +		color = 0; +		color = REG_S(PALETTE_30_DATA, PALETTE_DATA_R, r >> 6) | +			REG_S(PALETTE_30_DATA, PALETTE_DATA_G, g >> 6) | +			REG_S(PALETTE_30_DATA, PALETTE_DATA_B, b >> 6); +		MMIO_W(PALETTE_30_DATA, color); +		radeon_ms_crtc->lut_r[regno * 4] = r; +		radeon_ms_crtc->lut_g[regno * 4] = g; +		radeon_ms_crtc->lut_b[regno * 4] = b; +		if (regno < 32) { +			MMIO_W(PALETTE_INDEX, +			       REG_S(PALETTE_INDEX, PALETTE_W_INDEX, +				       regno * 8)); +			color = 0; +			color = REG_S(PALETTE_DATA, PALETTE_DATA_R, r >> 8) | +				REG_S(PALETTE_DATA, PALETTE_DATA_G, g >> 8) | +				REG_S(PALETTE_DATA, PALETTE_DATA_B, b >> 8); +			MMIO_W(PALETTE_DATA, color); +			MMIO_W(PALETTE_INDEX, +			       REG_S(PALETTE_INDEX, PALETTE_W_INDEX, +				      regno * 8)); +			color = 0; +			color = REG_S(PALETTE_30_DATA, PALETTE_DATA_R,r >> 6) | +				REG_S(PALETTE_30_DATA, PALETTE_DATA_G,g >> 6) | +				REG_S(PALETTE_30_DATA, PALETTE_DATA_B,b >> 6); +			MMIO_W(PALETTE_30_DATA, color); +			radeon_ms_crtc->lut_r[regno * 8] = r; +			radeon_ms_crtc->lut_g[regno * 8] = g; +			radeon_ms_crtc->lut_b[regno * 8] = b; +		} +	} else { +		if (regno >= 256) { +			return; +		} +		radeon_ms_crtc->lut_r[regno] = r; +		radeon_ms_crtc->lut_g[regno] = g; +		radeon_ms_crtc->lut_b[regno] = b; +		MMIO_W(PALETTE_INDEX, +		       REG_S(PALETTE_INDEX, PALETTE_W_INDEX, regno)); +		color = 0; +		color = REG_S(PALETTE_DATA, PALETTE_DATA_R, r >> 8) | +			REG_S(PALETTE_DATA, PALETTE_DATA_G, g >> 8) | +			REG_S(PALETTE_DATA, PALETTE_DATA_B, b >> 8); +		MMIO_W(PALETTE_DATA, color); +		MMIO_W(PALETTE_INDEX, +				REG_S(PALETTE_INDEX, PALETTE_W_INDEX, regno)); +		color = 0; +		color = REG_S(PALETTE_30_DATA, PALETTE_DATA_R, r >> 6) | +			REG_S(PALETTE_30_DATA, PALETTE_DATA_G, g >> 6) | +			REG_S(PALETTE_30_DATA, PALETTE_DATA_B, b >> 6); +	} +} + +static void radeon_ms_crtc_load_lut(struct drm_crtc *crtc) +{ +	struct radeon_ms_crtc *radeon_ms_crtc = crtc->driver_private; +	int i; + +	if (!crtc->enabled) +		return; + +	for (i = 0; i < 256; i++) { +		radeon_ms_crtc_gamma_set(crtc, +				radeon_ms_crtc->lut_r[i], +				radeon_ms_crtc->lut_g[i], +				radeon_ms_crtc->lut_b[i], +				i); +	} +} + +static bool radeon_ms_crtc_lock(struct drm_crtc *crtc) +{ +    return true; +} + +static void radeon_ms_crtc_unlock(struct drm_crtc *crtc) +{ +} + +static const struct drm_crtc_funcs radeon_ms_crtc1_funcs= { +	.dpms = radeon_ms_crtc1_dpms, +	.save = NULL, /* XXX */ +	.restore = NULL, /* XXX */ +	.lock = radeon_ms_crtc_lock, +	.unlock = radeon_ms_crtc_unlock, +	.prepare = radeon_ms_crtc_mode_prepare, +	.commit = radeon_ms_crtc_mode_commit, +	.mode_fixup = radeon_ms_crtc_mode_fixup, +	.mode_set = radeon_ms_crtc1_mode_set, +	.gamma_set = radeon_ms_crtc_gamma_set, +	.cleanup = NULL, /* XXX */ +}; + +int radeon_ms_crtc_create(struct drm_device *dev, int crtc) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct drm_crtc *drm_crtc; +	struct radeon_ms_crtc *radeon_ms_crtc; +	int i; + +	switch (crtc) { +	case 1: +		radeon_ms_crtc1_init(dev_priv, &dev_priv->driver_state); +		drm_crtc = drm_crtc_create(dev, &radeon_ms_crtc1_funcs); +		break; +	case 2: +	default: +		return -EINVAL; +	} +	if (drm_crtc == NULL) { +		return -ENOMEM; +	} + +	radeon_ms_crtc = drm_alloc(sizeof(struct radeon_ms_crtc), DRM_MEM_DRIVER); +	if (radeon_ms_crtc == NULL) { +		kfree(drm_crtc); +		return -ENOMEM; +	} + +	radeon_ms_crtc->crtc = crtc; +	for (i = 0; i < 256; i++) { +		radeon_ms_crtc->lut_r[i] = i << 8; +		radeon_ms_crtc->lut_g[i] = i << 8; +		radeon_ms_crtc->lut_b[i] = i << 8; +	} +	drm_crtc->driver_private = radeon_ms_crtc; +	return 0; +} diff --git a/shared-core/radeon_ms_dac.c b/shared-core/radeon_ms_dac.c new file mode 100644 index 00000000..e6312942 --- /dev/null +++ b/shared-core/radeon_ms_dac.c @@ -0,0 +1,400 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * All Rights Reserved. + * + * 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 on 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 + * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS 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. + */ +#include "radeon_ms.h" + +int radeon_ms_dac1_initialize(struct radeon_ms_output *output) +{ +	struct drm_radeon_private *dev_priv = output->dev->dev_private; +	struct radeon_state *state = &dev_priv->driver_state; + +	state->dac_cntl = +		REG_S(DAC_CNTL, DAC_RANGE_CNTL, DAC_RANGE_CNTL__PS2) | +		DAC_CNTL__DAC_8BIT_EN | +		DAC_CNTL__DAC_VGA_ADR_EN | +		DAC_CNTL__DAC_PDWN | +		REG_S(DAC_CNTL, DAC, 0xff); +	state->dac_ext_cntl = 0; +	state->dac_macro_cntl = +		DAC_MACRO_CNTL__DAC_PDWN_R | +		DAC_MACRO_CNTL__DAC_PDWN_G | +		DAC_MACRO_CNTL__DAC_PDWN_B | +		REG_S(DAC_MACRO_CNTL, DAC_WHITE_CNTL, 7) | +		REG_S(DAC_MACRO_CNTL, DAC_BG_ADJ, 7); +	state->dac_embedded_sync_cntl = +		DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_VSYNC_EN_Y_G; +	state->dac_broad_pulse = 0; +	state->dac_skew_clks = 0; +	state->dac_incr = 0; +	state->dac_neg_sync_level = 0; +	state->dac_pos_sync_level = 0; +	state->dac_blank_level = 0; +	state->dac_sync_equalization = 0; +	state->disp_output_cntl = 0; +	radeon_ms_dac1_restore(output, state); +	return 0; +} + +enum drm_output_status radeon_ms_dac1_detect(struct radeon_ms_output *output) +{ +	return output_status_unknown; +} + +void radeon_ms_dac1_dpms(struct radeon_ms_output *output, int mode) +{ +	struct drm_radeon_private *dev_priv = output->dev->dev_private; +	struct radeon_state *state = &dev_priv->driver_state; +	uint32_t dac_cntl; +	uint32_t dac_macro_cntl; + +	dac_cntl = DAC_CNTL__DAC_PDWN; +	dac_macro_cntl = DAC_MACRO_CNTL__DAC_PDWN_R | +		DAC_MACRO_CNTL__DAC_PDWN_G | +		DAC_MACRO_CNTL__DAC_PDWN_B; +	switch(mode) { +	case DPMSModeOn: +		state->dac_cntl &= ~dac_cntl; +		state->dac_macro_cntl &= ~dac_macro_cntl; +		break; +	case DPMSModeStandby: +	case DPMSModeSuspend: +	case DPMSModeOff: +		state->dac_cntl |= dac_cntl; +		state->dac_macro_cntl |= dac_macro_cntl; +		break; +	default: +		/* error */ +		break; +	} +	MMIO_W(DAC_CNTL, state->dac_cntl); +	MMIO_W(DAC_MACRO_CNTL, state->dac_macro_cntl); +} + +int radeon_ms_dac1_get_modes(struct radeon_ms_output *output) +{ +	return 0; +} + +bool radeon_ms_dac1_mode_fixup(struct radeon_ms_output *output, +		struct drm_display_mode *mode, +		struct drm_display_mode *adjusted_mode) +{ +	return true; +} + +int radeon_ms_dac1_mode_set(struct radeon_ms_output *output, +		struct drm_display_mode *mode, +		struct drm_display_mode *adjusted_mode) +{ +	struct drm_radeon_private *dev_priv = output->dev->dev_private; +	struct radeon_ms_connector *connector = output->connector; +	struct radeon_state *state = &dev_priv->driver_state; +	uint32_t v = 0; + +	if (connector == NULL) { +		/* output not associated with a connector */ +		return -EINVAL; +	} +	state->disp_output_cntl &= ~DISP_OUTPUT_CNTL__DISP_DAC_SOURCE__MASK; +	state->dac_cntl2 &= ~DAC_CNTL2__DAC_CLK_SEL; +	switch (connector->crtc) { +	case 1: +		v =  DISP_DAC_SOURCE__PRIMARYCRTC; +		break; +	case 2: +		v =  DISP_DAC_SOURCE__SECONDARYCRTC; +		state->dac_cntl2 |= DAC_CNTL2__DAC_CLK_SEL; +		break; +	} +	state->disp_output_cntl |= REG_S(DISP_OUTPUT_CNTL, DISP_DAC_SOURCE, v); +	MMIO_W(DISP_OUTPUT_CNTL, state->disp_output_cntl); +	MMIO_W(DAC_CNTL2, state->dac_cntl2); +	return 0; +} + +void radeon_ms_dac1_restore(struct radeon_ms_output *output, +		struct radeon_state *state) +{ +	struct drm_radeon_private *dev_priv = output->dev->dev_private; + +	MMIO_W(DAC_CNTL, state->dac_cntl); +	MMIO_W(DAC_EXT_CNTL, state->dac_ext_cntl); +	MMIO_W(DAC_MACRO_CNTL, state->dac_macro_cntl); +	MMIO_W(DAC_EMBEDDED_SYNC_CNTL, state->dac_embedded_sync_cntl); +	MMIO_W(DAC_BROAD_PULSE, state->dac_broad_pulse); +	MMIO_W(DAC_SKEW_CLKS, state->dac_skew_clks); +	MMIO_W(DAC_INCR, state->dac_incr); +	MMIO_W(DAC_NEG_SYNC_LEVEL, state->dac_neg_sync_level); +	MMIO_W(DAC_POS_SYNC_LEVEL, state->dac_pos_sync_level); +	MMIO_W(DAC_BLANK_LEVEL, state->dac_blank_level); +	MMIO_W(DAC_SYNC_EQUALIZATION, state->dac_sync_equalization); +} + +void radeon_ms_dac1_save(struct radeon_ms_output *output, +		struct radeon_state *state) +{ +	struct drm_radeon_private *dev_priv = output->dev->dev_private; + +	state->dac_cntl = MMIO_R(DAC_CNTL); +	state->dac_ext_cntl = MMIO_R(DAC_EXT_CNTL); +	state->dac_macro_cntl = MMIO_R(DAC_MACRO_CNTL); +	state->dac_embedded_sync_cntl = MMIO_R(DAC_EMBEDDED_SYNC_CNTL); +	state->dac_broad_pulse = MMIO_R(DAC_BROAD_PULSE); +	state->dac_skew_clks = MMIO_R(DAC_SKEW_CLKS); +	state->dac_incr = MMIO_R(DAC_INCR); +	state->dac_neg_sync_level = MMIO_R(DAC_NEG_SYNC_LEVEL); +	state->dac_pos_sync_level = MMIO_R(DAC_POS_SYNC_LEVEL); +	state->dac_blank_level = MMIO_R(DAC_BLANK_LEVEL); +	state->dac_sync_equalization = MMIO_R(DAC_SYNC_EQUALIZATION); +} + +int radeon_ms_dac2_initialize(struct radeon_ms_output *output) +{ +	struct drm_radeon_private *dev_priv = output->dev->dev_private; +	struct radeon_state *state = &dev_priv->driver_state; + +	state->tv_dac_cntl = TV_DAC_CNTL__BGSLEEP | +		REG_S(TV_DAC_CNTL, STD, STD__PS2) | +		REG_S(TV_DAC_CNTL, BGADJ, 0); +	switch (dev_priv->family) { +	case CHIP_R100: +	case CHIP_R200: +	case CHIP_RV200: +	case CHIP_RV250: +	case CHIP_RV280: +	case CHIP_RS300: +	case CHIP_R300: +	case CHIP_R350: +	case CHIP_R360: +	case CHIP_RV350: +	case CHIP_RV370: +	case CHIP_RV380: +	case CHIP_RS400: +		state->tv_dac_cntl |= TV_DAC_CNTL__RDACPD | +			TV_DAC_CNTL__GDACPD | +			TV_DAC_CNTL__BDACPD | +			REG_S(TV_DAC_CNTL, DACADJ, 0); +		break; +	case CHIP_RV410: +	case CHIP_R420: +	case CHIP_R430: +	case CHIP_R480: +		state->tv_dac_cntl |= TV_DAC_CNTL__RDACPD_R4 | +			TV_DAC_CNTL__GDACPD_R4 | +			TV_DAC_CNTL__BDACPD_R4 | +			REG_S(TV_DAC_CNTL, DACADJ_R4, 0); +		break; +	} +	state->tv_master_cntl = TV_MASTER_CNTL__TV_ASYNC_RST | +		TV_MASTER_CNTL__CRT_ASYNC_RST | +		TV_MASTER_CNTL__RESTART_PHASE_FIX | +		TV_MASTER_CNTL__CRT_FIFO_CE_EN | +		TV_MASTER_CNTL__TV_FIFO_CE_EN; +	state->dac_cntl2 = 0; +	state->disp_output_cntl = 0; +	radeon_ms_dac2_restore(output, state); +	return 0; +} + +enum drm_output_status radeon_ms_dac2_detect(struct radeon_ms_output *output) +{ +	return output_status_unknown; +} + +void radeon_ms_dac2_dpms(struct radeon_ms_output *output, int mode) +{ +	struct drm_radeon_private *dev_priv = output->dev->dev_private; +	struct radeon_state *state = &dev_priv->driver_state; +	uint32_t tv_dac_cntl_on, tv_dac_cntl_off; + +	tv_dac_cntl_off = TV_DAC_CNTL__BGSLEEP; +	tv_dac_cntl_on = TV_DAC_CNTL__NBLANK | +			 TV_DAC_CNTL__NHOLD; +	switch (dev_priv->family) { +	case CHIP_R100: +	case CHIP_R200: +	case CHIP_RV200: +	case CHIP_RV250: +	case CHIP_RV280: +	case CHIP_RS300: +	case CHIP_R300: +	case CHIP_R350: +	case CHIP_R360: +	case CHIP_RV350: +	case CHIP_RV370: +	case CHIP_RV380: +	case CHIP_RS400: +		tv_dac_cntl_off |= TV_DAC_CNTL__RDACPD | +			TV_DAC_CNTL__GDACPD | +			TV_DAC_CNTL__BDACPD; +		break; +	case CHIP_RV410: +	case CHIP_R420: +	case CHIP_R430: +	case CHIP_R480: +		tv_dac_cntl_off |= TV_DAC_CNTL__RDACPD_R4 | +			TV_DAC_CNTL__GDACPD_R4 | +			TV_DAC_CNTL__BDACPD_R4; +		break; +	} +	switch(mode) { +	case DPMSModeOn: +		state->tv_dac_cntl &= ~tv_dac_cntl_off; +		state->tv_dac_cntl |= tv_dac_cntl_on; +		break; +	case DPMSModeStandby: +	case DPMSModeSuspend: +	case DPMSModeOff: +		state->tv_dac_cntl &= ~tv_dac_cntl_on; +		state->tv_dac_cntl |= tv_dac_cntl_off; +		break; +	default: +		/* error */ +		break; +	} +	MMIO_W(TV_DAC_CNTL, state->tv_dac_cntl); +} + +int radeon_ms_dac2_get_modes(struct radeon_ms_output *output) +{ +	return 0; +} + +bool radeon_ms_dac2_mode_fixup(struct radeon_ms_output *output, +		struct drm_display_mode *mode, +		struct drm_display_mode *adjusted_mode) +{ +	return true; +} + +int radeon_ms_dac2_mode_set(struct radeon_ms_output *output, +		struct drm_display_mode *mode, +		struct drm_display_mode *adjusted_mode) +{ +	struct drm_radeon_private *dev_priv = output->dev->dev_private; +	struct radeon_ms_connector *connector = output->connector; +	struct radeon_state *state = &dev_priv->driver_state; + +	if (connector == NULL) { +		/* output not associated with a connector */ +		return -EINVAL; +	} +	switch (dev_priv->family) { +	case CHIP_R100: +	case CHIP_R200: +		state->disp_output_cntl &= ~DISP_OUTPUT_CNTL__DISP_TV_SOURCE; +		switch (connector->crtc) { +		case 1: +			break; +		case 2: +			state->disp_output_cntl |= +				DISP_OUTPUT_CNTL__DISP_TV_SOURCE; +			break; +		} +		break; +	case CHIP_RV200: +	case CHIP_RV250: +	case CHIP_RV280: +	case CHIP_RS300: +		break; +	case CHIP_R300: +	case CHIP_R350: +	case CHIP_R360: +	case CHIP_RV350: +	case CHIP_RV370: +	case CHIP_RV380: +	case CHIP_RS400: +	case CHIP_RV410: +	case CHIP_R420: +	case CHIP_R430: +	case CHIP_R480: +		state->disp_output_cntl &= +			~DISP_OUTPUT_CNTL__DISP_TVDAC_SOURCE__MASK; +		switch (connector->crtc) { +		case 1: +			state->disp_output_cntl |= +				REG_S(DISP_OUTPUT_CNTL, +						DISP_TVDAC_SOURCE, +						DISP_TVDAC_SOURCE__PRIMARYCRTC); +				break; +		case 2: +				state->disp_output_cntl |= +					REG_S(DISP_OUTPUT_CNTL, +							DISP_TVDAC_SOURCE, +							DISP_TVDAC_SOURCE__SECONDARYCRTC); +				break; +		} +		break; +	} +	switch (dev_priv->family) { +	case CHIP_R200: +		break; +	case CHIP_R100: +	case CHIP_RV200: +	case CHIP_RV250: +	case CHIP_RV280: +	case CHIP_RS300: +	case CHIP_R300: +	case CHIP_R350: +	case CHIP_R360: +	case CHIP_RV350: +	case CHIP_RV370: +	case CHIP_RV380: +	case CHIP_RS400: +	case CHIP_RV410: +	case CHIP_R420: +	case CHIP_R430: +	case CHIP_R480: +		if (connector->type != CONNECTOR_CTV && +		    connector->type != CONNECTOR_STV) { +			state->dac_cntl2 |= DAC_CNTL2__DAC2_CLK_SEL; +		} +	} +	MMIO_W(DAC_CNTL2, state->dac_cntl2); +	MMIO_W(DISP_OUTPUT_CNTL, state->disp_output_cntl); +	return 0; +} + +void radeon_ms_dac2_restore(struct radeon_ms_output *output, +		struct radeon_state *state) +{ +	struct drm_radeon_private *dev_priv = output->dev->dev_private; + +	MMIO_W(DAC_CNTL2, state->dac_cntl2); +	MMIO_W(TV_DAC_CNTL, state->tv_dac_cntl); +	MMIO_W(TV_MASTER_CNTL, state->tv_master_cntl); +} + +void radeon_ms_dac2_save(struct radeon_ms_output *output, +		struct radeon_state *state) +{ +	struct drm_radeon_private *dev_priv = output->dev->dev_private; + +	state->dac_cntl2 = MMIO_R(DAC_CNTL2); +	state->tv_dac_cntl = MMIO_R(TV_DAC_CNTL); +	state->tv_master_cntl = MMIO_R(TV_MASTER_CNTL); +} diff --git a/shared-core/radeon_ms_drm.c b/shared-core/radeon_ms_drm.c new file mode 100644 index 00000000..bf76b45d --- /dev/null +++ b/shared-core/radeon_ms_drm.c @@ -0,0 +1,318 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * All Rights Reserved. + * + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: + *    Jerome Glisse <glisse@freedesktop.org> + */ +#include "drm_pciids.h" +#include "radeon_ms.h" + + +static uint32_t radeon_ms_mem_prios[] = { +	DRM_BO_MEM_VRAM, +	DRM_BO_MEM_TT, +	DRM_BO_MEM_LOCAL, +}; + +static uint32_t radeon_ms_busy_prios[] = { +	DRM_BO_MEM_TT, +	DRM_BO_MEM_VRAM, +	DRM_BO_MEM_LOCAL, +}; + +struct drm_fence_driver radeon_ms_fence_driver = { +	.num_classes = 1, +	.wrap_diff = (1 << 30), +	.flush_diff = (1 << 29), +	.sequence_mask = 0xffffffffU, +	.lazy_capable = 1, +	.emit = radeon_ms_fence_emit_sequence, +	.poke_flush = radeon_ms_poke_flush, +	.has_irq = radeon_ms_fence_has_irq, +}; + +struct drm_bo_driver radeon_ms_bo_driver = { +	.mem_type_prio = radeon_ms_mem_prios, +	.mem_busy_prio = radeon_ms_busy_prios, +	.num_mem_type_prio = sizeof(radeon_ms_mem_prios)/sizeof(uint32_t), +	.num_mem_busy_prio = sizeof(radeon_ms_busy_prios)/sizeof(uint32_t), +	.create_ttm_backend_entry = radeon_ms_create_ttm_backend, +	.fence_type = radeon_ms_fence_types, +	.invalidate_caches = radeon_ms_invalidate_caches, +	.init_mem_type = radeon_ms_init_mem_type, +	.evict_flags = radeon_ms_evict_flags, +	.move = radeon_ms_bo_move, +	.ttm_cache_flush = radeon_ms_ttm_flush, +}; + +struct drm_ioctl_desc radeon_ms_ioctls[] = { +	DRM_IOCTL_DEF(DRM_RADEON_EXECBUFFER, radeon_ms_execbuffer, DRM_AUTH), +}; +int radeon_ms_num_ioctls = DRM_ARRAY_SIZE(radeon_ms_ioctls); + +int radeon_ms_driver_dma_ioctl(struct drm_device *dev, void *data, +			       struct drm_file *file_priv) +{ +	struct drm_device_dma *dma = dev->dma; +	struct drm_dma *d = data; + +	LOCK_TEST_WITH_RETURN(dev, file_priv); + +	/* Please don't send us buffers. +	 */ +	if (d->send_count != 0) { +		DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n", +			  DRM_CURRENTPID, d->send_count); +		return -EINVAL; +	} + +	/* Don't ask us buffer neither :) +	 */ +	DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", +		  DRM_CURRENTPID, d->request_count, dma->buf_count); +	return -EINVAL; +} + +void radeon_ms_driver_lastclose(struct drm_device * dev) +{ +} + +int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags) +{ +	struct drm_radeon_private *dev_priv; +	int ret = 0; + +	DRM_INFO("[radeon_ms] loading\n"); +	/* allocate and clear device private structure */ +	dev_priv = drm_alloc(sizeof(struct drm_radeon_private), DRM_MEM_DRIVER); +	if (dev_priv == NULL) +		return -ENOMEM; +	memset(dev_priv, 0, sizeof(struct drm_radeon_private)); +	dev->dev_private = (void *)dev_priv; + +	/* initialize modesetting structure (must be done here) */ +	drm_mode_config_init(dev); + +	/* flags correspond to chipset family */ +	dev_priv->usec_timeout = 100; +	dev_priv->family = flags & 0xffffU; +	dev_priv->bus_type = flags & 0xff0000U; +	/* initialize family functions */ +	ret = radeon_ms_family_init(dev); +	if (ret != 0) { +		radeon_ms_driver_unload(dev); +		return ret; +	} + +	/* we don't want userspace to be able to map this so don't use +	 * drm_addmap */ +	dev_priv->mmio.offset = drm_get_resource_start(dev, 2); +	dev_priv->mmio.size = drm_get_resource_len(dev, 2); +	dev_priv->mmio.type = _DRM_REGISTERS; +	dev_priv->mmio.flags = _DRM_RESTRICTED; +	drm_core_ioremap(&dev_priv->mmio, dev);  +	/* map vram FIXME: IGP likely don't have any of this */ +	dev_priv->vram.offset = drm_get_resource_start(dev, 0); +	dev_priv->vram.size = drm_get_resource_len(dev, 0); +	dev_priv->vram.type = _DRM_FRAME_BUFFER; +	dev_priv->vram.flags = _DRM_RESTRICTED; +	drm_core_ioremap(&dev_priv->vram, dev); + +	/* save radeon initial state which will be restored upon module +	 * exit */ +	radeon_ms_state_save(dev, &dev_priv->load_state); +	dev_priv->restore_state = 1; +	memcpy(&dev_priv->driver_state, &dev_priv->load_state, +	       sizeof(struct radeon_state)); + +	/* initialize irq */ +	ret = radeon_ms_irq_init(dev); +	if (ret != 0) { +		radeon_ms_driver_unload(dev); +		return ret; +	} + +	/* init bo driver */ +	dev_priv->fence_id_last = 1; +	dev_priv->fence_reg = SCRATCH_REG2; +	drm_bo_driver_init(dev); +	/* initialize vram */ +	ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, dev_priv->vram.size); +	if (ret != 0) { +		radeon_ms_driver_unload(dev); +		return ret; +	} + +	/* initialize gpu address space (only after) VRAM initialization */ +	ret = radeon_ms_gpu_initialize(dev); +	if (ret != 0) { +		radeon_ms_driver_unload(dev); +		return ret; +	} +	radeon_ms_gpu_restore(dev, &dev_priv->driver_state); + +	/* initialize ttm */ +	ret = drm_bo_init_mm(dev, DRM_BO_MEM_TT, 0, +			     dev_priv->gpu_gart_size / RADEON_PAGE_SIZE); +	if (ret != 0) { +		radeon_ms_driver_unload(dev); +		return ret; +	} + +	/* initialize ring buffer */ +	/* set ring size to 4Mo FIXME: should make a parameter for this */ +	dev_priv->write_back_area_size = 4 * 1024; +	dev_priv->ring_buffer_size = 4 * 1024 * 1024; +	ret = radeon_ms_cp_init(dev); +	if (ret != 0) { +		radeon_ms_driver_unload(dev); +		return ret; +	} + +	/* initialize modesetting */ +	dev->mode_config.min_width = 0; +	dev->mode_config.min_height = 0; +	dev->mode_config.max_width = 4096; +	dev->mode_config.max_height = 4096; +	dev->mode_config.fb_base = dev_priv->vram.offset; +	ret = radeon_ms_crtc_create(dev, 1); +	if (ret != 0) { +		radeon_ms_driver_unload(dev); +		return ret; +	} +	ret = radeon_ms_outputs_from_rom(dev); +	if (ret < 0) { +		radeon_ms_driver_unload(dev); +		return ret; +	} else if (!ret) { +		ret = radeon_ms_outputs_from_properties(dev); +		if (ret < 0) { +			radeon_ms_driver_unload(dev); +			return ret; +		} else if (ret == 0) { +			DRM_INFO("[radeon_ms] no outputs !\n"); +		} +	} else { +		DRM_INFO("[radeon_ms] added %d outputs from rom.\n", ret); +	} +	ret = radeon_ms_connectors_from_rom(dev); +	if (ret < 0) { +		radeon_ms_driver_unload(dev); +		return ret; +	} else if (!ret) { +		ret = radeon_ms_connectors_from_properties(dev); +		if (ret < 0) { +			radeon_ms_driver_unload(dev); +			return ret; +		} else if (!ret) { +			DRM_INFO("[radeon_ms] no connectors !\n"); +		} +	} else { +		DRM_INFO("[radeon_ms] added %d connectors from rom.\n", ret); +	} +	radeon_ms_outputs_save(dev, &dev_priv->load_state); +	drm_initial_config(dev, false); + +	ret = drm_irq_install(dev); +	if (ret != 0) { +		radeon_ms_driver_unload(dev); +		return ret; +	} + +	DRM_INFO("[radeon_ms] successfull initialization\n"); +	return 0; +} + +int radeon_ms_driver_open(struct drm_device * dev, struct drm_file *file_priv) +{ +	return 0; +} + + +int radeon_ms_driver_unload(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	if (dev_priv == NULL) { +		return 0; +	} + +	/* cleanup modesetting */ +	drm_mode_config_cleanup(dev); +	DRM_INFO("[radeon_ms] modesetting clean\n"); +	radeon_ms_outputs_restore(dev, &dev_priv->load_state); +	radeon_ms_connectors_destroy(dev); +	radeon_ms_outputs_destroy(dev); +	 +	/* shutdown cp engine */ +	radeon_ms_cp_finish(dev); +	DRM_INFO("[radeon_ms] cp clean\n"); + +	drm_irq_uninstall(dev); +	DRM_INFO("[radeon_ms] irq uninstalled\n"); + +	DRM_INFO("[radeon_ms] unloading\n"); +	/* clean ttm memory manager */ +	mutex_lock(&dev->struct_mutex); +	if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT)) { +		DRM_ERROR("TT memory manager not clean. Delaying takedown\n"); +	} +	mutex_unlock(&dev->struct_mutex); +	DRM_INFO("[radeon_ms] TT memory clean\n"); +	/* finish */ +	if (dev_priv->bus_finish) { +		dev_priv->bus_finish(dev); +	} +	DRM_INFO("[radeon_ms] bus down\n"); +	/* clean vram memory manager */ +	mutex_lock(&dev->struct_mutex); +	if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM)) { +		DRM_ERROR("VRAM memory manager not clean. Delaying takedown\n"); +	} +	mutex_unlock(&dev->struct_mutex); +	DRM_INFO("[radeon_ms] VRAM memory clean\n"); +	/* clean memory manager */ +	drm_bo_driver_finish(dev); +	DRM_INFO("[radeon_ms] memory manager clean\n"); +	/* restore card state */ +	if (dev_priv->restore_state) { +		radeon_ms_state_restore(dev, &dev_priv->load_state); +	} +	DRM_INFO("[radeon_ms] state restored\n"); +	if (dev_priv->mmio.handle) { +		drm_core_ioremapfree(&dev_priv->mmio, dev); +	} +	if (dev_priv->vram.handle) { +		drm_core_ioremapfree(&dev_priv->vram, dev); +	} +	DRM_INFO("[radeon_ms] map released\n"); +	drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); +	dev->dev_private = NULL; + +	DRM_INFO("[radeon_ms] that's all the folks\n"); +	return 0; +} + diff --git a/shared-core/radeon_ms_drm.h b/shared-core/radeon_ms_drm.h new file mode 100644 index 00000000..842d5331 --- /dev/null +++ b/shared-core/radeon_ms_drm.h @@ -0,0 +1,60 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Dave Airlie + * Copyright 2007 Alex Deucher + * All Rights Reserved. + * + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: + *    Jérôme Glisse <glisse@freedesktop.org> + */ +#ifndef __RADEON_MS_DRM_H__ +#define __RADEON_MS_DRM_H__ + +/* fence definitions */ +/* The only fence class we support */ +#define DRM_RADEON_FENCE_CLASS_ACCEL 0 +/* Fence type that guarantees read-write flush */ +#define DRM_RADEON_FENCE_TYPE_RW 2 +/* cache flushes programmed just before the fence */ +#define DRM_RADEON_FENCE_FLAG_FLUSHED 0x01000000 + +/* radeon ms ioctl */ +#define DRM_RADEON_EXECBUFFER	0x00 + +struct drm_radeon_execbuffer_arg { +	uint64_t    next; +	uint32_t    reloc_offset; +	union { +		struct drm_bo_op_req    req; +		struct drm_bo_arg_rep   rep; +	} d; +}; + +struct drm_radeon_execbuffer { +	uint32_t args_count; +	uint64_t args; +	uint32_t cmd_size; +	struct drm_fence_arg fence_arg; +}; + +#endif diff --git a/shared-core/radeon_ms_exec.c b/shared-core/radeon_ms_exec.c new file mode 100644 index 00000000..b2ce3cbb --- /dev/null +++ b/shared-core/radeon_ms_exec.c @@ -0,0 +1,242 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: + *    Jerome Glisse <glisse@freedesktop.org> + */ +#include "radeon_ms.h" + +static void radeon_ms_execbuffer_args_clean(struct drm_device *dev, +					    struct drm_buffer_object **buffers, +					    uint32_t args_count) +{ +	mutex_lock(&dev->struct_mutex); +	while (args_count--) { +		drm_bo_usage_deref_locked(&buffers[args_count]); +	} +	mutex_unlock(&dev->struct_mutex); +} + +static int radeon_ms_execbuffer_args(struct drm_device *dev, +				     struct drm_file *file_priv, +				     struct drm_radeon_execbuffer *execbuffer, +				     struct drm_buffer_object **buffers, +				     uint32_t *relocs) +{ +	struct drm_radeon_execbuffer_arg arg; +	struct drm_bo_arg_rep rep; +	uint32_t args_count = 0; +	uint64_t next = 0; +	uint64_t data = execbuffer->args; +	int ret = 0; + +	do { +		if (args_count >= execbuffer->args_count) { +			DRM_ERROR("[radeon_ms] buffer count exceeded %d\n.", +				  execbuffer->args_count); +			ret = -EINVAL; +			goto out_err; +		} +		buffers[args_count] = NULL; +		if (copy_from_user(&arg, (void __user *)((unsigned)data), +		    sizeof(struct drm_radeon_execbuffer_arg))) { +			ret = -EFAULT; +			goto out_err; +		} +		mutex_lock(&dev->struct_mutex); +		buffers[args_count] = +			drm_lookup_buffer_object(file_priv, +						 arg.d.req.arg_handle, 1); +		relocs[args_count] = arg.reloc_offset; +		mutex_unlock(&dev->struct_mutex); +		if (arg.d.req.op != drm_bo_validate) { +			DRM_ERROR("[radeon_ms] buffer object operation wasn't " +				  "validate.\n"); +			ret = -EINVAL; +			goto out_err; +		} +		memset(&rep, 0, sizeof(struct drm_bo_arg_rep)); +		if (args_count >= 1) { +			ret = drm_bo_handle_validate(file_priv, +						     arg.d.req.bo_req.handle, +						     arg.d.req.bo_req.fence_class, +						     arg.d.req.bo_req.flags, +						     arg.d.req.bo_req.mask, +						     arg.d.req.bo_req.hint, +						     0, +						     &rep.bo_info, +						     &buffers[args_count]); +		} +		if (ret) { +			DRM_ERROR("[radeon_ms] error on handle validate %d\n", +				  ret); +			rep.ret = ret; +			goto out_err; +		} +		next = arg.next; +		arg.d.rep = rep; +		if (copy_to_user((void __user *)((unsigned)data), &arg, +		    sizeof(struct drm_radeon_execbuffer_arg))) { +			ret = -EFAULT; +			goto out_err; +		} +		data = next; +		args_count++; +	} while (next != 0); +	if (args_count != execbuffer->args_count) { +		DRM_ERROR("[radeon_ms] not enought buffer got %d waited %d\n.", +			  args_count, execbuffer->args_count); +		ret = -EINVAL; +		goto out_err; +	} +	return 0; +out_err: +	radeon_ms_execbuffer_args_clean(dev, buffers, args_count); +	return ret; +} + +static int radeon_ms_execbuffer_check(struct drm_device *dev, +				      struct drm_file *file_priv, +				      struct drm_radeon_execbuffer *execbuffer, +				      struct drm_buffer_object **buffers, +				      uint32_t *relocs, +				      uint32_t *cmd) +{ +	uint32_t i, gpu_addr; +	int ret; + +	for (i = 0; i < execbuffer->args_count; i++) { +		if (relocs[i]) { +			ret = radeon_ms_bo_get_gpu_addr(dev, &buffers[i]->mem, +							&gpu_addr); +			if (ret) { +				return ret; +			} +			cmd[relocs[i]] |= (gpu_addr) >> 10; +		} +	} +	for (i = 0; i < execbuffer->cmd_size; i++) { +#if 0 +		DRM_INFO("cmd[%d]=0x%08X\n", i, cmd[i]); +#endif +	} +	return 0; +} + +int radeon_ms_execbuffer(struct drm_device *dev, void *data, +			 struct drm_file *file_priv) +{ +	struct drm_radeon_execbuffer *execbuffer = data; +	struct drm_fence_arg *fence_arg = &execbuffer->fence_arg; +	struct drm_buffer_object **buffers; +	struct drm_bo_kmap_obj cmd_kmap; +	struct drm_fence_object *fence; +	uint32_t *relocs; +	uint32_t *cmd; +	int cmd_is_iomem; +	int ret = 0; + + +	ret = drm_bo_read_lock(&dev->bm.bm_lock); +	if (ret) { +		return ret; +	} + +	relocs = drm_calloc(execbuffer->args_count, sizeof(uint32_t), +			    DRM_MEM_DRIVER); +	if (relocs == NULL) { +	        drm_bo_read_unlock(&dev->bm.bm_lock); +		return -ENOMEM; +        } +	buffers = drm_calloc(execbuffer->args_count, +			     sizeof(struct drm_buffer_object *), +			     DRM_MEM_DRIVER); +	if (buffers == NULL) { +		drm_free(relocs, (execbuffer->args_count * sizeof(uint32_t)), +			 DRM_MEM_DRIVER); +	        drm_bo_read_unlock(&dev->bm.bm_lock); +		return -ENOMEM; +        } +	/* process arguments */ +	ret = radeon_ms_execbuffer_args(dev, file_priv, execbuffer, +					buffers, relocs); +	if (ret) { +		DRM_ERROR("[radeon_ms] execbuffer wrong arguments\n"); +		goto out_free; +	} +	/* map command buffer */ +	memset(&cmd_kmap, 0, sizeof(struct drm_bo_kmap_obj)); +	ret = drm_bo_kmap(buffers[0], +			  0, +		          buffers[0]->mem.num_pages, +			  &cmd_kmap); +	if (ret) { +		DRM_ERROR("[radeon_ms] error mapping ring buffer: %d\n", ret); +		goto out_free_release; +	} +	cmd = drm_bmo_virtual(&cmd_kmap, &cmd_is_iomem); +	/* do cmd checking & relocations */ +	ret = radeon_ms_execbuffer_check(dev, file_priv, execbuffer, +					 buffers, relocs, cmd); +	if (ret) { +		drm_putback_buffer_objects(dev); +		goto out_free_release; +	} + +	ret = radeon_ms_ring_emit(dev, cmd, execbuffer->cmd_size); +	if (ret) { +		drm_putback_buffer_objects(dev); +		goto out_free_release; +	} + +	/* fence */ +	ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence); +	if (ret) { +		drm_putback_buffer_objects(dev); +		DRM_ERROR("[radeon_ms] fence buffer objects failed\n"); +		goto out_free_release; +	} +	if (!(fence_arg->flags & DRM_FENCE_FLAG_NO_USER)) { +		ret = drm_fence_add_user_object(file_priv, fence, +						fence_arg->flags & DRM_FENCE_FLAG_SHAREABLE); +		if (!ret) { +			fence_arg->handle = fence->base.hash.key; +			fence_arg->fence_class = fence->fence_class; +			fence_arg->type = fence->type; +			fence_arg->signaled = fence->signaled; +			fence_arg->sequence = fence->sequence; +		} +	} +	drm_fence_usage_deref_unlocked(&fence); +out_free_release: +	drm_bo_kunmap(&cmd_kmap); +	radeon_ms_execbuffer_args_clean(dev, buffers, execbuffer->args_count); +out_free: +	drm_free(relocs, (execbuffer->args_count * sizeof(uint32_t)), +		 DRM_MEM_DRIVER); +	drm_free(buffers, +		 (execbuffer->args_count * sizeof(struct drm_buffer_object *)), +		 DRM_MEM_DRIVER); +	drm_bo_read_unlock(&dev->bm.bm_lock); +	return ret; +} diff --git a/shared-core/radeon_ms_family.c b/shared-core/radeon_ms_family.c new file mode 100644 index 00000000..b70dca20 --- /dev/null +++ b/shared-core/radeon_ms_family.c @@ -0,0 +1,141 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: + *    Jerome Glisse <glisse@freedesktop.org> + */ +#include "drmP.h" +#include "drm.h" +#include "radeon_ms.h" + +extern const uint32_t radeon_cp_microcode[]; +extern const uint32_t r200_cp_microcode[]; +extern const uint32_t r300_cp_microcode[]; + +static void radeon_flush_cache(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	uint32_t cmd[6]; +	int i, ret; + +	cmd[0] = CP_PACKET0(RB2D_DSTCACHE_CTLSTAT, 0); +	cmd[1] = REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FLUSH, 3); +	cmd[2] = CP_PACKET0(RB3D_DSTCACHE_CTLSTAT, 0); +	cmd[3] = REG_S(RB3D_DSTCACHE_CTLSTAT, DC_FLUSH, 3); +	cmd[4] = CP_PACKET0(RB3D_ZCACHE_CTLSTAT, 0); +	cmd[5] = RB3D_ZCACHE_CTLSTAT__ZC_FLUSH; +	/* try to wait but if we timeout we likely are in bad situation */ +	for (i = 0; i < dev_priv->usec_timeout; i++) { +		ret = radeon_ms_ring_emit(dev, cmd, 6); +		if (!ret) { +			break; +		} +	} +} + +static void r300_flush_cache(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	uint32_t cmd[6]; +	int i, ret; + +	cmd[0] = CP_PACKET0(RB2D_DSTCACHE_CTLSTAT, 0); +	cmd[1] = REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FLUSH, 3); +	cmd[2] = CP_PACKET0(RB3D_DSTCACHE_CTLSTAT_R3, 0); +	cmd[3] = REG_S(RB3D_DSTCACHE_CTLSTAT_R3, DC_FLUSH, 3); +	cmd[4] = CP_PACKET0(RB3D_ZCACHE_CTLSTAT_R3, 0); +	cmd[5] = RB3D_ZCACHE_CTLSTAT_R3__ZC_FLUSH; +	/* try to wait but if we timeout we likely are in bad situation */ +	for (i = 0; i < dev_priv->usec_timeout; i++) { +		ret = radeon_ms_ring_emit(dev, cmd, 6); +		if (!ret) { +			break; +		} +	} +} + +int radeon_ms_family_init(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	int ret; + +	dev_priv->microcode = radeon_cp_microcode; +	dev_priv->irq_emit = radeon_ms_irq_emit; + +	switch (dev_priv->family) { +	case CHIP_R100: +	case CHIP_R200: +		dev_priv->microcode = radeon_cp_microcode; +		dev_priv->flush_cache = radeon_flush_cache; +		break; +	case CHIP_RV200: +	case CHIP_RV250: +	case CHIP_RV280: +	case CHIP_RS300: +		dev_priv->microcode = r200_cp_microcode; +		dev_priv->flush_cache = radeon_flush_cache; +		break; +	case CHIP_R300: +	case CHIP_R350: +	case CHIP_R360: +	case CHIP_RV350: +	case CHIP_RV370: +	case CHIP_RV380: +	case CHIP_RS400: +	case CHIP_RV410: +	case CHIP_R420: +	case CHIP_R430: +	case CHIP_R480: +		dev_priv->microcode = r300_cp_microcode; +		dev_priv->flush_cache = r300_flush_cache; +		break; +	default: +		DRM_ERROR("Unknown radeon family, aborting\n"); +		return -EINVAL; +	} +	switch (dev_priv->bus_type) { +	case RADEON_AGP: +		dev_priv->create_ttm = drm_agp_init_ttm; +		dev_priv->bus_init = radeon_ms_agp_init; +		dev_priv->bus_restore = radeon_ms_agp_restore; +		dev_priv->bus_save = radeon_ms_agp_save; +		break; +	case RADEON_PCIE: +		dev_priv->create_ttm = radeon_ms_pcie_create_ttm; +		dev_priv->bus_finish = radeon_ms_pcie_finish; +		dev_priv->bus_init = radeon_ms_pcie_init; +		dev_priv->bus_restore = radeon_ms_pcie_restore; +		dev_priv->bus_save = radeon_ms_pcie_save; +		break; +	default: +		DRM_ERROR("Unknown radeon bus type, aborting\n"); +		return -EINVAL; +	} +	ret = radeon_ms_rom_init(dev); +	if (ret) { +		return ret; +	} +	ret = radeon_ms_properties_init(dev); +	return ret; +} diff --git a/shared-core/radeon_ms_fence.c b/shared-core/radeon_ms_fence.c new file mode 100644 index 00000000..6fcf5437 --- /dev/null +++ b/shared-core/radeon_ms_fence.c @@ -0,0 +1,129 @@ +/* + * Copyright 2007 Dave Airlie. + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: + *    Dave Airlie + *    Jerome Glisse <glisse@freedesktop.org> + */ +#include "radeon_ms.h" + +static void radeon_ms_fence_flush(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct drm_fence_class_manager *fc = &dev->fm.fence_class[0]; +	uint32_t pending_flush_types = 0; +	uint32_t sequence; + +	if (dev_priv == NULL) { +		return; +	} +	pending_flush_types = fc->pending_flush | +			      ((fc->pending_exe_flush) ? +				DRM_FENCE_TYPE_EXE : 0); +	if (pending_flush_types) { +		sequence = mmio_read(dev_priv, dev_priv->fence_reg); +		drm_fence_handler(dev, 0, sequence, pending_flush_types, 0); +	} +} + +int radeon_ms_fence_emit_sequence(struct drm_device *dev, uint32_t class, +			 	  uint32_t flags, uint32_t *sequence, +				  uint32_t *native_type) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	uint32_t fence_id, cmd[2], i, ret; + +	if (!dev_priv || dev_priv->cp_ready != 1) { +		return -EINVAL; +	} +	fence_id = (++dev_priv->fence_id_last); +	if (dev_priv->fence_id_last > 0x7FFFFFFF) { +		fence_id = dev_priv->fence_id_last = 1; +	} +	*sequence = fence_id; +	*native_type = DRM_FENCE_TYPE_EXE; +	if (flags & DRM_RADEON_FENCE_FLAG_FLUSHED) { +		*native_type |= DRM_RADEON_FENCE_TYPE_RW; +		dev_priv->flush_cache(dev); +	} +	cmd[0] = CP_PACKET0(dev_priv->fence_reg, 0); +	cmd[1] = fence_id; +	for (i = 0; i < dev_priv->usec_timeout; i++) { +		ret = radeon_ms_ring_emit(dev, cmd, 2); +		if (!ret) { +			dev_priv->irq_emit(dev); +			return 0; +		} +	} +	return -EBUSY; +} + +void radeon_ms_fence_handler(struct drm_device * dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct drm_fence_manager *fm = &dev->fm; + +	if (dev_priv == NULL) { +		return; +	} + +	write_lock(&fm->lock); +	radeon_ms_fence_flush(dev); +	write_unlock(&fm->lock); +} + +int radeon_ms_fence_has_irq(struct drm_device *dev, uint32_t class, +			    uint32_t flags) +{ +	/* +	 * We have an irq that tells us when we have a new breadcrumb. +	 */ +	if (class == 0 && flags == DRM_FENCE_TYPE_EXE) +		return 1; + +	return 0; +} + +int radeon_ms_fence_types(struct drm_buffer_object *bo, +			  uint32_t *class, uint32_t *type) +{ +	*class = 0; +	if (bo->mem.flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) +		*type = 3; +	else +		*type = 1; +	return 0; +} + +void radeon_ms_poke_flush(struct drm_device *dev, uint32_t class) +{ +	struct drm_fence_manager *fm = &dev->fm; +	unsigned long flags; + +	if (class != 0) +		return; +	write_lock_irqsave(&fm->lock, flags); +	radeon_ms_fence_flush(dev); +	write_unlock_irqrestore(&fm->lock, flags); +} diff --git a/shared-core/radeon_ms_gpu.c b/shared-core/radeon_ms_gpu.c new file mode 100644 index 00000000..28683781 --- /dev/null +++ b/shared-core/radeon_ms_gpu.c @@ -0,0 +1,589 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * All Rights Reserved. + * + * 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 on 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 + * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS 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. + */ +#include "radeon_ms.h" + +static int radeon_ms_gpu_address_space_init(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_state *state = &dev_priv->driver_state; + +	/* initialize gpu mapping */ +	dev_priv->gpu_vram_start = dev_priv->vram.offset; +	dev_priv->gpu_vram_end = dev_priv->gpu_vram_start + dev_priv->vram.size; +	/* align it on 16Mo boundary (clamp memory which is then +	 * unreachable but not manufacturer should use strange +	 * memory size */ +	dev_priv->gpu_vram_end = dev_priv->gpu_vram_end & (~0xFFFFFF); +	dev_priv->gpu_vram_end -= 1; +	dev_priv->gpu_vram_size = dev_priv->gpu_vram_end - +				  dev_priv->gpu_vram_start + 1; +	/* set gart size to 32Mo FIXME: should make a parameter for this */ +	dev_priv->gpu_gart_size = 1024 * 1024 * 32; +	if (dev_priv->gpu_gart_size > (0xffffffffU - dev_priv->gpu_vram_end)) { +		/* align gart start to next 4Ko in gpu address space */ +		dev_priv->gpu_gart_start = (dev_priv->gpu_vram_end + 1) + 0xfff; +		dev_priv->gpu_gart_start = dev_priv->gpu_gart_start & (~0xfff); +		dev_priv->gpu_gart_end = dev_priv->gpu_gart_start + +					 dev_priv->gpu_gart_size; +		dev_priv->gpu_gart_end = (dev_priv->gpu_gart_end & (~0xfff)) - +					 0x1000; +	} else { +		/* align gart start to next 4Ko in gpu address space */ +		dev_priv->gpu_gart_start = (dev_priv->gpu_vram_start & ~0xfff) - +					   dev_priv->gpu_gart_size; +		dev_priv->gpu_gart_start = dev_priv->gpu_gart_start & (~0xfff); +		dev_priv->gpu_gart_end = dev_priv->gpu_gart_start + +					 dev_priv->gpu_gart_size; +		dev_priv->gpu_gart_end = (dev_priv->gpu_gart_end & (~0xfff)) - +					 0x1000; +	} +	state->mc_fb_location = +		REG_S(MC_FB_LOCATION, MC_FB_START, +				dev_priv->gpu_vram_start >> 16) | +		REG_S(MC_FB_LOCATION, MC_FB_TOP, dev_priv->gpu_vram_end >> 16); +	state->display_base_addr = +		REG_S(DISPLAY_BASE_ADDR, DISPLAY_BASE_ADDR, +				dev_priv->gpu_vram_start); +	state->config_aper_0_base = dev_priv->gpu_vram_start; +	state->config_aper_1_base = dev_priv->gpu_vram_start; +	state->config_aper_size = dev_priv->gpu_vram_size; +	DRM_INFO("[radeon_ms] gpu vram start 0x%08X\n", +		 dev_priv->gpu_vram_start); +	DRM_INFO("[radeon_ms] gpu vram end   0x%08X\n", +		 dev_priv->gpu_vram_end); +	DRM_INFO("[radeon_ms] gpu gart start 0x%08X\n", +		 dev_priv->gpu_gart_start); +	DRM_INFO("[radeon_ms] gpu gart end   0x%08X\n", +		 dev_priv->gpu_gart_end); +	return 0; +} + +static void radeon_ms_gpu_reset(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	uint32_t clock_cntl_index, mclk_cntl, rbbm_soft_reset; +	uint32_t reset_mask, host_path_cntl, cache_mode; + +	radeon_ms_cp_stop(dev); +	radeon_ms_gpu_flush(dev); + +	/* reset clock */ +	clock_cntl_index = MMIO_R(CLOCK_CNTL_INDEX); +	pll_index_errata(dev_priv); +	mclk_cntl = PPLL_R(MCLK_CNTL); +	PPLL_W(MCLK_CNTL, +			mclk_cntl | +			MCLK_CNTL__FORCE_MCLKA | +			MCLK_CNTL__FORCE_MCLKB | +			MCLK_CNTL__FORCE_YCLKA | +			MCLK_CNTL__FORCE_YCLKB | +			MCLK_CNTL__FORCE_MC | +			MCLK_CNTL__FORCE_AIC); +	PPLL_W(SCLK_CNTL, +			PPLL_R(SCLK_CNTL) | +			SCLK_CNTL__FORCE_CP | +			SCLK_CNTL__FORCE_VIP); + +	/* Soft resetting HDP thru RBBM_SOFT_RESET register can cause some +	 * unexpected behaviour on some machines.  Here we use +	 * RADEON_HOST_PATH_CNTL to reset it. +	 */ +	host_path_cntl = MMIO_R(HOST_PATH_CNTL); +	rbbm_soft_reset = MMIO_R(RBBM_SOFT_RESET); +	reset_mask = RBBM_SOFT_RESET__SOFT_RESET_CP | +		RBBM_SOFT_RESET__SOFT_RESET_HI | +		RBBM_SOFT_RESET__SOFT_RESET_VAP | +		RBBM_SOFT_RESET__SOFT_RESET_SE | +		RBBM_SOFT_RESET__SOFT_RESET_RE | +		RBBM_SOFT_RESET__SOFT_RESET_PP | +		RBBM_SOFT_RESET__SOFT_RESET_E2 | +		RBBM_SOFT_RESET__SOFT_RESET_RB; +	MMIO_W(RBBM_SOFT_RESET, rbbm_soft_reset | reset_mask); +	MMIO_R(RBBM_SOFT_RESET); +	MMIO_W(RBBM_SOFT_RESET, 0); +	MMIO_R(RBBM_SOFT_RESET); + +	cache_mode = MMIO_R(RB2D_DSTCACHE_MODE); +	MMIO_W(RB2D_DSTCACHE_MODE, +			cache_mode | RB2D_DSTCACHE_MODE__DC_DISABLE_IGNORE_PE); + +	MMIO_W(HOST_PATH_CNTL, host_path_cntl | HOST_PATH_CNTL__HDP_SOFT_RESET); +	MMIO_R(HOST_PATH_CNTL); +	MMIO_W(HOST_PATH_CNTL, host_path_cntl); +	MMIO_R(HOST_PATH_CNTL); + +	MMIO_W(CLOCK_CNTL_INDEX, clock_cntl_index); +	pll_index_errata(dev_priv); +	PPLL_W(MCLK_CNTL, mclk_cntl); +} + +static void radeon_ms_gpu_resume(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	uint32_t a; +	uint32_t i; + +	/* make sure we have sane offset before restoring crtc */ +	a = (MMIO_R(MC_FB_LOCATION) & MC_FB_LOCATION__MC_FB_START__MASK) << 16; +	MMIO_W(DISPLAY_BASE_ADDR, a); +	MMIO_W(CRTC2_DISPLAY_BASE_ADDR, a); +	MMIO_W(CRTC_OFFSET, 0); +	MMIO_W(CUR_OFFSET, 0); +	MMIO_W(CRTC_OFFSET_CNTL, CRTC_OFFSET_CNTL__CRTC_OFFSET_FLIP_CNTL); +	MMIO_W(CRTC2_OFFSET, 0); +	MMIO_W(CUR2_OFFSET, 0); +	MMIO_W(CRTC2_OFFSET_CNTL, CRTC2_OFFSET_CNTL__CRTC2_OFFSET_FLIP_CNTL); +	for (i = 0; i < dev_priv->usec_timeout; i++) { +		if (!(CRTC_OFFSET__CRTC_GUI_TRIG_OFFSET & +		      MMIO_R(CRTC_OFFSET))) { +			break; +		} +		DRM_UDELAY(1); +	} +	if (i >= dev_priv->usec_timeout) { +		DRM_ERROR("[radeon_ms] timeout waiting for crtc...\n"); +	} +	for (i = 0; i < dev_priv->usec_timeout; i++) { +		if (!(CRTC2_OFFSET__CRTC2_GUI_TRIG_OFFSET & +		      MMIO_R(CRTC2_OFFSET))) { +			break; +		} +		DRM_UDELAY(1); +	} +	if (i >= dev_priv->usec_timeout) { +		DRM_ERROR("[radeon_ms] timeout waiting for crtc...\n"); +	} +	DRM_UDELAY(10000); +} + +static void radeon_ms_gpu_stop(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	uint32_t ov0_scale_cntl, crtc_ext_cntl, crtc_gen_cntl; +	uint32_t crtc2_gen_cntl, i; + +	radeon_ms_wait_for_idle(dev); +	/* Capture MC_STATUS in case things go wrong ... */ +	ov0_scale_cntl = dev_priv->ov0_scale_cntl = MMIO_R(OV0_SCALE_CNTL); +	crtc_ext_cntl = dev_priv->crtc_ext_cntl = MMIO_R(CRTC_EXT_CNTL); +	crtc_gen_cntl = dev_priv->crtc_gen_cntl = MMIO_R(CRTC_GEN_CNTL); +	crtc2_gen_cntl = dev_priv->crtc2_gen_cntl = MMIO_R(CRTC2_GEN_CNTL); +	ov0_scale_cntl &= ~OV0_SCALE_CNTL__OV0_OVERLAY_EN__MASK; +	crtc_ext_cntl |= CRTC_EXT_CNTL__CRTC_DISPLAY_DIS; +	crtc_gen_cntl &= ~CRTC_GEN_CNTL__CRTC_CUR_EN; +	crtc_gen_cntl &= ~CRTC_GEN_CNTL__CRTC_ICON_EN; +	crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_EXT_DISP_EN; +	crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B; +	crtc2_gen_cntl &= ~CRTC2_GEN_CNTL__CRTC2_CUR_EN; +	crtc2_gen_cntl &= ~CRTC2_GEN_CNTL__CRTC2_ICON_EN; +	crtc2_gen_cntl |= CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B; +	MMIO_W(OV0_SCALE_CNTL, ov0_scale_cntl); +	MMIO_W(CRTC_EXT_CNTL, crtc_ext_cntl); +	MMIO_W(CRTC_GEN_CNTL, crtc_gen_cntl); +	MMIO_W(CRTC2_GEN_CNTL, crtc2_gen_cntl); +	DRM_UDELAY(10000); +	switch (dev_priv->family) { +	case CHIP_R100: +	case CHIP_R200: +	case CHIP_RV200: +	case CHIP_RV250: +	case CHIP_RV280: +	case CHIP_RS300: +		for (i = 0; i < dev_priv->usec_timeout; i++) { +			if ((MC_STATUS__MC_IDLE & MMIO_R(MC_STATUS))) { +				DRM_INFO("[radeon_ms] gpu stoped in %d usecs\n", +					 i); +				return; +			} +			DRM_UDELAY(1); +		} +		break; +	case CHIP_R300: +	case CHIP_R350: +	case CHIP_R360: +	case CHIP_RV350: +	case CHIP_RV370: +	case CHIP_RV380: +	case CHIP_RS400: +	case CHIP_RV410: +	case CHIP_R420: +	case CHIP_R430: +	case CHIP_R480: +		for (i = 0; i < dev_priv->usec_timeout; i++) { +			if ((MC_STATUS__MC_IDLE_R3 & MMIO_R(MC_STATUS))) { +				DRM_INFO("[radeon_ms] gpu stoped in %d usecs\n", +					 i); +				return; +			} +			DRM_UDELAY(1); +		} +		break; +	default: +		DRM_ERROR("Unknown radeon family, aborting\n"); +		return; +	} +	DRM_ERROR("[radeon_ms] failed to stop gpu...will proceed anyway\n"); +	DRM_UDELAY(20000); +} + +static int radeon_ms_wait_for_fifo(struct drm_device *dev, int num_fifo) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	int i; + +	for (i = 0; i < dev_priv->usec_timeout; i++) { +		int t; +		t = RBBM_STATUS__CMDFIFO_AVAIL__MASK & MMIO_R(RBBM_STATUS); +		t = t >> RBBM_STATUS__CMDFIFO_AVAIL__SHIFT; +		if (t >= num_fifo) +			return 0; +		DRM_UDELAY(1); +	} +	DRM_ERROR("[radeon_ms] failed to wait for fifo\n"); +	return -EBUSY; +} + +int radeon_ms_gpu_initialize(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_state *state = &dev_priv->driver_state; +	int ret; + +	state->disp_misc_cntl = DISP_MISC_CNTL__SYNC_PAD_FLOP_EN | +		REG_S(DISP_MISC_CNTL, SYNC_STRENGTH, 2) | +		REG_S(DISP_MISC_CNTL, PALETTE_MEM_RD_MARGIN, 0xb) | +		REG_S(DISP_MISC_CNTL, PALETTE2_MEM_RD_MARGIN, 0xb) | +		REG_S(DISP_MISC_CNTL, RMX_BUF_MEM_RD_MARGIN, 0x5); +	state->disp_merge_cntl = REG_S(DISP_MERGE_CNTL, DISP_GRPH_ALPHA, 0xff) | +		REG_S(DISP_MERGE_CNTL, DISP_OV0_ALPHA, 0xff); +	state->disp_pwr_man = DISP_PWR_MAN__DISP_PWR_MAN_D3_CRTC_EN | +		DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN | +		REG_S(DISP_PWR_MAN, DISP_PWR_MAN_DPMS, DISP_PWR_MAN_DPMS__OFF) | +		DISP_PWR_MAN__DISP_D3_RST | +		DISP_PWR_MAN__DISP_D3_REG_RST | +		DISP_PWR_MAN__DISP_D3_GRPH_RST | +		DISP_PWR_MAN__DISP_D3_SUBPIC_RST | +		DISP_PWR_MAN__DISP_D3_OV0_RST | +		DISP_PWR_MAN__DISP_D1D2_GRPH_RST | +		DISP_PWR_MAN__DISP_D1D2_SUBPIC_RST | +		DISP_PWR_MAN__DISP_D1D2_OV0_RST | +		DISP_PWR_MAN__DISP_DVO_ENABLE_RST | +		DISP_PWR_MAN__TV_ENABLE_RST; +	state->disp2_merge_cntl = 0; +	ret = radeon_ms_gpu_address_space_init(dev); +	if (ret) { +		return ret; +	} + +	/* initialize bus */ +	ret = dev_priv->bus_init(dev); +	if (ret != 0) { +		return ret; +	} +	return 0; +} + +void radeon_ms_gpu_dpms(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_state *state = &dev_priv->driver_state; + +	if (dev_priv->crtc1_dpms == dev_priv->crtc2_dpms) { +		/* both crtc are in same state so use global display pwr */ +		state->disp_pwr_man &= ~DISP_PWR_MAN__DISP_PWR_MAN_DPMS__MASK; +		switch(dev_priv->crtc1_dpms) { +		case DPMSModeOn: +			state->disp_pwr_man |= REG_S(DISP_PWR_MAN, +					DISP_PWR_MAN_DPMS, +					DISP_PWR_MAN_DPMS__ON); +			break; +		case DPMSModeStandby: +			state->disp_pwr_man |= REG_S(DISP_PWR_MAN, +					DISP_PWR_MAN_DPMS, +					DISP_PWR_MAN_DPMS__STANDBY); +			break; +		case DPMSModeSuspend: +			state->disp_pwr_man |= REG_S(DISP_PWR_MAN, +					DISP_PWR_MAN_DPMS, +					DISP_PWR_MAN_DPMS__SUSPEND); +			break; +		case DPMSModeOff: +			state->disp_pwr_man |= REG_S(DISP_PWR_MAN, +					DISP_PWR_MAN_DPMS, +					DISP_PWR_MAN_DPMS__OFF); +			break; +		default: +			/* error */ +			break; +		} +		MMIO_W(DISP_PWR_MAN, state->disp_pwr_man); +	} else { +		state->disp_pwr_man &= ~DISP_PWR_MAN__DISP_PWR_MAN_DPMS__MASK; +		state->disp_pwr_man |= REG_S(DISP_PWR_MAN, +				DISP_PWR_MAN_DPMS, +				DISP_PWR_MAN_DPMS__ON); +		MMIO_W(DISP_PWR_MAN, state->disp_pwr_man); +	} +} + +void radeon_ms_gpu_flush(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	uint32_t i; +	uint32_t purge2d; +	uint32_t purge3d; + +	switch (dev_priv->family) { +	case CHIP_R100: +	case CHIP_R200: +	case CHIP_RV200: +	case CHIP_RV250: +	case CHIP_RV280: +	case CHIP_RS300: +		purge2d = REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FLUSH, 3) | +			REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FREE, 3); +		purge3d = REG_S(RB3D_DSTCACHE_CTLSTAT, DC_FLUSH, 3) | +			REG_S(RB3D_DSTCACHE_CTLSTAT, DC_FREE, 3); +		MMIO_W(RB2D_DSTCACHE_CTLSTAT, purge2d); +		MMIO_W(RB3D_DSTCACHE_CTLSTAT, purge3d); +		break; +	case CHIP_R300: +	case CHIP_R350: +	case CHIP_R360: +	case CHIP_RV350: +	case CHIP_RV370: +	case CHIP_RV380: +	case CHIP_RS400: +	case CHIP_RV410: +	case CHIP_R420: +	case CHIP_R430: +	case CHIP_R480: +		purge2d = REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FLUSH, 3) | +			REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FREE, 3); +		purge3d = REG_S(RB3D_DSTCACHE_CTLSTAT_R3, DC_FLUSH, 3) | +			REG_S(RB3D_DSTCACHE_CTLSTAT_R3, DC_FREE, 3); +		MMIO_W(RB2D_DSTCACHE_CTLSTAT, purge2d); +		MMIO_W(RB3D_DSTCACHE_CTLSTAT_R3, purge3d); +		break; +	default: +		DRM_ERROR("Unknown radeon family, aborting\n"); +		return; +	} +	for (i = 0; i < dev_priv->usec_timeout; i++) { +		if (!(RB2D_DSTCACHE_CTLSTAT__DC_BUSY & +					MMIO_R(RB2D_DSTCACHE_CTLSTAT))) { +			return; +		} +		DRM_UDELAY(1); +	} +	DRM_ERROR("[radeon_ms] gpu flush timeout\n"); +} + +void radeon_ms_gpu_restore(struct drm_device *dev, struct radeon_state *state) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	uint32_t wait_until; +	uint32_t fbstart; +	int ret, ok = 1; + +	radeon_ms_gpu_reset(dev); +	radeon_ms_wait_for_idle(dev); +	radeon_ms_gpu_stop(dev); + +	MMIO_W(AIC_CTRL, state->aic_ctrl); +	MMIO_W(MC_FB_LOCATION, state->mc_fb_location); +	MMIO_R(MC_FB_LOCATION); +	MMIO_W(CONFIG_APER_0_BASE, state->config_aper_0_base); +	MMIO_W(CONFIG_APER_1_BASE, state->config_aper_1_base); +	MMIO_W(CONFIG_APER_SIZE, state->config_aper_size); +	MMIO_W(DISPLAY_BASE_ADDR, state->display_base_addr); +	if (dev_priv->bus_restore) { +		dev_priv->bus_restore(dev, state); +	} + +	radeon_ms_gpu_reset(dev); +	radeon_ms_gpu_resume(dev); + +	MMIO_W(BUS_CNTL, state->bus_cntl); +	wait_until = WAIT_UNTIL__WAIT_DMA_VIPH0_IDLE | +		WAIT_UNTIL__WAIT_DMA_VIPH1_IDLE | +		WAIT_UNTIL__WAIT_DMA_VIPH2_IDLE | +		WAIT_UNTIL__WAIT_DMA_VIPH3_IDLE | +		WAIT_UNTIL__WAIT_DMA_VID_IDLE | +		WAIT_UNTIL__WAIT_DMA_GUI_IDLE | +		WAIT_UNTIL__WAIT_2D_IDLE | +		WAIT_UNTIL__WAIT_3D_IDLE | +		WAIT_UNTIL__WAIT_2D_IDLECLEAN | +		WAIT_UNTIL__WAIT_3D_IDLECLEAN | +		WAIT_UNTIL__WAIT_HOST_IDLECLEAN; +	switch (dev_priv->family) { +	case CHIP_R100: +	case CHIP_R200: +	case CHIP_RV200: +	case CHIP_RV250: +	case CHIP_RV280: +	case CHIP_RS300: +		break; +	case CHIP_R300: +	case CHIP_R350: +	case CHIP_R360: +	case CHIP_RV350: +	case CHIP_RV370: +	case CHIP_RV380: +	case CHIP_RS400: +	case CHIP_RV410: +	case CHIP_R420: +	case CHIP_R430: +	case CHIP_R480: +		wait_until |= WAIT_UNTIL__WAIT_VAP_IDLE; +		break; +	} +	MMIO_W(WAIT_UNTIL, wait_until);  +	MMIO_W(DISP_MISC_CNTL, state->disp_misc_cntl); +	MMIO_W(DISP_PWR_MAN, state->disp_pwr_man); +	MMIO_W(DISP_MERGE_CNTL, state->disp_merge_cntl); +	MMIO_W(DISP_OUTPUT_CNTL, state->disp_output_cntl); +	MMIO_W(DISP2_MERGE_CNTL, state->disp2_merge_cntl); + +	/* Setup engine location. This shouldn't be necessary since we +	 * set them appropriately before any accel ops, but let's avoid +	 * random bogus DMA in case we inadvertently trigger the engine +	 * in the wrong place (happened). +	 */ +	ret = radeon_ms_wait_for_fifo(dev, 2); +	if (ret) { +		ok = 0; +		DRM_ERROR("[radeon_ms] no fifo for setting up dst & src gui\n"); +		DRM_ERROR("[radeon_ms] proceed anyway\n"); +	} +	fbstart = (MC_FB_LOCATION__MC_FB_START__MASK & +			MMIO_R(MC_FB_LOCATION)) << 16; +	MMIO_W(DST_PITCH_OFFSET, +		REG_S(DST_PITCH_OFFSET, DST_OFFSET, fbstart >> 10)); +	MMIO_W(SRC_PITCH_OFFSET, +		REG_S(SRC_PITCH_OFFSET, SRC_OFFSET, fbstart >> 10)); + +	ret = radeon_ms_wait_for_fifo(dev, 1); +	if (ret) { +		ok = 0; +		DRM_ERROR("[radeon_ms] no fifo for setting up dp data type\n"); +		DRM_ERROR("[radeon_ms] proceed anyway\n"); +	} +#ifdef __BIG_ENDIAN +	MMIO_W(DP_DATATYPE, DP_DATATYPE__DP_BYTE_PIX_ORDER); +#else +	MMIO_W(DP_DATATYPE, 0); +#endif + +	ret = radeon_ms_wait_for_fifo(dev, 1); +	if (ret) { +		ok = 0; +		DRM_ERROR("[radeon_ms] no fifo for setting up surface cntl\n"); +		DRM_ERROR("[radeon_ms] proceed anyway\n"); +	} +	MMIO_W(SURFACE_CNTL, SURFACE_CNTL__SURF_TRANSLATION_DIS); + +	ret = radeon_ms_wait_for_fifo(dev, 2); +	if (ret) { +		ok = 0; +		DRM_ERROR("[radeon_ms] no fifo for setting scissor\n"); +		DRM_ERROR("[radeon_ms] proceed anyway\n"); +	} +	MMIO_W(DEFAULT_SC_BOTTOM_RIGHT, 0x1fff1fff); +	MMIO_W(DEFAULT2_SC_BOTTOM_RIGHT, 0x1fff1fff); + +	ret = radeon_ms_wait_for_fifo(dev, 1); +	if (ret) { +		ok = 0; +		DRM_ERROR("[radeon_ms] no fifo for setting up gui cntl\n"); +		DRM_ERROR("[radeon_ms] proceed anyway\n"); +	} +	MMIO_W(DP_GUI_MASTER_CNTL, 0); + +	ret = radeon_ms_wait_for_fifo(dev, 5); +	if (ret) { +		ok = 0; +		DRM_ERROR("[radeon_ms] no fifo for setting up clear color\n"); +		DRM_ERROR("[radeon_ms] proceed anyway\n"); +	} +	MMIO_W(DP_BRUSH_BKGD_CLR, 0x00000000); +	MMIO_W(DP_BRUSH_FRGD_CLR, 0xffffffff); +	MMIO_W(DP_SRC_BKGD_CLR, 0x00000000); +	MMIO_W(DP_SRC_FRGD_CLR, 0xffffffff); +	MMIO_W(DP_WRITE_MSK, 0xffffffff); + +	if (!ok) { +		DRM_ERROR("[radeon_ms] engine restore not enough fifo\n"); +	} +} + +void radeon_ms_gpu_save(struct drm_device *dev, struct radeon_state *state) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	state->aic_ctrl = MMIO_R(AIC_CTRL); +	state->bus_cntl = MMIO_R(BUS_CNTL); +	state->mc_fb_location = MMIO_R(MC_FB_LOCATION); +	state->display_base_addr = MMIO_R(DISPLAY_BASE_ADDR); +	state->config_aper_0_base = MMIO_R(CONFIG_APER_0_BASE); +	state->config_aper_1_base = MMIO_R(CONFIG_APER_1_BASE); +	state->config_aper_size = MMIO_R(CONFIG_APER_SIZE); +	state->disp_misc_cntl = MMIO_R(DISP_MISC_CNTL); +	state->disp_pwr_man = MMIO_R(DISP_PWR_MAN); +	state->disp_merge_cntl = MMIO_R(DISP_MERGE_CNTL); +	state->disp_output_cntl = MMIO_R(DISP_OUTPUT_CNTL); +	state->disp2_merge_cntl = MMIO_R(DISP2_MERGE_CNTL); +	if (dev_priv->bus_save) { +		dev_priv->bus_save(dev, state); +	} +} + +int radeon_ms_wait_for_idle(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	int i, j, ret; + +	for (i = 0; i < 2; i++) { +		ret = radeon_ms_wait_for_fifo(dev, 64); +		if (ret) { +			DRM_ERROR("[radeon_ms] fifo not empty\n"); +		} +		for (j = 0; j < dev_priv->usec_timeout; j++) { +			if (!(RBBM_STATUS__GUI_ACTIVE & MMIO_R(RBBM_STATUS))) { +				radeon_ms_gpu_flush(dev); +				return 0; +			} +			DRM_UDELAY(1); +		} +		DRM_ERROR("[radeon_ms] idle timed out:  status=0x%08x\n", +				MMIO_R(RBBM_STATUS)); +		radeon_ms_gpu_stop(dev); +		radeon_ms_gpu_reset(dev); +	} +	return -EBUSY; +} diff --git a/shared-core/radeon_ms_i2c.c b/shared-core/radeon_ms_i2c.c new file mode 100644 index 00000000..f4468c1e --- /dev/null +++ b/shared-core/radeon_ms_i2c.c @@ -0,0 +1,336 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * All Rights Reserved. + * + * 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 on 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 + * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS 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. + */ +#include "radeon_ms.h" + +static int get_clock(void *data) +{ +	struct radeon_ms_i2c *i2c = data; +	struct drm_radeon_private *dev_priv = i2c->drm_dev->dev_private; +	int v; + +	switch (i2c->reg) { +	case VIPPAD_EN: +		v = MMIO_R(VIPPAD_Y); +		if ((REG_G(VIPPAD_Y, VIPPAD_Y_VHAD, v) & 2)) { +			v = 1; +		} else { +			v = 0; +		} +		break; +	case VIPPAD1_EN: +		v = MMIO_R(VIPPAD1_Y); +		if ((REG_G(VIPPAD1_Y, VIPPAD_Y_DVODATA, v) & 8)) { +			v = 1; +		} else { +			v = 0; +		} +		break; +	case GPIO_DDC1: +		v = MMIO_R(GPIO_DDC1); +		if ((GPIO_DDC1__DDC1_CLK_INPUT & v)) { +			v = 1; +		} else { +			v = 0; +		} +		break; +	case GPIO_DDC2: +		v = MMIO_R(GPIO_DDC2); +		if ((GPIO_DDC2__DDC2_CLK_INPUT & v)) { +			v = 1; +		} else { +			v = 0; +		} +		break; +	case GPIO_MONID: +		v = MMIO_R(GPIO_MONID); +		if ((GPIO_MONID__GPIO_MONID_1_INPUT & v)) { +			v = 1; +		} else { +			v = 0; +		} +		break; +	case GPIO_CRT2_DDC: +		v = MMIO_R(GPIO_CRT2_DDC); +		if ((GPIO_CRT2_DDC__CRT2_DDC_CLK_INPUT & v)) { +			v = 1; +		} else { +			v = 0; +		} +		break; +	default: +		v = 0; +		break; +	} +	return v; +} + +static int get_data(void *data) +{ +	struct radeon_ms_i2c *i2c = data; +	struct drm_radeon_private *dev_priv = i2c->drm_dev->dev_private; +	int v; + +	switch (i2c->reg) { +	case VIPPAD_EN: +		v = MMIO_R(VIPPAD_Y); +		if ((REG_G(VIPPAD_Y, VIPPAD_Y_VHAD, v) & 1)) { +			v = 1; +		} else { +			v = 0; +		} +		break; +	case VIPPAD1_EN: +		v = MMIO_R(VIPPAD1_Y); +		if ((REG_G(VIPPAD1_Y, VIPPAD_Y_DVODATA, v) & 4)) { +			v = 1; +		} else { +			v = 0; +		} +		break; +	case GPIO_DDC1: +		v = MMIO_R(GPIO_DDC1); +		if ((GPIO_DDC1__DDC1_DATA_INPUT & v)) { +			v = 1; +		} else { +			v = 0; +		} +		break; +	case GPIO_DDC2: +		v = MMIO_R(GPIO_DDC2); +		if ((GPIO_DDC2__DDC2_DATA_INPUT & v)) { +			v = 1; +		} else { +			v = 0; +		} +		break; +	case GPIO_MONID: +		v = MMIO_R(GPIO_MONID); +		if ((GPIO_MONID__GPIO_MONID_0_INPUT & v)) { +			v = 1; +		} else { +			v = 0; +		} +		break; +	case GPIO_CRT2_DDC: +		v = MMIO_R(GPIO_CRT2_DDC); +		if ((GPIO_CRT2_DDC__CRT2_DDC_DATA_INPUT & v)) { +			v = 1; +		} else { +			v = 0; +		} +		break; +	default: +		v = 0; +		break; +	} +	return v; +} + +static void set_clock(void *i2c_priv, int clock) +{ +	struct radeon_ms_i2c *i2c = i2c_priv; +	struct drm_radeon_private *dev_priv = i2c->drm_dev->dev_private; +	int v, line; + +	v = MMIO_R(i2c->reg); +	switch (i2c->reg) { +	case VIPPAD_EN: +		line = REG_G(VIPPAD_EN, VIPPAD_EN_VHAD, v) & ~2; +		v &= ~VIPPAD_EN__VIPPAD_EN_VHAD__MASK; +		if (!clock) { +			v |= REG_S(VIPPAD_EN, VIPPAD_EN_VHAD, line | 2); +		} else { +			v |= REG_S(VIPPAD_EN, VIPPAD_EN_VHAD, line); +		} +		break; +	case VIPPAD1_EN: +		line = REG_G(VIPPAD1_EN, VIPPAD_EN_DVODATA, v) & ~8; +		v &= ~VIPPAD1_EN__VIPPAD_EN_DVODATA__MASK; +		if (!clock) { +			v |= REG_S(VIPPAD1_EN, VIPPAD_EN_DVODATA, line | 8); +		} else { +			v |= REG_S(VIPPAD1_EN, VIPPAD_EN_DVODATA, line); +		} +		break; +	case GPIO_DDC1: +		v &= ~GPIO_DDC1__DDC1_CLK_OUT_EN; +		if (!clock) { +			v |= GPIO_DDC1__DDC1_CLK_OUT_EN; +		} +		break; +	case GPIO_DDC2: +		v &= ~GPIO_DDC2__DDC2_CLK_OUT_EN; +		if (!clock) { +			v |= GPIO_DDC2__DDC2_CLK_OUT_EN; +		} +		break; +	case GPIO_MONID: +		v &= ~GPIO_MONID__GPIO_MONID_1_OUT_EN; +		if (!clock) { +			v |= GPIO_MONID__GPIO_MONID_1_OUT_EN; +		} +		break; +	case GPIO_CRT2_DDC: +		v &= ~GPIO_CRT2_DDC__CRT2_DDC_CLK_OUT_EN; +		if (!clock) { +			v |= GPIO_CRT2_DDC__CRT2_DDC_CLK_OUT_EN; +		} +		break; +	default: +		return; +	} +	MMIO_W(i2c->reg, v); +} + +static void set_data(void *i2c_priv, int data) +{ +	struct radeon_ms_i2c *i2c = i2c_priv; +	struct drm_radeon_private *dev_priv = i2c->drm_dev->dev_private; +	int v, line; + +	v = MMIO_R(i2c->reg); +	switch (i2c->reg) { +	case VIPPAD_EN: +		line = REG_G(VIPPAD_EN, VIPPAD_EN_VHAD, v) & ~1; +		v &= ~VIPPAD_EN__VIPPAD_EN_VHAD__MASK; +		if (!data) { +			v |= REG_S(VIPPAD_EN, VIPPAD_EN_VHAD, line | 1); +		} else { +			v |= REG_S(VIPPAD_EN, VIPPAD_EN_VHAD, line); +		} +		break; +	case VIPPAD1_EN: +		line = REG_G(VIPPAD1_EN, VIPPAD_EN_DVODATA, v) & ~4; +		v &= ~VIPPAD1_EN__VIPPAD_EN_DVODATA__MASK; +		if (!data) { +			v |= REG_S(VIPPAD1_EN, VIPPAD_EN_DVODATA, line | 4); +		} else { +			v |= REG_S(VIPPAD1_EN, VIPPAD_EN_DVODATA, line); +		} +		break; +	case GPIO_DDC1: +		v &= ~GPIO_DDC1__DDC1_DATA_OUT_EN; +		if (!data) { +			v |= GPIO_DDC1__DDC1_DATA_OUT_EN; +		} +		break; +	case GPIO_DDC2: +		v &= ~GPIO_DDC2__DDC2_DATA_OUT_EN; +		if (!data) { +			v |= GPIO_DDC2__DDC2_DATA_OUT_EN; +		} +		break; +	case GPIO_MONID: +		v &= ~GPIO_MONID__GPIO_MONID_0_OUT_EN; +		if (!data) { +			v |= GPIO_MONID__GPIO_MONID_0_OUT_EN; +		} +		break; +	case GPIO_CRT2_DDC: +		v &= ~GPIO_CRT2_DDC__CRT2_DDC_DATA_OUT_EN; +		if (!data) { +			v |= GPIO_CRT2_DDC__CRT2_DDC_DATA_OUT_EN; +		} +		break; +	default: +		return; +	} +	MMIO_W(i2c->reg, v); +} + +/** + * radeon_ms_i2c_create - instantiate an radeon i2c bus on specified GPIO reg + * @dev: DRM device + * @output: driver specific output device + * @reg: GPIO reg to use + * @name: name for this bus + * + * Creates and registers a new i2c bus with the Linux i2c layer, for use + * in output probing and control (e.g. DDC or SDVO control functions). + * + */ +struct radeon_ms_i2c *radeon_ms_i2c_create(struct drm_device *dev, +					   const uint32_t reg, +					   const char *name) +{ +	struct radeon_ms_i2c *i2c; +	int ret; + +	i2c = drm_alloc(sizeof(struct radeon_ms_i2c), DRM_MEM_DRIVER); +	if (i2c == NULL) { +		return NULL; +	} +	memset(i2c, 0, sizeof(struct radeon_ms_i2c)); + +	i2c->drm_dev = dev; +	i2c->reg = reg; +	snprintf(i2c->adapter.name, I2C_NAME_SIZE, "radeon-%s", name); +	i2c->adapter.owner = THIS_MODULE; +	/* fixme need to take a look at what its needed for */ +	i2c->adapter.id = I2C_HW_B_RADEON; +	i2c->adapter.algo_data = &i2c->algo; +	i2c->adapter.dev.parent = &dev->pdev->dev; +	i2c->algo.setsda = set_data; +	i2c->algo.setscl = set_clock; +	i2c->algo.getsda = get_data; +	i2c->algo.getscl = get_clock; +	i2c->algo.udelay = 20; +	i2c->algo.timeout = usecs_to_jiffies(2200); +	i2c->algo.data = i2c; + +	i2c_set_adapdata(&i2c->adapter, i2c); + +	ret = i2c_bit_add_bus(&i2c->adapter); +	if(ret) { +		DRM_INFO("[radeon_ms] failed to register I2C '%s' bus (0x%X)\n", +			 i2c->adapter.name, reg); +		goto out_free; +	} +	DRM_INFO("[radeon_ms] registered I2C '%s' bus (0x%X)\n", +		 i2c->adapter.name, reg); +	return i2c; + +out_free: +	drm_free(i2c, sizeof(struct radeon_ms_i2c), DRM_MEM_DRIVER); +	return NULL; +} + +/** + * radeon_ms_i2c_destroy - unregister and free i2c bus resources + * @output: channel to free + * + * Unregister the adapter from the i2c layer, then free the structure. + */ +void radeon_ms_i2c_destroy(struct radeon_ms_i2c *i2c) +{ +	if (i2c == NULL) { +		return; +	} +	i2c_del_adapter(&i2c->adapter); +	drm_free(i2c, sizeof(struct radeon_ms_i2c), DRM_MEM_DRIVER); +} diff --git a/shared-core/radeon_ms_irq.c b/shared-core/radeon_ms_irq.c new file mode 100644 index 00000000..2f94118f --- /dev/null +++ b/shared-core/radeon_ms_irq.c @@ -0,0 +1,161 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * All Rights Reserved. + * + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: + *    Jerome Glisse <glisse@freedesktop.org> + */ +#include "drmP.h" +#include "drm.h" +#include "radeon_ms.h" + +static uint32_t radeon_ack_irqs(struct drm_radeon_private *dev_priv, +				uint32_t mask) +{ +	uint32_t irqs; + +	irqs = MMIO_R(GEN_INT_STATUS); +	if (irqs) { +		MMIO_W(GEN_INT_STATUS, irqs); +	} +	if (irqs & (~mask)) { +		/* reprogram irq */ +		MMIO_W(GEN_INT_CNTL, dev_priv->driver_state.gen_int_cntl); +	} +	return irqs; +} + +void radeon_ms_irq_emit(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	uint32_t cmd[4]; +	int i, ret; + +	cmd[0] = CP_PACKET0(GEN_INT_CNTL, 1); +	cmd[1] = dev_priv->driver_state.gen_int_cntl | GEN_INT_CNTL__SW_INT_EN; +	cmd[2] = GEN_INT_STATUS__SW_INT_SET; +	/* try to wait but if we timeout we likely are in bad situation */ +	for (i = 0; i < dev_priv->usec_timeout; i++) { +		ret = radeon_ms_ring_emit(dev, cmd, 3); +		if (!ret) { +			break; +		} +	} +} + +static void radeon_ms_irq_enable(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_state *state = &dev_priv->driver_state; + +	state->gen_int_cntl = GEN_INT_CNTL__SW_INT_EN; +	radeon_ms_irq_restore(dev, state); +} + +irqreturn_t radeon_ms_irq_handler(DRM_IRQ_ARGS) +{ +	struct drm_device *dev = (struct drm_device *)arg; +	struct drm_radeon_private *dev_priv = dev->dev_private; +	uint32_t status, mask; + +	/* Only consider the bits we're interested in - others could be used +	 * outside the DRM +	 */ +	mask = GEN_INT_STATUS__SW_INT | +	       GEN_INT_STATUS__CRTC_VBLANK_STAT | +	       GEN_INT_STATUS__CRTC2_VBLANK_STAT; +	status = radeon_ack_irqs(dev_priv, mask); +	if (!status) { +		return IRQ_NONE; +	} + +	/* SW interrupt */ +	if (GEN_INT_STATUS__SW_INT & status) { +		radeon_ms_fence_handler(dev); +	} +	radeon_ms_fence_handler(dev); +	return IRQ_HANDLED; +} + +void radeon_ms_irq_preinstall(struct drm_device * dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_state *state = &dev_priv->driver_state; +	uint32_t mask; + +	/* Disable *all* interrupts */ +	state->gen_int_cntl = 0; +	radeon_ms_irq_restore(dev, state); + +	/* Clear bits if they're already high */ +	mask = GEN_INT_STATUS__SW_INT | +	       GEN_INT_STATUS__CRTC_VBLANK_STAT | +	       GEN_INT_STATUS__CRTC2_VBLANK_STAT; +	radeon_ack_irqs(dev_priv, mask); +} + +int radeon_ms_irq_postinstall(struct drm_device * dev) +{ +	radeon_ms_irq_enable(dev); +	return 0; +} + +int radeon_ms_irq_init(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_state *state = &dev_priv->driver_state; + +	/* Disable *all* interrupts */ +	state->gen_int_cntl = 0; +	radeon_ms_irq_restore(dev, state); +	return 0; +} + +void radeon_ms_irq_restore(struct drm_device *dev, struct radeon_state *state) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	MMIO_W(GEN_INT_CNTL, state->gen_int_cntl); +} + +void radeon_ms_irq_save(struct drm_device *dev, struct radeon_state *state) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	state->gen_int_cntl = MMIO_R(GEN_INT_CNTL); +} + +void radeon_ms_irq_uninstall(struct drm_device * dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_state *state = &dev_priv->driver_state; + +	if (dev_priv == NULL) { +		return; +	} + +	/* Disable *all* interrupts */ +	state->gen_int_cntl = 0; +	radeon_ms_irq_restore(dev, state); +} diff --git a/shared-core/radeon_ms_output.c b/shared-core/radeon_ms_output.c new file mode 100644 index 00000000..bc174371 --- /dev/null +++ b/shared-core/radeon_ms_output.c @@ -0,0 +1,361 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * All Rights Reserved. + * + * 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 on 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 + * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS 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. + */ +#include "radeon_ms.h" + +static struct radeon_ms_output *radeon_ms_connector_get_output( +		struct drm_radeon_private *dev_priv, +		struct radeon_ms_connector *connector, int i) +{ +	if (connector->outputs[i] < 0) { +		return NULL; +	} +	if (connector->outputs[i] >= RADEON_MAX_OUTPUTS) { +		return NULL; +	} +	i = connector->outputs[i]; +	if (dev_priv->outputs[i] == NULL) { +		return NULL; +	} +	if (dev_priv->outputs[i]->connector == NULL) { +		return dev_priv->outputs[i]; +	} +	if (dev_priv->outputs[i]->connector == connector) { +		return dev_priv->outputs[i]; +	} +	return NULL; +} + +static void radeon_ms_output_dpms(struct drm_output *output, int mode) +{ +	struct drm_radeon_private *dev_priv = output->dev->dev_private; +	struct radeon_ms_connector *connector = output->driver_private; +	struct radeon_ms_output *routput = NULL; +	int i; + +	if (connector == NULL) { +		return; +	} +	for (i = 0; i < RADEON_MAX_OUTPUTS; i++) { +		routput = radeon_ms_connector_get_output(dev_priv, +				connector, i); + +		if (routput) { +			routput->connector = connector; +			routput->dpms(routput, mode); +		} +	} +	radeon_ms_gpu_dpms(output->dev); +} + +static int radeon_ms_output_mode_valid(struct drm_output *output, +		struct drm_display_mode *mode) +{ +	struct radeon_ms_connector *connector = output->driver_private; + +	if (connector == NULL) { +		return MODE_ERROR; +	} +	return MODE_OK; +} + +static bool radeon_ms_output_mode_fixup(struct drm_output *output, +		struct drm_display_mode *mode, +		struct drm_display_mode *adjusted_mode) +{ +	return true; +} + +static void radeon_ms_output_prepare(struct drm_output *output) +{ +	if (output->funcs->dpms) { +		output->funcs->dpms(output, DPMSModeOff); +	} +} + +static void radeon_ms_output_commit(struct drm_output *output) +{ +	if (output->funcs->dpms) { +		output->funcs->dpms(output, DPMSModeOn); +	} +} + +static void radeon_ms_output_mode_set(struct drm_output *output, +		struct drm_display_mode *mode, +		struct drm_display_mode *adjusted_mode) +{ +	struct drm_radeon_private *dev_priv = output->dev->dev_private; +	struct radeon_ms_connector *connector = output->driver_private; +	struct radeon_ms_crtc *crtc; +	struct radeon_ms_output *routput = NULL; +	int i; + +	if (connector == NULL) { +		return; +	} +	if (output->crtc == NULL) { +		return; +	} +	crtc = output->crtc->driver_private; +	connector->crtc = crtc->crtc; +	/* catch unknown crtc */ +	switch (connector->crtc) { +		case 1: +		case 2: +			break; +		default: +			/* error */ +			return; +	} +	for (i = 0; i < RADEON_MAX_OUTPUTS; i++) { +		routput = radeon_ms_connector_get_output(dev_priv, +				connector, i); +		if (routput) { +			routput->connector = connector; +			routput->mode_set(routput, mode, adjusted_mode); +		} +	} +} + +static enum drm_output_status radeon_ms_output_detect(struct drm_output *output) +{ +	struct radeon_ms_connector *connector = output->driver_private; + +	if (connector == NULL || connector->i2c == NULL) { +		return output_status_unknown; +	} +	kfree(connector->edid); +	connector->edid = drm_get_edid(output, &connector->i2c->adapter); +	if (connector->edid == NULL) { +		return output_status_unknown; +	} +	return output_status_connected; +} + +static int radeon_ms_output_get_modes(struct drm_output *output) +{ +	struct radeon_ms_connector *connector = output->driver_private; +	int ret = 0; + +	if (connector == NULL || connector->i2c == NULL) { +		return 0; +	} +	if (connector->edid == NULL) { +		return 0; +	} +	drm_mode_output_update_edid_property(output, connector->edid); +	ret = drm_add_edid_modes(output, connector->edid); +	kfree(connector->edid); +	connector->edid = NULL; +	return ret; +} + +static void radeon_ms_output_cleanup(struct drm_output *output) +{ +	struct radeon_ms_connector *connector = output->driver_private; + +	if (connector == NULL) { +		return; +	} +	if (connector->edid) { +		kfree(connector->edid); +	} +	connector->edid = NULL; +	connector->output = NULL; +	output->driver_private = NULL; +} + +const struct drm_output_funcs radeon_ms_output_funcs = { +	.dpms = radeon_ms_output_dpms, +	.save = NULL, +	.restore = NULL, +	.mode_valid = radeon_ms_output_mode_valid, +	.mode_fixup = radeon_ms_output_mode_fixup, +	.prepare = radeon_ms_output_prepare, +	.mode_set = radeon_ms_output_mode_set, +	.commit = radeon_ms_output_commit, +	.detect = radeon_ms_output_detect, +	.get_modes = radeon_ms_output_get_modes, +	.cleanup = radeon_ms_output_cleanup, +}; + +void radeon_ms_connectors_destroy(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_ms_connector *connector = NULL; +	int i = 0; + +	for (i = 0; i < RADEON_MAX_CONNECTORS; i++) { +		if (dev_priv->connectors[i]) { +			connector = dev_priv->connectors[i]; +			dev_priv->connectors[i] = NULL; +			if (connector->output) { +				drm_output_destroy(connector->output); +				connector->output = NULL; +			} +			if (connector->i2c) { +				radeon_ms_i2c_destroy(connector->i2c); +				connector->i2c = NULL; +			} +			drm_free(connector, +					sizeof(struct radeon_ms_connector), +					DRM_MEM_DRIVER); +		} +	} +} + +int radeon_ms_connectors_from_properties(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_ms_connector *connector = NULL; +	struct drm_output *output = NULL; +	int i = 0, c = 0; + +	radeon_ms_connectors_destroy(dev); +	for (i = 0; i < RADEON_MAX_CONNECTORS; i++) { +		if (dev_priv->properties.connectors[i]) { +			connector = +				drm_alloc(sizeof(struct radeon_ms_connector), +						DRM_MEM_DRIVER); +			if (connector == NULL) { +				radeon_ms_connectors_destroy(dev); +				return -ENOMEM; +			} +			memcpy(connector, dev_priv->properties.connectors[i], +			       sizeof(struct radeon_ms_connector)); +			connector->i2c = +				radeon_ms_i2c_create(dev, connector->i2c_reg, +						     connector->name); +			if (connector->i2c == NULL) { +				radeon_ms_connectors_destroy(dev); +				return -ENOMEM; +			} +			output = drm_output_create(dev, +						   &radeon_ms_output_funcs, +						   connector->type); +			if (output == NULL) { +				radeon_ms_connectors_destroy(dev); +				return -EINVAL; +			} +			connector->output = output; +			output->driver_private = connector; +			output->possible_crtcs = 0x3; +			dev_priv->connectors[c++] = connector; +		} +	} +	return c; +} + +int radeon_ms_connectors_from_rom(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	switch (dev_priv->rom.type) { +	case ROM_COMBIOS: +		return radeon_ms_connectors_from_combios(dev); +	} +	return 0; +} + +void radeon_ms_outputs_destroy(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	int i = 0; + +	for (i = 0; i < RADEON_MAX_OUTPUTS; i++) { +		if (dev_priv->outputs[i]) { +			drm_free(dev_priv->outputs[i], +					sizeof(struct radeon_ms_output), +					DRM_MEM_DRIVER); +			dev_priv->outputs[i] = NULL; +		} +	} +} + +int radeon_ms_outputs_from_properties(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	int i = 0; +	int c = 0; + +	radeon_ms_outputs_destroy(dev); +	for (i = 0; i < RADEON_MAX_OUTPUTS; i++) { +		if (dev_priv->properties.outputs[i]) { +			dev_priv->outputs[i] = +				drm_alloc(sizeof(struct radeon_ms_output), +					  DRM_MEM_DRIVER); +			if (dev_priv->outputs[i] == NULL) { +				radeon_ms_outputs_destroy(dev); +				return -ENOMEM; +			} +			memcpy(dev_priv->outputs[i], +			       dev_priv->properties.outputs[i], +			       sizeof(struct radeon_ms_output)); +			dev_priv->outputs[i]->dev = dev; +			dev_priv->outputs[i]->initialize(dev_priv->outputs[i]); +			c++; +		} +	} +	return c; +} + +int radeon_ms_outputs_from_rom(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	switch (dev_priv->rom.type) { +	case ROM_COMBIOS: +		return radeon_ms_outputs_from_combios(dev); +	} +	return 0; +} + +void radeon_ms_outputs_restore(struct drm_device *dev, +		struct radeon_state *state) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	int i; + +	for (i = 0; i < RADEON_MAX_OUTPUTS; i++) { +		if (dev_priv->outputs[i]) { +			dev_priv->outputs[i]->restore(dev_priv->outputs[i], +					state); +		} +	} +} + +void radeon_ms_outputs_save(struct drm_device *dev, struct radeon_state *state) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	int i; + +	for (i = 0; i < RADEON_MAX_OUTPUTS; i++) { +		if (dev_priv->outputs[i]) { +			dev_priv->outputs[i]->save(dev_priv->outputs[i], state); +		} +	} +} diff --git a/shared-core/radeon_ms_properties.c b/shared-core/radeon_ms_properties.c new file mode 100644 index 00000000..baf2a7f2 --- /dev/null +++ b/shared-core/radeon_ms_properties.c @@ -0,0 +1,123 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: + *    Jerome Glisse <glisse@freedesktop.org> + */ +#include "drmP.h" +#include "drm.h" +#include "radeon_ms.h" + +struct radeon_ms_output radeon_ms_dac1 = { +	OUTPUT_DAC1, +	NULL, +	NULL, +	radeon_ms_dac1_initialize, +	radeon_ms_dac1_detect, +	radeon_ms_dac1_dpms, +	radeon_ms_dac1_get_modes, +	radeon_ms_dac1_mode_fixup, +	radeon_ms_dac1_mode_set, +	radeon_ms_dac1_restore, +	radeon_ms_dac1_save +}; + +struct radeon_ms_output radeon_ms_dac2 = { +	OUTPUT_DAC2, +	NULL, +	NULL, +	radeon_ms_dac2_initialize, +	radeon_ms_dac2_detect, +	radeon_ms_dac2_dpms, +	radeon_ms_dac2_get_modes, +	radeon_ms_dac2_mode_fixup, +	radeon_ms_dac2_mode_set, +	radeon_ms_dac2_restore, +	radeon_ms_dac2_save +}; + +struct radeon_ms_connector radeon_ms_vga = { +	NULL, NULL, NULL, CONNECTOR_VGA, MT_NONE, 0, GPIO_DDC1, +	{ +		0, -1, -1, -1, -1, -1, -1, -1 +	}, +	"VGA" +}; + +struct radeon_ms_connector radeon_ms_dvi_i_2 = { +	NULL, NULL, NULL, CONNECTOR_DVI_I, MT_NONE, 0, GPIO_DDC2, +	{ +		1, -1, -1, -1, -1, -1, -1, -1 +	}, +	"DVI-I" +}; + +struct radeon_ms_properties properties[] = { +	/* default only one VGA connector */ +	{ +		0, 0, 27000, 12, 25000, 200000, 1, 1, 1, 1, +		{ +			&radeon_ms_dac1, NULL, NULL, NULL, NULL, NULL, NULL, +			NULL +		}, +		{ +			&radeon_ms_vga, NULL, NULL, NULL, NULL, NULL, NULL, +			NULL +		} +	} +}; + +int radeon_ms_properties_init(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	int i, ret; + +	for (i = 1; i < sizeof(properties)/sizeof(properties[0]); i++) { +		if (dev->pdev->subsystem_vendor == properties[i].subvendor && +		    dev->pdev->subsystem_device == properties[i].subdevice) { +			DRM_INFO("[radeon_ms] found properties for " +			         "0x%04X:0x%04X\n", properties[i].subvendor, +				 properties[i].subdevice); +			memcpy(&dev_priv->properties, &properties[i], +			       sizeof(struct radeon_ms_properties)); +		} +	} +	if (dev_priv->properties.subvendor == 0) { +		ret = radeon_ms_rom_get_properties(dev); +		if (ret < 0) { +			return ret; +		} +		if (!ret) { +			memcpy(&dev_priv->properties, &properties[0], +			       sizeof(struct radeon_ms_properties)); +		} else { +			dev_priv->properties.pll_dummy_reads = 1; +			dev_priv->properties.pll_delay = 1; +			dev_priv->properties.pll_r300_errata = 1; +		} +		dev_priv->properties.subvendor = dev->pdev->subsystem_vendor; +		dev_priv->properties.subdevice = dev->pdev->subsystem_device; +	} +	return 0; +} diff --git a/shared-core/radeon_ms_properties.h b/shared-core/radeon_ms_properties.h new file mode 100644 index 00000000..a02a84d5 --- /dev/null +++ b/shared-core/radeon_ms_properties.h @@ -0,0 +1,50 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: + *    Jerome Glisse <glisse@freedesktop.org> + */ +#ifndef __RADEON_MS_PROPERTIES_H__ +#define __RADEON_MS_PROPERTIES_H__ + +#define RADEON_PAGE_SIZE        4096 +#define RADEON_MAX_CONNECTORS   8 +#define RADEON_MAX_OUTPUTS      8 + +struct radeon_ms_properties { +	uint16_t                    subvendor; +	uint16_t                    subdevice; +	int16_t                     pll_reference_freq; +	int16_t                     pll_reference_div; +	int32_t                     pll_min_pll_freq; +	int32_t                     pll_max_pll_freq; +	char                        pll_use_bios; +	char                        pll_dummy_reads; +	char                        pll_delay; +	char                        pll_r300_errata; +	struct radeon_ms_output     *outputs[RADEON_MAX_OUTPUTS]; +	struct radeon_ms_connector  *connectors[RADEON_MAX_CONNECTORS]; +}; + +#endif diff --git a/shared-core/radeon_ms_reg.h b/shared-core/radeon_ms_reg.h new file mode 100644 index 00000000..56963c63 --- /dev/null +++ b/shared-core/radeon_ms_reg.h @@ -0,0 +1,1681 @@ +/* + * Copyright 2007  Advanced Micro Devices, Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ +#ifndef __RADEON_REG_H__ +#define __RADEON_REG_H__ + +#define MC_FB_LOCATION                                      0x00000148 +#define    MC_FB_LOCATION__MC_FB_START__MASK                    0x0000FFFF +#define    MC_FB_LOCATION__MC_FB_START__SHIFT                   0 +#define    MC_FB_LOCATION__MC_FB_TOP__MASK                      0xFFFF0000 +#define    MC_FB_LOCATION__MC_FB_TOP__SHIFT                     16 +#define MC_AGP_LOCATION                                     0x0000014C +#define    MC_AGP_LOCATION__MC_AGP_START__MASK                  0x0000FFFF +#define    MC_AGP_LOCATION__MC_AGP_START__SHIFT                 0 +#define    MC_AGP_LOCATION__MC_AGP_TOP__MASK                    0xFFFF0000 +#define    MC_AGP_LOCATION__MC_AGP_TOP__SHIFT                   16 +#define AGP_COMMAND                                         0x00000F60 +#define    AGP_COMMAND__DATA_RATE__MASK                         0x00000007 +#define    AGP_COMMAND__DATA_RATE__SHIFT                        0 +#define    DATA_RATE__v2_1X                                         0x1 +#define    DATA_RATE__v2_2X                                         0x2 +#define    DATA_RATE__v2_4X                                         0x4 +#define    DATA_RATE__v3_4X                                         0x1 +#define    DATA_RATE__v3_8X                                         0x2 +#define    AGP_COMMAND__AGP_EN                                  0x00000100 +#define    AGP_COMMAND__SBA_EN                                  0x00000200 +#define    AGP_COMMAND__RQ_DEPTH__MASK                          0xFF000000 +#define    AGP_COMMAND__RQ_DEPTH__SHIFT                         24 +#define    AGP_COMMAND__FW_EN                                   0x00000010 +#define    AGP_COMMAND__MODE_4G_EN                              0x00000020 +#define    AGP_COMMAND__PARQSZ__MASK                            0x0000E000 +#define    AGP_COMMAND__PARQSZ__SHIFT                           13 +#define AGP_STATUS                                          0x00000F5C +#define    AGP_STATUS__RATE1X                                   0x00000001 +#define    AGP_STATUS__RATE2X                                   0x00000002 +#define    AGP_STATUS__RATE4X                                   0x00000004 +#define    AGP_STATUS__SBA                                      0x00000200 +#define    AGP_STATUS__RQ__MASK                                 0xFF000000 +#define    AGP_STATUS__RQ__SHIFT                                24 +#define    AGP_STATUS__FW                                       0x00000010 +#define    AGP_STATUS__MODE_4G                                  0x00000020 +#define    AGP_STATUS__RATE1X_4X                                0x00000001 +#define    AGP_STATUS__RATE2X_8X                                0x00000002 +#define    AGP_STATUS__MODE_AGP30                               0x00000008 +#define    AGP_STATUS__CAL_CYCLE__MASK                          0x00001C00 +#define    AGP_STATUS__CAL_CYCLE__SHIFT                         10 +#define    AGP_STATUS__ISOCH_SUPPORT                            0x00020000 +#define AGP_BASE                                            0x00000170 +#define    AGP_BASE__AGP_BASE_ADDR__MASK                        0xFFFFFFFF +#define    AGP_BASE__AGP_BASE_ADDR__SHIFT                       0 +#define AGP_BASE_2                                          0x0000015C +#define    AGP_BASE_2__AGP_BASE_ADDR_2__MASK                    0x0000000F +#define    AGP_BASE_2__AGP_BASE_ADDR_2__SHIFT                   0 +#define CONFIG_MEMSIZE                                      0x000000F8 +#define    CONFIG_MEMSIZE__CONFIG_MEMSIZE__MASK                 0x1F000000 +#define    CONFIG_MEMSIZE__CONFIG_MEMSIZE__SHIFT                24 +#define    CONFIG_MEMSIZE__CONFIG_MEMSIZE_R2__MASK              0x1FF00000 +#define    CONFIG_MEMSIZE__CONFIG_MEMSIZE_R2__SHIFT             20 +#define CONFIG_APER_0_BASE                                  0x00000100 +#define    CONFIG_APER_0_BASE__APER_0_BASE__MASK                0xFE000000 +#define    CONFIG_APER_0_BASE__APER_0_BASE__SHIFT               25 +#define CONFIG_APER_1_BASE                                  0x00000104 +#define    CONFIG_APER_1_BASE__APER_1_BASE__MASK                0xFF000000 +#define    CONFIG_APER_1_BASE__APER_1_BASE__SHIFT               24 +#define CONFIG_APER_SIZE                                    0x00000108 +#define    CONFIG_APER_SIZE__APER_SIZE__MASK                    0x0F000000 +#define    CONFIG_APER_SIZE__APER_SIZE__SHIFT                   24 +#define GEN_INT_CNTL                                        0x00000040 +#define    GEN_INT_CNTL__CRTC_VBLANK                            0x00000001 +#define    GEN_INT_CNTL__CRTC_VLINE                             0x00000002 +#define    GEN_INT_CNTL__CRTC_VSYNC                             0x00000004 +#define    GEN_INT_CNTL__SNAPSHOT                               0x00000008 +#define    GEN_INT_CNTL__FP_DETECT                              0x00000010 +#define    GEN_INT_CNTL__CRTC2_VLINE                            0x00000020 +#define    GEN_INT_CNTL__DMA_VIPH0_INT_EN                       0x00001000 +#define    GEN_INT_CNTL__CRTC2_VSYNC                            0x00000040 +#define    GEN_INT_CNTL__SNAPSHOT2                              0x00000080 +#define    GEN_INT_CNTL__CRTC2_VBLANK                           0x00000200 +#define    GEN_INT_CNTL__FP2_DETECT                             0x00000400 +#define    GEN_INT_CNTL__VSYNC_DIFF_OVER_LIMIT                  0x00000800 +#define    GEN_INT_CNTL__DMA_VIPH1_INT_EN                       0x00002000 +#define    GEN_INT_CNTL__DMA_VIPH2_INT_EN                       0x00004000 +#define    GEN_INT_CNTL__DMA_VIPH3_INT_EN                       0x00008000 +#define    GEN_INT_CNTL__I2C_INT_EN                             0x00020000 +#define    GEN_INT_CNTL__GUI_IDLE                               0x00080000 +#define    GEN_INT_CNTL__VIPH_INT_EN                            0x01000000 +#define    GEN_INT_CNTL__SW_INT_EN                              0x02000000 +#define    GEN_INT_CNTL__GEYSERVILLE                            0x08000000 +#define    GEN_INT_CNTL__DVI_I2C_INT                            0x20000000 +#define    GEN_INT_CNTL__GUIDMA                                 0x40000000 +#define    GEN_INT_CNTL__VIDDMA                                 0x80000000 +#define    GEN_INT_CNTL__TIMER_INT                              0x00010000 +#define    GEN_INT_CNTL__IDCT_INT_EN                            0x08000000 +#define GEN_INT_STATUS                                      0x00000044 +#define    GEN_INT_STATUS__CRTC_VBLANK_STAT                     0x00000001 +#define    GEN_INT_STATUS__CRTC_VBLANK_STAT_AK                  0x00000001 +#define    GEN_INT_STATUS__CRTC_VLINE_STAT                      0x00000002 +#define    GEN_INT_STATUS__CRTC_VLINE_STAT_AK                   0x00000002 +#define    GEN_INT_STATUS__CRTC_VSYNC_STAT                      0x00000004 +#define    GEN_INT_STATUS__CRTC_VSYNC_STAT_AK                   0x00000004 +#define    GEN_INT_STATUS__SNAPSHOT_STAT                        0x00000008 +#define    GEN_INT_STATUS__SNAPSHOT_STAT_AK                     0x00000008 +#define    GEN_INT_STATUS__FP_DETECT_STAT                       0x00000010 +#define    GEN_INT_STATUS__FP_DETECT_STAT_AK                    0x00000010 +#define    GEN_INT_STATUS__CRTC2_VLINE_STAT                     0x00000020 +#define    GEN_INT_STATUS__CRTC2_VLINE_STAT_AK                  0x00000020 +#define    GEN_INT_STATUS__CRTC2_VSYNC_STAT                     0x00000040 +#define    GEN_INT_STATUS__CRTC2_VSYNC_STAT_AK                  0x00000040 +#define    GEN_INT_STATUS__SNAPSHOT2_STAT                       0x00000080 +#define    GEN_INT_STATUS__SNAPSHOT2_STAT_AK                    0x00000080 +#define    GEN_INT_STATUS__CAP0_INT_ACTIVE                      0x00000100 +#define    GEN_INT_STATUS__CRTC2_VBLANK_STAT                    0x00000200 +#define    GEN_INT_STATUS__CRTC2_VBLANK_STAT_AK                 0x00000200 +#define    GEN_INT_STATUS__FP2_DETECT_STAT                      0x00000400 +#define    GEN_INT_STATUS__FP2_DETECT_STAT_AK                   0x00000400 +#define    GEN_INT_STATUS__VSYNC_DIFF_OVER_LIMIT_STAT           0x00000800 +#define    GEN_INT_STATUS__VSYNC_DIFF_OVER_LIMIT_STAT_AK        0x00000800 +#define    GEN_INT_STATUS__DMA_VIPH0_INT                        0x00001000 +#define    GEN_INT_STATUS__DMA_VIPH0_INT_AK                     0x00001000 +#define    GEN_INT_STATUS__DMA_VIPH1_INT                        0x00002000 +#define    GEN_INT_STATUS__DMA_VIPH1_INT_AK                     0x00002000 +#define    GEN_INT_STATUS__DMA_VIPH2_INT                        0x00004000 +#define    GEN_INT_STATUS__DMA_VIPH2_INT_AK                     0x00004000 +#define    GEN_INT_STATUS__DMA_VIPH3_INT                        0x00008000 +#define    GEN_INT_STATUS__DMA_VIPH3_INT_AK                     0x00008000 +#define    GEN_INT_STATUS__I2C_INT                              0x00020000 +#define    GEN_INT_STATUS__I2C_INT_AK                           0x00020000 +#define    GEN_INT_STATUS__GUI_IDLE_STAT                        0x00080000 +#define    GEN_INT_STATUS__GUI_IDLE_STAT_AK                     0x00080000 +#define    GEN_INT_STATUS__VIPH_INT                             0x01000000 +#define    GEN_INT_STATUS__SW_INT                               0x02000000 +#define    GEN_INT_STATUS__SW_INT_AK                            0x02000000 +#define    GEN_INT_STATUS__SW_INT_SET                           0x04000000 +#define    GEN_INT_STATUS__GEYSERVILLE_STAT                     0x08000000 +#define    GEN_INT_STATUS__GEYSERVILLE_STAT_AK                  0x08000000 +#define    GEN_INT_STATUS__DVI_I2C_INT_STAT                     0x20000000 +#define    GEN_INT_STATUS__DVI_I2C_INT_AK                       0x20000000 +#define    GEN_INT_STATUS__GUIDMA_STAT                          0x40000000 +#define    GEN_INT_STATUS__GUIDMA_AK                            0x40000000 +#define    GEN_INT_STATUS__VIDDMA_STAT                          0x80000000 +#define    GEN_INT_STATUS__VIDDMA_AK                            0x80000000 +#define    GEN_INT_STATUS__TIMER_INT_STAT                       0x00010000 +#define    GEN_INT_STATUS__TIMER_INT_STAT_AK                    0x00010000 +#define    GEN_INT_STATUS__IDCT_INT_STAT                        0x08000000 +#define    GEN_INT_STATUS__IDCT_INT_STAT_AK                     0x08000000 +#define RB2D_DSTCACHE_MODE                                  0x00003428 +#define    RB2D_DSTCACHE_MODE__DC_BYPASS__MASK                  0x00000003 +#define    RB2D_DSTCACHE_MODE__DC_BYPASS__SHIFT                 0 +#define    RB2D_DSTCACHE_MODE__DC_LINE_SIZE__MASK               0x0000000C +#define    RB2D_DSTCACHE_MODE__DC_LINE_SIZE__SHIFT              2 +#define    RB2D_DSTCACHE_MODE__DC_AUTOFLUSH_ENABLE__MASK        0x00000300 +#define    RB2D_DSTCACHE_MODE__DC_AUTOFLUSH_ENABLE__SHIFT       8 +#define    RB2D_DSTCACHE_MODE__DC_FORCE_RMW                     0x00010000 +#define    RB2D_DSTCACHE_MODE__DC_DISABLE_RI_FILL               0x01000000 +#define    RB2D_DSTCACHE_MODE__DC_DISABLE_RI_READ               0x02000000 +#define    RB2D_DSTCACHE_MODE__DC_AUTOFREE_ENABLE__MASK         0x00000C00 +#define    RB2D_DSTCACHE_MODE__DC_AUTOFREE_ENABLE__SHIFT        10 +#define    RB2D_DSTCACHE_MODE__DC_DISABLE                       0x04000000 +#define    RB2D_DSTCACHE_MODE__DC_DISABLE_IGNORE_PE             0x00020000 +#define RB2D_DSTCACHE_CTLSTAT                               0x0000342C +#define    RB2D_DSTCACHE_CTLSTAT__DC_FLUSH__MASK                0x00000003 +#define    RB2D_DSTCACHE_CTLSTAT__DC_FLUSH__SHIFT               0 +#define    RB2D_DSTCACHE_CTLSTAT__DC_FREE__MASK                 0x0000000C +#define    RB2D_DSTCACHE_CTLSTAT__DC_FREE__SHIFT                2 +#define    RB2D_DSTCACHE_CTLSTAT__DC_BUSY                       0x80000000 +#define RB3D_DSTCACHE_CTLSTAT                               0x0000325C +#define    RB3D_DSTCACHE_CTLSTAT__DC_FLUSH__MASK                0x00000003 +#define    RB3D_DSTCACHE_CTLSTAT__DC_FLUSH__SHIFT               0 +#define    RB3D_DSTCACHE_CTLSTAT__DC_FREE__MASK                 0x0000000C +#define    RB3D_DSTCACHE_CTLSTAT__DC_FREE__SHIFT                2 +#define    RB3D_DSTCACHE_CTLSTAT__DC_BUSY                       0x80000000 +#define RB3D_DSTCACHE_CTLSTAT_R3                            0x00004E4C +#define    RB3D_DSTCACHE_CTLSTAT_R3__DC_FLUSH__MASK             0x00000003 +#define    RB3D_DSTCACHE_CTLSTAT_R3__DC_FLUSH__SHIFT            0 +#define    RB3D_DSTCACHE_CTLSTAT_R3__DC_FREE__MASK              0x0000000C +#define    RB3D_DSTCACHE_CTLSTAT_R3__DC_FREE__SHIFT             2 +#define    RB3D_DSTCACHE_CTLSTAT_R3__DC_FINISH                  0x00000010 +#define RB3D_ZCACHE_CTLSTAT                                 0x00003254 +#define    RB3D_ZCACHE_CTLSTAT__ZC_FLUSH                        0x00000001 +#define    RB3D_ZCACHE_CTLSTAT__ZC_FREE                         0x00000004 +#define    RB3D_ZCACHE_CTLSTAT__ZC_DIRTY                        0x40000000 +#define    RB3D_ZCACHE_CTLSTAT__ZC_BUSY                         0x80000000 +#define RB3D_ZCACHE_CTLSTAT_R3                              0x00004F18 +#define    RB3D_ZCACHE_CTLSTAT_R3__ZC_FLUSH                     0x00000001 +#define    RB3D_ZCACHE_CTLSTAT_R3__ZC_FREE                      0x00000002 +#define    RB3D_ZCACHE_CTLSTAT_R3__ZC_BUSY                      0x80000000 +#define SCRATCH_REG0                                        0x000015E0 +#define    SCRATCH_REG0__SCRATCH_REG0__MASK                     0xFFFFFFFF +#define    SCRATCH_REG0__SCRATCH_REG0__SHIFT                    0 +#define SCRATCH_REG1                                        0x000015E4 +#define    SCRATCH_REG1__SCRATCH_REG1__MASK                     0xFFFFFFFF +#define    SCRATCH_REG1__SCRATCH_REG1__SHIFT                    0 +#define SCRATCH_REG2                                        0x000015E8 +#define    SCRATCH_REG2__SCRATCH_REG2__MASK                     0xFFFFFFFF +#define    SCRATCH_REG2__SCRATCH_REG2__SHIFT                    0 +#define SCRATCH_REG3                                        0x000015EC +#define    SCRATCH_REG3__SCRATCH_REG3__MASK                     0xFFFFFFFF +#define    SCRATCH_REG3__SCRATCH_REG3__SHIFT                    0 +#define SCRATCH_REG4                                        0x000015F0 +#define    SCRATCH_REG4__SCRATCH_REG4__MASK                     0xFFFFFFFF +#define    SCRATCH_REG4__SCRATCH_REG4__SHIFT                    0 +#define SCRATCH_REG5                                        0x000015F4 +#define    SCRATCH_REG5__SCRATCH_REG5__MASK                     0xFFFFFFFF +#define    SCRATCH_REG5__SCRATCH_REG5__SHIFT                    0 +#define SCRATCH_REG6                                        0x000015F8 +#define    SCRATCH_REG6__SCRATCH_REG6__MASK                     0xFFFFFFFF +#define    SCRATCH_REG6__SCRATCH_REG6__SHIFT                    0 +#define SCRATCH_REG7                                        0x000015FC +#define    SCRATCH_REG7__SCRATCH_REG7__MASK                     0xFFFFFFFF +#define    SCRATCH_REG7__SCRATCH_REG7__SHIFT                    0 +#define PCIE_INDEX                                          0x00000030 +#define    PCIE_INDEX__PCIE_INDEX__MASK                         0x000007FF +#define    PCIE_INDEX__PCIE_INDEX__SHIFT                        0 +#define PCIE_DATA                                           0x00000034 +#define    PCIE_DATA__PCIE_DATA__MASK                           0xFFFFFFFF +#define    PCIE_DATA__PCIE_DATA__SHIFT                          0 +#define PCIE_TX_GART_CNTL                                   0x00000010 +#define    PCIE_TX_GART_CNTL__GART_EN                           0x00000001 +#define    PCIE_TX_GART_CNTL__GART_UNMAPPED_ACCESS__MASK        0x00000006 +#define    PCIE_TX_GART_CNTL__GART_UNMAPPED_ACCESS__SHIFT       1 +#define    GART_UNMAPPED_ACCESS__PTHRU                              0x0 +#define    GART_UNMAPPED_ACCESS__CLAMP                              0x1 +#define    GART_UNMAPPED_ACCESS__DISCARD                            0x3 +#define    PCIE_TX_GART_CNTL__GART_MODE__MASK                   0x00000018 +#define    PCIE_TX_GART_CNTL__GART_MODE__SHIFT                  3 +#define    GART_MODE__CACHE_32x128                                  0x0 +#define    GART_MODE__CACHE_8x4x128                                 0x1 +#define    PCIE_TX_GART_CNTL__GART_CHK_RW_VALID_EN              0x00000020 +#define    PCIE_TX_GART_CNTL__GART_RDREQPATH_SEL__MASK          0x00000040 +#define    PCIE_TX_GART_CNTL__GART_RDREQPATH_SEL__SHIFT         6 +#define    GART_RDREQPATH_SEL__HDP                                  0x0 +#define    GART_RDREQPATH_SEL__DRQMC                                0x1 +#define    PCIE_TX_GART_CNTL__GART_INVALIDATE_TLB               0x00000100 +#define PCIE_TX_GART_DISCARD_RD_ADDR_LO                     0x00000011 +#define    PCIE_TX_GART_DISCARD_RD_ADDR_LO__GART_DISCARD_RD_ADDR_LO__MASK 0xFFFFFFFF +#define    PCIE_TX_GART_DISCARD_RD_ADDR_LO__GART_DISCARD_RD_ADDR_LO__SHIFT 0 +#define PCIE_TX_GART_DISCARD_RD_ADDR_HI                     0x00000012 +#define    PCIE_TX_GART_DISCARD_RD_ADDR_HI__GART_DISCARD_RD_ADDR_HI__MASK 0x000000FF +#define    PCIE_TX_GART_DISCARD_RD_ADDR_HI__GART_DISCARD_RD_ADDR_HI__SHIFT 0 +#define PCIE_TX_GART_BASE                                   0x00000013 +#define    PCIE_TX_GART_BASE__GART_BASE__MASK                   0xFFFFFFFF +#define    PCIE_TX_GART_BASE__GART_BASE__SHIFT                  0 +#define PCIE_TX_GART_START_LO                               0x00000014 +#define    PCIE_TX_GART_START_LO__GART_START_LO__MASK           0xFFFFFFFF +#define    PCIE_TX_GART_START_LO__GART_START_LO__SHIFT          0 +#define PCIE_TX_GART_START_HI                               0x00000015 +#define    PCIE_TX_GART_START_HI__GART_START_HI__MASK           0x000000FF +#define    PCIE_TX_GART_START_HI__GART_START_HI__SHIFT          0 +#define PCIE_TX_GART_END_LO                                 0x00000016 +#define    PCIE_TX_GART_END_LO__GART_END_LO__MASK               0xFFFFFFFF +#define    PCIE_TX_GART_END_LO__GART_END_LO__SHIFT              0 +#define PCIE_TX_GART_END_HI                                 0x00000017 +#define    PCIE_TX_GART_END_HI__GART_END_HI__MASK               0x000000FF +#define    PCIE_TX_GART_END_HI__GART_END_HI__SHIFT              0 +#define PCIE_TX_GART_ERROR                                  0x00000018 +#define    PCIE_TX_GART_ERROR__GART_UNMAPPED                    0x00000002 +#define    PCIE_TX_GART_ERROR__GART_INVALID_READ                0x00000004 +#define    PCIE_TX_GART_ERROR__GART_INVALID_WRITE               0x00000008 +#define    PCIE_TX_GART_ERROR__GART_INVALID_ADDR__MASK          0xFFFFFFF0 +#define    PCIE_TX_GART_ERROR__GART_INVALID_ADDR__SHIFT         4 +#define CP_RB_CNTL                                          0x00000704 +#define    CP_RB_CNTL__RB_BUFSZ__MASK                           0x0000003F +#define    CP_RB_CNTL__RB_BUFSZ__SHIFT                          0 +#define    CP_RB_CNTL__RB_BLKSZ__MASK                           0x00003F00 +#define    CP_RB_CNTL__RB_BLKSZ__SHIFT                          8 +#define    CP_RB_CNTL__BUF_SWAP__MASK                           0x00030000 +#define    CP_RB_CNTL__BUF_SWAP__SHIFT                          16 +#define    CP_RB_CNTL__MAX_FETCH__MASK                          0x000C0000 +#define    CP_RB_CNTL__MAX_FETCH__SHIFT                         18 +#define    CP_RB_CNTL__RB_NO_UPDATE                             0x08000000 +#define    CP_RB_CNTL__RB_RPTR_WR_ENA                           0x80000000 +#define CP_RB_BASE                                          0x00000700 +#define    CP_RB_BASE__RB_BASE__MASK                            0xFFFFFFFC +#define    CP_RB_BASE__RB_BASE__SHIFT                           2 +#define CP_RB_RPTR_ADDR                                     0x0000070C +#define    CP_RB_RPTR_ADDR__RB_RPTR_SWAP__MASK                  0x00000003 +#define    CP_RB_RPTR_ADDR__RB_RPTR_SWAP__SHIFT                 0 +#define    CP_RB_RPTR_ADDR__RB_RPTR_ADDR__MASK                  0xFFFFFFFC +#define    CP_RB_RPTR_ADDR__RB_RPTR_ADDR__SHIFT                 2 +#define CP_RB_RPTR                                          0x00000710 +#define    CP_RB_RPTR__RB_RPTR__MASK                            0x007FFFFF +#define    CP_RB_RPTR__RB_RPTR__SHIFT                           0 +#define CP_RB_RPTR_WR                                       0x0000071C +#define    CP_RB_RPTR_WR__RB_RPTR_WR__MASK                      0x007FFFFF +#define    CP_RB_RPTR_WR__RB_RPTR_WR__SHIFT                     0 +#define CP_RB_WPTR                                          0x00000714 +#define    CP_RB_WPTR__RB_WPTR__MASK                            0x007FFFFF +#define    CP_RB_WPTR__RB_WPTR__SHIFT                           0 +#define CP_RB_WPTR_DELAY                                    0x00000718 +#define    CP_RB_WPTR_DELAY__PRE_WRITE_TIMER__MASK              0x0FFFFFFF +#define    CP_RB_WPTR_DELAY__PRE_WRITE_TIMER__SHIFT             0 +#define    CP_RB_WPTR_DELAY__PRE_WRITE_LIMIT__MASK              0xF0000000 +#define    CP_RB_WPTR_DELAY__PRE_WRITE_LIMIT__SHIFT             28 +#define SCRATCH_UMSK                                        0x00000770 +#define    SCRATCH_UMSK__SCRATCH_UMSK__MASK                     0x0000003F +#define    SCRATCH_UMSK__SCRATCH_UMSK__SHIFT                    0 +#define    SCRATCH_UMSK__SCRATCH_SWAP__MASK                     0x00030000 +#define    SCRATCH_UMSK__SCRATCH_SWAP__SHIFT                    16 +#define    SCRATCH_UMSK__SCRATCH_UMSK_R2__MASK                  0x000000FF +#define    SCRATCH_UMSK__SCRATCH_UMSK_R2__SHIFT                 0 +#define SCRATCH_ADDR                                        0x00000774 +#define    SCRATCH_ADDR__SCRATCH_ADDR__MASK                     0xFFFFFFE0 +#define    SCRATCH_ADDR__SCRATCH_ADDR__SHIFT                    5 +#define CP_ME_RAM_ADDR                                      0x000007D4 +#define    CP_ME_RAM_ADDR__ME_RAM_ADDR__MASK                    0x000000FF +#define    CP_ME_RAM_ADDR__ME_RAM_ADDR__SHIFT                   0 +#define CP_ME_RAM_DATAH                                     0x000007DC +#define    CP_ME_RAM_DATAH__ME_RAM_DATAH__MASK                  0x0000003F +#define    CP_ME_RAM_DATAH__ME_RAM_DATAH__SHIFT                 0 +#define    CP_ME_RAM_DATAH__ME_RAM_DATAH_R3__MASK               0x000000FF +#define    CP_ME_RAM_DATAH__ME_RAM_DATAH_R3__SHIFT              0 +#define CP_ME_RAM_DATAL                                     0x000007E0 +#define    CP_ME_RAM_DATAL__ME_RAM_DATAL__MASK                  0xFFFFFFFF +#define    CP_ME_RAM_DATAL__ME_RAM_DATAL__SHIFT                 0 +#define CP_CSQ_CNTL                                         0x00000740 +#define    CP_CSQ_CNTL__CSQ_CNT_PRIMARY__MASK                   0x000000FF +#define    CP_CSQ_CNTL__CSQ_CNT_PRIMARY__SHIFT                  0 +#define    CP_CSQ_CNTL__CSQ_CNT_INDIRECT__MASK                  0x0000FF00 +#define    CP_CSQ_CNTL__CSQ_CNT_INDIRECT__SHIFT                 8 +#define    CP_CSQ_CNTL__CSQ_MODE__MASK                          0xF0000000 +#define    CP_CSQ_CNTL__CSQ_MODE__SHIFT                         28 +#define    CSQ_MODE__CSQ_PRIDIS_INDDIS                              0x0 +#define    CSQ_MODE__CSQ_PRIPIO_INDDIS                              0x1 +#define    CSQ_MODE__CSQ_PRIBM_INDDIS                               0x2 +#define    CSQ_MODE__CSQ_PRIPIO_INDBM                               0x3 +#define    CSQ_MODE__CSQ_PRIBM_INDBM                                0x4 +#define    CSQ_MODE__CSQ_PRIPIO_INDPIO                              0xF +#define    CP_CSQ_CNTL__CSQ_CNT_PRIMARY_R2__MASK                0x000001FF +#define    CP_CSQ_CNTL__CSQ_CNT_PRIMARY_R2__SHIFT               0 +#define    CP_CSQ_CNTL__CSQ_CNT_INDIRECT_R2__MASK               0x0003FE00 +#define    CP_CSQ_CNTL__CSQ_CNT_INDIRECT_R2__SHIFT              9 +#define    CP_CSQ_CNTL__CSQ_CNT_INDIRECT2__MASK                 0x07FC0000 +#define    CP_CSQ_CNTL__CSQ_CNT_INDIRECT2__SHIFT                18 +#define CRTC_GEN_CNTL                                       0x00000050 +#define    CRTC_GEN_CNTL__CRTC_DBL_SCAN_EN                      0x00000001 +#define    CRTC_GEN_CNTL__CRTC_INTERLACE_EN                     0x00000002 +#define    CRTC_GEN_CNTL__CRTC_C_SYNC_EN                        0x00000010 +#define    CRTC_GEN_CNTL__CRTC_PIX_WIDTH__MASK                  0x00000F00 +#define    CRTC_GEN_CNTL__CRTC_PIX_WIDTH__SHIFT                 8 +#define    CRTC_PIX_WIDTH__4BPP                                     0x100 +#define    CRTC_PIX_WIDTH__8BPP                                     0x200 +#define    CRTC_PIX_WIDTH__15BPP                                    0x300 +#define    CRTC_PIX_WIDTH__16BPP                                    0x400 +#define    CRTC_PIX_WIDTH__24BPP                                    0x500 +#define    CRTC_PIX_WIDTH__34BPP                                    0x600 +#define    CRTC_PIX_WIDTH__16BPP_4444                               0x700 +#define    CRTC_PIX_WIDTH__16BPP_88                                 0x800 +#define    CRTC_GEN_CNTL__CRTC_ICON_EN                          0x00008000 +#define    CRTC_GEN_CNTL__CRTC_CUR_EN                           0x00010000 +#define    CRTC_GEN_CNTL__CRTC_VSTAT_MODE__MASK                 0x00060000 +#define    CRTC_GEN_CNTL__CRTC_VSTAT_MODE__SHIFT                17 +#define    CRTC_GEN_CNTL__CRTC_CUR_MODE__MASK                   0x00700000 +#define    CRTC_GEN_CNTL__CRTC_CUR_MODE__SHIFT                  20 +#define    CRTC_CUR_MODE__PREMULTI_ALPHA                            0x2 +#define    CRTC_CUR_MODE__COLOR24BPP                                0x1 +#define    CRTC_GEN_CNTL__CRTC_EXT_DISP_EN                      0x01000000 +#define    CRTC_GEN_CNTL__CRTC_EN                               0x02000000 +#define    CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B                    0x04000000 +#define    CRTC_GEN_CNTL__CRTC_MODE9_COLOR_ORDER                0x00001000 +#define CRTC_EXT_CNTL                                       0x00000054 +#define    CRTC_EXT_CNTL__CRTC_VGA_XOVERSCAN                    0x00000001 +#define    CRTC_EXT_CNTL__VGA_BLINK_RATE__MASK                  0x00000006 +#define    CRTC_EXT_CNTL__VGA_BLINK_RATE__SHIFT                 1 +#define    CRTC_EXT_CNTL__VGA_ATI_LINEAR                        0x00000008 +#define    CRTC_EXT_CNTL__VGA_128KAP_PAGING                     0x00000010 +#define    CRTC_EXT_CNTL__VGA_TEXT_132                          0x00000020 +#define    CRTC_EXT_CNTL__VGA_XCRT_CNT_EN                       0x00000040 +#define    CRTC_EXT_CNTL__CRTC_HSYNC_DIS                        0x00000100 +#define    CRTC_EXT_CNTL__CRTC_VSYNC_DIS                        0x00000200 +#define    CRTC_EXT_CNTL__CRTC_DISPLAY_DIS                      0x00000400 +#define    CRTC_EXT_CNTL__CRTC_SYNC_TRISTATE                    0x00000800 +#define    CRTC_EXT_CNTL__CRTC_HSYNC_TRISTATE                   0x00001000 +#define    CRTC_EXT_CNTL__CRTC_VSYNC_TRISTATE                   0x00002000 +#define    CRTC_EXT_CNTL__CRT_ON                                0x00008000 +#define    CRTC_EXT_CNTL__VGA_CUR_B_TEST                        0x00020000 +#define    CRTC_EXT_CNTL__VGA_PACK_DIS                          0x00040000 +#define    CRTC_EXT_CNTL__VGA_MEM_PS_EN                         0x00080000 +#define    CRTC_EXT_CNTL__VCRTC_IDX_MASTER__MASK                0x7F000000 +#define    CRTC_EXT_CNTL__VCRTC_IDX_MASTER__SHIFT               24 +#define CRTC_H_TOTAL_DISP                                   0x00000200 +#define    CRTC_H_TOTAL_DISP__CRTC_H_TOTAL__MASK                0x000003FF +#define    CRTC_H_TOTAL_DISP__CRTC_H_TOTAL__SHIFT               0 +#define    CRTC_H_TOTAL_DISP__CRTC_H_DISP__MASK                 0x01FF0000 +#define    CRTC_H_TOTAL_DISP__CRTC_H_DISP__SHIFT                16 +#define CRTC_H_SYNC_STRT_WID                                0x00000204 +#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_STRT_PIX__MASK     0x00000007 +#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_STRT_PIX__SHIFT    0 +#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_STRT_CHAR__MASK    0x00001FF8 +#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_STRT_CHAR__SHIFT   3 +#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_WID__MASK          0x003F0000 +#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_WID__SHIFT         16 +#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_POL                0x00800000 +#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_SKEW_TUNE__MASK    0x07000000 +#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_SKEW_TUNE__SHIFT   24 +#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_SKEW_TUNE_MODE     0x10000000 +#define CRTC_V_TOTAL_DISP                                   0x00000208 +#define    CRTC_V_TOTAL_DISP__CRTC_V_TOTAL__MASK                0x00000FFF +#define    CRTC_V_TOTAL_DISP__CRTC_V_TOTAL__SHIFT               0 +#define    CRTC_V_TOTAL_DISP__CRTC_V_DISP__MASK                 0x0FFF0000 +#define    CRTC_V_TOTAL_DISP__CRTC_V_DISP__SHIFT                16 +#define CRTC_V_SYNC_STRT_WID                                0x0000020C +#define    CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_STRT__MASK         0x00000FFF +#define    CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_STRT__SHIFT        0 +#define    CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_WID__MASK          0x001F0000 +#define    CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_WID__SHIFT         16 +#define    CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_POL                0x00800000 +#define CRTC_OFFSET                                         0x00000224 +#define    CRTC_OFFSET__CRTC_OFFSET__MASK                       0x07FFFFFF +#define    CRTC_OFFSET__CRTC_OFFSET__SHIFT                      0 +#define    CRTC_OFFSET__CRTC_GUI_TRIG_OFFSET                    0x40000000 +#define    CRTC_OFFSET__CRTC_OFFSET_LOCK                        0x80000000 +#define    CRTC_OFFSET__CRTC_OFFSET_R3__MASK                    0x0FFFFFFF +#define    CRTC_OFFSET__CRTC_OFFSET_R3__SHIFT                   0 +#define CRTC_OFFSET_CNTL                                    0x00000228 +#define    CRTC_OFFSET_CNTL__CRTC_TILE_LINE__MASK               0x0000000F +#define    CRTC_OFFSET_CNTL__CRTC_TILE_LINE__SHIFT              0 +#define    CRTC_OFFSET_CNTL__CRTC_TILE_LINE_RIGHT__MASK         0x000000F0 +#define    CRTC_OFFSET_CNTL__CRTC_TILE_LINE_RIGHT__SHIFT        4 +#define    CRTC_OFFSET_CNTL__CRTC_TILE_EN_RIGHT                 0x00004000 +#define    CRTC_OFFSET_CNTL__CRTC_TILE_EN                       0x00008000 +#define    CRTC_OFFSET_CNTL__CRTC_OFFSET_FLIP_CNTL              0x00010000 +#define    CRTC_OFFSET_CNTL__CRTC_STEREO_OFFSET_EN              0x00020000 +#define    CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_EN__MASK          0x000C0000 +#define    CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_EN__SHIFT         18 +#define    CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_OUT_EN            0x00100000 +#define    CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC                   0x00200000 +#define    CRTC_OFFSET_CNTL__CRTC_GUI_TRIG_OFFSET_LEFT_EN       0x10000000 +#define    CRTC_OFFSET_CNTL__CRTC_GUI_TRIG_OFFSET_RIGHT_EN      0x20000000 +#define    CRTC_OFFSET_CNTL__CRTC_GUI_TRIG_OFFSET               0x40000000 +#define    CRTC_OFFSET_CNTL__CRTC_OFFSET_LOCK                   0x80000000 +#define    CRTC_OFFSET_CNTL__CRTC_X_Y_MODE_EN_RIGHT             0x00000040 +#define    CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_BUFFER_MODE_RIGHT__MASK 0x00000180 +#define    CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_BUFFER_MODE_RIGHT__SHIFT 7 +#define    CRTC_OFFSET_CNTL__CRTC_X_Y_MODE_EN                   0x00000200 +#define    CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_BUFFER_MODE__MASK  0x00000C00 +#define    CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_BUFFER_MODE__SHIFT 10 +#define    CRTC_MICRO_TILE_BUFFER_MODE__AUTO                        0x0 +#define    CRTC_MICRO_TILE_BUFFER_MODE__SLINE                       0x1 +#define    CRTC_MICRO_TILE_BUFFER_MODE__DLINE                       0x2 +#define    CRTC_MICRO_TILE_BUFFER_MODE__DIS                         0x3 +#define    CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_EN_RIGHT           0x00001000 +#define    CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_EN                 0x00002000 +#define    CRTC_OFFSET_CNTL__CRTC_MACRO_TILE_EN_RIGHT           0x00004000 +#define    CRTC_OFFSET_CNTL__CRTC_MACRO_TILE_EN                 0x00008000 +#define CRTC_PITCH                                          0x0000022C +#define    CRTC_PITCH__CRTC_PITCH__MASK                         0x000007FF +#define    CRTC_PITCH__CRTC_PITCH__SHIFT                        0 +#define    CRTC_PITCH__CRTC_PITCH_RIGHT__MASK                   0x07FF0000 +#define    CRTC_PITCH__CRTC_PITCH_RIGHT__SHIFT                  16 +#define CRTC_MORE_CNTL                                      0x0000027C +#define    CRTC_MORE_CNTL__CRTC_HORZ_BLANK_MODE_SEL             0x00000001 +#define    CRTC_MORE_CNTL__CRTC_VERT_BLANK_MODE_SEL             0x00000002 +#define    CRTC_MORE_CNTL__CRTC_AUTO_HORZ_CENTER_EN             0x00000004 +#define    CRTC_MORE_CNTL__CRTC_AUTO_VERT_CENTER_EN             0x00000008 +#define    CRTC_MORE_CNTL__CRTC_H_CUTOFF_ACTIVE_EN              0x00000010 +#define    CRTC_MORE_CNTL__CRTC_V_CUTOFF_ACTIVE_EN              0x00000020 +#define    CRTC_MORE_CNTL__FORCE_H_EVEN_PIXEL_COUNT             0x00000040 +#define    CRTC_MORE_CNTL__RMX_H_FILT_COEFFICIENT__MASK         0x07000000 +#define    CRTC_MORE_CNTL__RMX_H_FILT_COEFFICIENT__SHIFT        24 +#define    CRTC_MORE_CNTL__RMX_H_FILTER_EN                      0x08000000 +#define    CRTC_MORE_CNTL__RMX_V_FILT_COEFFICIENT__MASK         0x70000000 +#define    CRTC_MORE_CNTL__RMX_V_FILT_COEFFICIENT__SHIFT        28 +#define    CRTC_MORE_CNTL__RMX_V_FILTER_EN                      0x80000000 +#define    CRTC_MORE_CNTL__DSP_RST_HCOUNT                       0x00000100 +#define    CRTC_MORE_CNTL__DSP_RST_VCOUNT                       0x00000200 +#define    CRTC_MORE_CNTL__HCOUNT_RST_POS                       0x00000400 +#define    CRTC_MORE_CNTL__VCOUNT_RST_POS                       0x00000800 +#define    CRTC_MORE_CNTL__CRTC_FIX_VSYNC_EDGE_POSITION_EN      0x00001000 +#define CRTC_TILE_X0_Y0                                     0x00000350 +#define    CRTC_TILE_X0_Y0__CRTC_TILE_X0__MASK                  0x00000FFF +#define    CRTC_TILE_X0_Y0__CRTC_TILE_X0__SHIFT                 0 +#define    CRTC_TILE_X0_Y0__CRTC_TILE_Y0__MASK                  0x0FFF0000 +#define    CRTC_TILE_X0_Y0__CRTC_TILE_Y0__SHIFT                 16 +#define    CRTC_TILE_X0_Y0__CRTC_GUI_TRIG_OFFSET                0x40000000 +#define    CRTC_TILE_X0_Y0__CRTC_OFFSET_LOCK                    0x80000000 +#define DAC_CNTL                                            0x00000058 +#define    DAC_CNTL__DAC_RANGE_CNTL__MASK                       0x00000003 +#define    DAC_CNTL__DAC_RANGE_CNTL__SHIFT                      0 +#define    DAC_RANGE_CNTL__PS2                                      0x2 +#define    DAC_RANGE_CNTL__YPbPr                                    0x3 +#define    DAC_CNTL__DAC_BLANKING                               0x00000004 +#define    DAC_CNTL__DAC_CMP_EN                                 0x00000008 +#define    DAC_CNTL__DAC_CMP_OUT_R                              0x00000010 +#define    DAC_CNTL__DAC_CMP_OUT_G                              0x00000020 +#define    DAC_CNTL__DAC_CMP_OUT_B                              0x00000040 +#define    DAC_CNTL__DAC_CMP_OUTPUT                             0x00000080 +#define    DAC_CNTL__DAC_8BIT_EN                                0x00000100 +#define    DAC_CNTL__DAC_4BPP_PIX_ORDER                         0x00000200 +#define    DAC_CNTL__DAC_TVO_EN                                 0x00000400 +#define    DAC_CNTL__DAC_VGA_ADR_EN                             0x00002000 +#define    DAC_CNTL__DAC_EXPAND_MODE                            0x00004000 +#define    DAC_CNTL__DAC_PDWN                                   0x00008000 +#define    DAC_CNTL__CRT_SENSE                                  0x00010000 +#define    DAC_CNTL__CRT_DETECTION_ON                           0x00020000 +#define    DAC_CNTL__DAC_CRC_CONT_EN                            0x00040000 +#define    DAC_CNTL__DAC_CRC_EN                                 0x00080000 +#define    DAC_CNTL__DAC_CRC_FIELD                              0x00100000 +#define    DAC_CNTL__DAC_LUT_COUNTER_LIMIT__MASK                0x00600000 +#define    DAC_CNTL__DAC_LUT_COUNTER_LIMIT__SHIFT               21 +#define    DAC_CNTL__DAC_LUT_READ_SEL                           0x00800000 +#define    DAC_CNTL__DAC__MASK                                  0xFF000000 +#define    DAC_CNTL__DAC__SHIFT                                 24 +#define    DAC_CNTL__DAC_CRC_BLANKb_ONLY                        0x00000800 +#define DAC_CNTL2                                           0x0000007C +#define    DAC_CNTL2__DAC_CLK_SEL                               0x00000001 +#define    DAC_CNTL2__DAC2_CLK_SEL                              0x00000002 +#define    DAC_CNTL2__PALETTE_ACCESS_CNTL                       0x00000020 +#define    DAC_CNTL2__DAC2_CMP_EN                               0x00000080 +#define    DAC_CNTL2__DAC2_CMP_OUT_R                            0x00000100 +#define    DAC_CNTL2__DAC2_CMP_OUT_G                            0x00000200 +#define    DAC_CNTL2__DAC2_CMP_OUT_B                            0x00000400 +#define    DAC_CNTL2__DAC2_CMP_OUTPUT                           0x00000800 +#define    DAC_CNTL2__DAC2_EXPAND_MODE                          0x00004000 +#define    DAC_CNTL2__CRT2_SENSE                                0x00010000 +#define    DAC_CNTL2__CRT2_DETECTION_ON                         0x00020000 +#define    DAC_CNTL2__DAC_CRC2_CONT_EN                          0x00040000 +#define    DAC_CNTL2__DAC_CRC2_EN                               0x00080000 +#define    DAC_CNTL2__DAC_CRC2_FIELD                            0x00100000 +#define    DAC_CNTL2__DAC2_LUT_COUNTER_LIMIT__MASK              0x00600000 +#define    DAC_CNTL2__DAC2_LUT_COUNTER_LIMIT__SHIFT             21 +#define    DAC_CNTL2__PALETTE_AUTOFILL_PRIMARY_W                0x00000800 +#define    DAC_CNTL2__PALETTE_AUTOFILL_PRIMARY_R                0x00000800 +#define    DAC_CNTL2__PALETTE_AUTOFILL_SECONDARY_W              0x00001000 +#define    DAC_CNTL2__PALETTE_AUTOFILL_SECONDARY_R              0x00001000 +#define    DAC_CNTL2__DAC2_CMP_EN_R3                            0x00000040 +#define    DAC_CNTL2__DAC2_CMP_OUT_R_R3                         0x00000080 +#define    DAC_CNTL2__DAC2_CMP_OUT_G_R3                         0x00000100 +#define    DAC_CNTL2__DAC2_CMP_OUT_B_R3                         0x00000200 +#define    DAC_CNTL2__DAC2_CMP_OUTPUT_R3                        0x00000400 +#define    DAC_CNTL2__DAC_CRC2_BLANKb_ONLY                      0x00020000 +#define DAC_EXT_CNTL                                        0x00000280 +#define    DAC_EXT_CNTL__DAC2_FORCE_BLANK_OFF_EN                0x00000001 +#define    DAC_EXT_CNTL__DAC2_FORCE_DATA_EN                     0x00000002 +#define    DAC_EXT_CNTL__DAC_FORCE_BLANK_OFF_EN                 0x00000010 +#define    DAC_EXT_CNTL__DAC_FORCE_DATA_EN                      0x00000020 +#define    DAC_EXT_CNTL__DAC_FORCE_DATA_SEL__MASK               0x000000C0 +#define    DAC_EXT_CNTL__DAC_FORCE_DATA_SEL__SHIFT              6 +#define    DAC_EXT_CNTL__DAC_FORCE_DATA__MASK                   0x0003FF00 +#define    DAC_EXT_CNTL__DAC_FORCE_DATA__SHIFT                  8 +#define DISP_MISC_CNTL                                      0x00000D00 +#define    DISP_MISC_CNTL__SOFT_RESET_GRPH_PP                   0x00000001 +#define    DISP_MISC_CNTL__SOFT_RESET_SUBPIC_PP                 0x00000002 +#define    DISP_MISC_CNTL__SOFT_RESET_OV0_PP                    0x00000004 +#define    DISP_MISC_CNTL__SOFT_RESET_GRPH_SCLK                 0x00000010 +#define    DISP_MISC_CNTL__SOFT_RESET_SUBPIC_SCLK               0x00000020 +#define    DISP_MISC_CNTL__SOFT_RESET_OV0_SCLK                  0x00000040 +#define    DISP_MISC_CNTL__SYNC_STRENGTH__MASK                  0x00000300 +#define    DISP_MISC_CNTL__SYNC_STRENGTH__SHIFT                 8 +#define    DISP_MISC_CNTL__SYNC_PAD_FLOP_EN                     0x00000400 +#define    DISP_MISC_CNTL__SOFT_RESET_GRPH2_PP                  0x00001000 +#define    DISP_MISC_CNTL__SOFT_RESET_GRPH2_SCLK                0x00008000 +#define    DISP_MISC_CNTL__SOFT_RESET_LVDS                      0x00010000 +#define    DISP_MISC_CNTL__SOFT_RESET_TMDS                      0x00020000 +#define    DISP_MISC_CNTL__SOFT_RESET_DIG_TMDS                  0x00040000 +#define    DISP_MISC_CNTL__SOFT_RESET_TV                        0x00080000 +#define    DISP_MISC_CNTL__PALETTE2_MEM_RD_MARGIN__MASK         0x00F00000 +#define    DISP_MISC_CNTL__PALETTE2_MEM_RD_MARGIN__SHIFT        20 +#define    DISP_MISC_CNTL__PALETTE_MEM_RD_MARGIN__MASK          0x0F000000 +#define    DISP_MISC_CNTL__PALETTE_MEM_RD_MARGIN__SHIFT         24 +#define    DISP_MISC_CNTL__RMX_BUF_MEM_RD_MARGIN__MASK          0xF0000000 +#define    DISP_MISC_CNTL__RMX_BUF_MEM_RD_MARGIN__SHIFT         28 +#define    DISP_MISC_CNTL__SOFT_RESET_DVO                       0x00040000 +#define    DISP_MISC_CNTL__SOFT_RESET_TV_R2                     0x00000800 +#define DAC_MACRO_CNTL                                      0x00000D04 +#define    DAC_MACRO_CNTL__DAC_WHITE_CNTL__MASK                 0x0000000F +#define    DAC_MACRO_CNTL__DAC_WHITE_CNTL__SHIFT                0 +#define    DAC_MACRO_CNTL__DAC_BG_ADJ__MASK                     0x00000F00 +#define    DAC_MACRO_CNTL__DAC_BG_ADJ__SHIFT                    8 +#define    DAC_MACRO_CNTL__DAC_PDWN_R                           0x00010000 +#define    DAC_MACRO_CNTL__DAC_PDWN_G                           0x00020000 +#define    DAC_MACRO_CNTL__DAC_PDWN_B                           0x00040000 +#define DISP_PWR_MAN                                        0x00000D08 +#define    DISP_PWR_MAN__DISP_PWR_MAN_D3_CRTC_EN                0x00000001 +#define    DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN              0x00000010 +#define    DISP_PWR_MAN__DISP_PWR_MAN_DPMS__MASK                0x00000300 +#define    DISP_PWR_MAN__DISP_PWR_MAN_DPMS__SHIFT               8 +#define    DISP_PWR_MAN_DPMS__ON                                    0x0 +#define    DISP_PWR_MAN_DPMS__STANDBY                               0x1 +#define    DISP_PWR_MAN_DPMS__SUSPEND                               0x2 +#define    DISP_PWR_MAN_DPMS__OFF                                   0x3 +#define    DISP_PWR_MAN__DISP_D3_RST                            0x00010000 +#define    DISP_PWR_MAN__DISP_D3_REG_RST                        0x00020000 +#define    DISP_PWR_MAN__DISP_D3_GRPH_RST                       0x00040000 +#define    DISP_PWR_MAN__DISP_D3_SUBPIC_RST                     0x00080000 +#define    DISP_PWR_MAN__DISP_D3_OV0_RST                        0x00100000 +#define    DISP_PWR_MAN__DISP_D1D2_GRPH_RST                     0x00200000 +#define    DISP_PWR_MAN__DISP_D1D2_SUBPIC_RST                   0x00400000 +#define    DISP_PWR_MAN__DISP_D1D2_OV0_RST                      0x00800000 +#define    DISP_PWR_MAN__DIG_TMDS_ENABLE_RST                    0x01000000 +#define    DISP_PWR_MAN__TV_ENABLE_RST                          0x02000000 +#define    DISP_PWR_MAN__AUTO_PWRUP_EN                          0x04000000 +#define    DISP_PWR_MAN__DISP_DVO_ENABLE_RST                    0x01000000 +#define DISP_MERGE_CNTL                                     0x00000D60 +#define    DISP_MERGE_CNTL__DISP_ALPHA_MODE__MASK               0x00000003 +#define    DISP_MERGE_CNTL__DISP_ALPHA_MODE__SHIFT              0 +#define    DISP_MERGE_CNTL__DISP_ALPHA_INV                      0x00000004 +#define    DISP_MERGE_CNTL__DISP_ALPHA_PREMULT                  0x00000008 +#define    DISP_MERGE_CNTL__DISP_RGB_OFFSET_EN                  0x00000100 +#define    DISP_MERGE_CNTL__DISP_LIN_TRANS_BYPASS               0x00000200 +#define    DISP_MERGE_CNTL__DISP_GRPH_ALPHA__MASK               0x00FF0000 +#define    DISP_MERGE_CNTL__DISP_GRPH_ALPHA__SHIFT              16 +#define    DISP_MERGE_CNTL__DISP_OV0_ALPHA__MASK                0xFF000000 +#define    DISP_MERGE_CNTL__DISP_OV0_ALPHA__SHIFT               24 +#define DISP_OUTPUT_CNTL                                    0x00000D64 +#define    DISP_OUTPUT_CNTL__DISP_DAC_SOURCE__MASK              0x00000003 +#define    DISP_OUTPUT_CNTL__DISP_DAC_SOURCE__SHIFT             0 +#define    DISP_DAC_SOURCE__YPbPr                                   0x3 +#define    DISP_DAC_SOURCE__PRIMARYCRTC                             0x0 +#define    DISP_DAC_SOURCE__SECONDARYCRTC                           0x1 +#define    DISP_DAC_SOURCE__RMX                                     0x2 +#define    DISP_OUTPUT_CNTL__DISP_TRANS_MATRIX_SEL__MASK        0x00000030 +#define    DISP_OUTPUT_CNTL__DISP_TRANS_MATRIX_SEL__SHIFT       4 +#define    DISP_OUTPUT_CNTL__DISP_RMX_SOURCE                    0x00000100 +#define    DISP_OUTPUT_CNTL__DISP_RMX_HTAP_SEL                  0x00000200 +#define    DISP_OUTPUT_CNTL__DISP_RMX_DITH_EN                   0x00000400 +#define    DISP_OUTPUT_CNTL__DISP_TV_SOURCE                     0x00010000 +#define    DISP_OUTPUT_CNTL__DISP_TV_MODE__MASK                 0x00060000 +#define    DISP_OUTPUT_CNTL__DISP_TV_MODE__SHIFT                17 +#define    DISP_OUTPUT_CNTL__DISP_TV_YG_DITH_EN                 0x00080000 +#define    DISP_OUTPUT_CNTL__DISP_TV_CbB_CrR_DITH_EN            0x00100000 +#define    DISP_OUTPUT_CNTL__DISP_TV_BIT_WIDTH                  0x00200000 +#define    DISP_OUTPUT_CNTL__DISP_TV_SYNC_MODE__MASK            0x00C00000 +#define    DISP_OUTPUT_CNTL__DISP_TV_SYNC_MODE__SHIFT           22 +#define    DISP_OUTPUT_CNTL__DISP_TV_SYNC_FORCE                 0x01000000 +#define    DISP_OUTPUT_CNTL__DISP_TV_SYNC_COLOR__MASK           0x06000000 +#define    DISP_OUTPUT_CNTL__DISP_TV_SYNC_COLOR__SHIFT          25 +#define    DISP_OUTPUT_CNTL__DISP_TV_EVEN_FLAG_CNTL__MASK       0x18000000 +#define    DISP_OUTPUT_CNTL__DISP_TV_EVEN_FLAG_CNTL__SHIFT      27 +#define    DISP_OUTPUT_CNTL__DISP_TV_SYNC_STATUS                0x20000000 +#define    DISP_OUTPUT_CNTL__DISP_TV_H_DOWNSCALE                0x40000000 +#define    DISP_OUTPUT_CNTL__DISP_TRANS_SOURCE__MASK            0x00003000 +#define    DISP_OUTPUT_CNTL__DISP_TRANS_SOURCE__SHIFT           12 +#define    DISP_TRANS_SOURCE__PRIMARYCRTC                           0x0 +#define    DISP_TRANS_SOURCE__SECONDARYCRTC                         0x1 +#define    DISP_TRANS_SOURCE__RMX                                   0x2 +#define    DISP_OUTPUT_CNTL__DISP_TVDAC_SOURCE__MASK            0x0000000C +#define    DISP_OUTPUT_CNTL__DISP_TVDAC_SOURCE__SHIFT           2 +#define    DISP_TVDAC_SOURCE__PRIMARYCRTC                           0x0 +#define    DISP_TVDAC_SOURCE__SECONDARYCRTC                         0x1 +#define    DISP_TVDAC_SOURCE__RMX                                   0x2 +#define    DISP_TVDAC_SOURCE__YPbPr                                 0x3 +#define DISP2_MERGE_CNTL                                    0x00000D68 +#define    DISP2_MERGE_CNTL__DISP2_RGB_OFFSET_EN                0x00000100 +#define DAC_EMBEDDED_SYNC_CNTL                              0x00000DC0 +#define    DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_SYNC_EN_Y_G        0x00000001 +#define    DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_SYNC_EN_Cb_B       0x00000002 +#define    DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_SYNC_EN_Cr_R       0x00000004 +#define    DAC_EMBEDDED_SYNC_CNTL__DAC_TRILEVEL_SYNC_EN         0x00000008 +#define    DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_VSYNC_EN_Y_G       0x00000010 +#define    DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_VSYNC_EN_CbCr_BR   0x00000020 +#define    DAC_EMBEDDED_SYNC_CNTL__DAC_HSYNC_WID_LSB__MASK      0x00070000 +#define    DAC_EMBEDDED_SYNC_CNTL__DAC_HSYNC_WID_LSB__SHIFT     16 +#define DAC_BROAD_PULSE                                     0x00000DC4 +#define    DAC_BROAD_PULSE__DAC_BROAD_PULSE_START__MASK         0x00001FFF +#define    DAC_BROAD_PULSE__DAC_BROAD_PULSE_START__SHIFT        0 +#define    DAC_BROAD_PULSE__DAC_BROAD_PULSE_END__MASK           0x1FFF0000 +#define    DAC_BROAD_PULSE__DAC_BROAD_PULSE_END__SHIFT          16 +#define    DAC_BROAD_PULSE__DAC_BROAD_PULSE_START_R2__MASK      0x00000FFF +#define    DAC_BROAD_PULSE__DAC_BROAD_PULSE_START_R2__SHIFT     0 +#define    DAC_BROAD_PULSE__DAC_BROAD_PULSE_END_R2__MASK        0x0FFF0000 +#define    DAC_BROAD_PULSE__DAC_BROAD_PULSE_END_R2__SHIFT       16 +#define DAC_SKEW_CLKS                                       0x00000DC8 +#define    DAC_SKEW_CLKS__DAC_SKEW_CLKS__MASK                   0x000000FF +#define    DAC_SKEW_CLKS__DAC_SKEW_CLKS__SHIFT                  0 +#define DAC_INCR                                            0x00000DCC +#define    DAC_INCR__DAC_INCR_Y_G__MASK                         0x000003FF +#define    DAC_INCR__DAC_INCR_Y_G__SHIFT                        0 +#define    DAC_INCR__DAC_INCR_CrCb_RB__MASK                     0x03FF0000 +#define    DAC_INCR__DAC_INCR_CrCb_RB__SHIFT                    16 +#define DAC_NEG_SYNC_LEVEL                                  0x00000DD0 +#define    DAC_NEG_SYNC_LEVEL__DAC_NEG_SYNC_LEVEL_Y_G__MASK     0x000003FF +#define    DAC_NEG_SYNC_LEVEL__DAC_NEG_SYNC_LEVEL_Y_G__SHIFT    0 +#define    DAC_NEG_SYNC_LEVEL__DAC_NEG_SYNC_LEVEL_CrCb_RB__MASK 0x03FF0000 +#define    DAC_NEG_SYNC_LEVEL__DAC_NEG_SYNC_LEVEL_CrCb_RB__SHIFT 16 +#define DAC_POS_SYNC_LEVEL                                  0x00000DD4 +#define    DAC_POS_SYNC_LEVEL__DAC_POS_SYNC_LEVEL_Y_G__MASK     0x000003FF +#define    DAC_POS_SYNC_LEVEL__DAC_POS_SYNC_LEVEL_Y_G__SHIFT    0 +#define    DAC_POS_SYNC_LEVEL__DAC_POS_SYNC_LEVEL_CrCb_RB__MASK 0x03FF0000 +#define    DAC_POS_SYNC_LEVEL__DAC_POS_SYNC_LEVEL_CrCb_RB__SHIFT 16 +#define DAC_BLANK_LEVEL                                     0x00000DD8 +#define    DAC_BLANK_LEVEL__DAC_BLANK_LEVEL_Y_G__MASK           0x000003FF +#define    DAC_BLANK_LEVEL__DAC_BLANK_LEVEL_Y_G__SHIFT          0 +#define    DAC_BLANK_LEVEL__DAC_BLANK_LEVEL_CrCb_RB__MASK       0x03FF0000 +#define    DAC_BLANK_LEVEL__DAC_BLANK_LEVEL_CrCb_RB__SHIFT      16 +#define DAC_SYNC_EQUALIZATION                               0x00000DDC +#define    DAC_SYNC_EQUALIZATION__DAC_SYNC_EQ_START__MASK       0x000007FF +#define    DAC_SYNC_EQUALIZATION__DAC_SYNC_EQ_START__SHIFT      0 +#define    DAC_SYNC_EQUALIZATION__DAC_SYNC_EQ_END__MASK         0x07FF0000 +#define    DAC_SYNC_EQUALIZATION__DAC_SYNC_EQ_END__SHIFT        16 +#define TV_MASTER_CNTL                                      0x00000800 +#define    TV_MASTER_CNTL__TV_ASYNC_RST                         0x00000001 +#define    TV_MASTER_CNTL__CRT_ASYNC_RST                        0x00000002 +#define    TV_MASTER_CNTL__RESTART_PHASE_FIX                    0x00000008 +#define    TV_MASTER_CNTL__TV_FIFO_ASYNC_RST                    0x00000010 +#define    TV_MASTER_CNTL__MV_BP_LEVEL_FIX_EN                   0x00000020 +#define    TV_MASTER_CNTL__EXTRA_BIT_ONE_0                      0x00000040 +#define    TV_MASTER_CNTL__CRT_FIFO_CE_EN                       0x00000200 +#define    TV_MASTER_CNTL__TV_FIFO_CE_EN                        0x00000400 +#define    TV_MASTER_CNTL__RE_SYNC_NOW_SEL__MASK                0x0000C000 +#define    TV_MASTER_CNTL__RE_SYNC_NOW_SEL__SHIFT               14 +#define    TV_MASTER_CNTL__EXTRA_BIT_ZERO_1                     0x00010000 +#define    TV_MASTER_CNTL__EXTRA_BIT_ONE_1                      0x00020000 +#define    TV_MASTER_CNTL__EXTRA_BIT_ZERO_2                     0x00040000 +#define    TV_MASTER_CNTL__EXTRA_BIT_ONE_2                      0x00080000 +#define    TV_MASTER_CNTL__TVCLK_ALWAYS_ONb                     0x40000000 +#define    TV_MASTER_CNTL__TV_ON                                0x80000000 +#define TV_DAC_CNTL                                         0x0000088C +#define    TV_DAC_CNTL__NBLANK                                  0x00000001 +#define    TV_DAC_CNTL__NHOLD                                   0x00000002 +#define    TV_DAC_CNTL__PEDESTAL                                0x00000004 +#define    TV_DAC_CNTL__DETECT                                  0x00000010 +#define    TV_DAC_CNTL__CMPOUT                                  0x00000020 +#define    TV_DAC_CNTL__BGSLEEP                                 0x00000040 +#define    TV_DAC_CNTL__STD__MASK                               0x00000300 +#define    TV_DAC_CNTL__STD__SHIFT                              8 +#define    STD__PAL                                                 0x0 +#define    STD__NTSC                                                0x1 +#define    STD__PS2                                                 0x2 +#define    STD__RS343                                               0x3 +#define    TV_DAC_CNTL__MON__MASK                               0x0000F000 +#define    TV_DAC_CNTL__MON__SHIFT                              12 +#define    TV_DAC_CNTL__BGADJ__MASK                             0x000F0000 +#define    TV_DAC_CNTL__BGADJ__SHIFT                            16 +#define    TV_DAC_CNTL__DACADJ__MASK                            0x00F00000 +#define    TV_DAC_CNTL__DACADJ__SHIFT                           20 +#define    TV_DAC_CNTL__RDACPD                                  0x01000000 +#define    TV_DAC_CNTL__GDACPD                                  0x02000000 +#define    TV_DAC_CNTL__BDACPD                                  0x04000000 +#define    TV_DAC_CNTL__RDACDET                                 0x20000000 +#define    TV_DAC_CNTL__GDACDET                                 0x40000000 +#define    TV_DAC_CNTL__BDACDET                                 0x80000000 +#define    TV_DAC_CNTL__DACADJ_R4__MASK                         0x01F00000 +#define    TV_DAC_CNTL__DACADJ_R4__SHIFT                        20 +#define    TV_DAC_CNTL__RDACPD_R4                               0x02000000 +#define    TV_DAC_CNTL__GDACPD_R4                               0x04000000 +#define    TV_DAC_CNTL__BDACPD_R4                               0x08000000 +#define    TV_DAC_CNTL__TVENABLE_R4                             0x10000000 +#define VIPPAD_EN                                           0x000001A0 +#define    VIPPAD_EN__VIPPAD_EN__MASK                           0x0007FFFF +#define    VIPPAD_EN__VIPPAD_EN__SHIFT                          0 +#define    VIPPAD_EN__VIPPAD_EN_TVODATA__MASK                   0x000003FF +#define    VIPPAD_EN__VIPPAD_EN_TVODATA__SHIFT                  0 +#define    VIPPAD_EN__VIPPAD_EN_TVOCLKO                         0x00000400 +#define    VIPPAD_EN__VIPPAD_EN_ROMCSb                          0x00000800 +#define    VIPPAD_EN__VIPPAD_EN_VHAD__MASK                      0x00003000 +#define    VIPPAD_EN__VIPPAD_EN_VHAD__SHIFT                     12 +#define    VIPPAD_EN__VIPPAD_EN_VPHCTL                          0x00010000 +#define    VIPPAD_EN__VIPPAD_EN_VIPCLK                          0x00020000 +#define    VIPPAD_EN__VIPPAD_EN_SI                              0x00080000 +#define    VIPPAD_EN__VIPPAD_EN_SO                              0x00100000 +#define    VIPPAD_EN__VIPPAD_EN_SCK                             0x00200000 +#define VIPPAD_Y                                            0x000001A4 +#define    VIPPAD_Y__VIPPAD_Y__MASK                             0x0007FFFF +#define    VIPPAD_Y__VIPPAD_Y__SHIFT                            0 +#define    VIPPAD_Y__VIPPAD_Y_TVODATA__MASK                     0x000003FF +#define    VIPPAD_Y__VIPPAD_Y_TVODATA__SHIFT                    0 +#define    VIPPAD_Y__VIPPAD_Y_TVOCLKO                           0x00000400 +#define    VIPPAD_Y__VIPPAD_Y_ROMCSb                            0x00000800 +#define    VIPPAD_Y__VIPPAD_Y_VHAD__MASK                        0x00003000 +#define    VIPPAD_Y__VIPPAD_Y_VHAD__SHIFT                       12 +#define    VIPPAD_Y__VIPPAD_Y_VPHCTL                            0x00010000 +#define    VIPPAD_Y__VIPPAD_Y_VIPCLK                            0x00020000 +#define    VIPPAD_Y__VIPPAD_Y_SI                                0x00080000 +#define    VIPPAD_Y__VIPPAD_Y_SO                                0x00100000 +#define    VIPPAD_Y__VIPPAD_Y_SCK                               0x00200000 +#define VIPPAD1_EN                                          0x000001B0 +#define    VIPPAD1_EN__VIPPAD1_EN__MASK                         0x0003FFFF +#define    VIPPAD1_EN__VIPPAD1_EN__SHIFT                        0 +#define    VIPPAD1_EN__VIPPAD_EN_VID__MASK                      0x000000FF +#define    VIPPAD1_EN__VIPPAD_EN_VID__SHIFT                     0 +#define    VIPPAD1_EN__VIPPAD_EN_VPCLK0                         0x00000100 +#define    VIPPAD1_EN__VIPPAD_EN_DVALID                         0x00000200 +#define    VIPPAD1_EN__VIPPAD_EN_PSYNC                          0x00000400 +#define    VIPPAD1_EN__VIPPAD_EN_DVODATA__MASK                  0x0FFF0000 +#define    VIPPAD1_EN__VIPPAD_EN_DVODATA__SHIFT                 16 +#define    VIPPAD1_EN__VIPPAD_EN_DVOCNTL__MASK                  0x70000000 +#define    VIPPAD1_EN__VIPPAD_EN_DVOCNTL__SHIFT                 28 +#define VIPPAD1_Y                                           0x000001B4 +#define    VIPPAD1_Y__VIPPAD1_Y__MASK                           0x0003FFFF +#define    VIPPAD1_Y__VIPPAD1_Y__SHIFT                          0 +#define    VIPPAD1_Y__VIPPAD_Y_VID__MASK                        0x000000FF +#define    VIPPAD1_Y__VIPPAD_Y_VID__SHIFT                       0 +#define    VIPPAD1_Y__VIPPAD_Y_VPCLK0                           0x00000100 +#define    VIPPAD1_Y__VIPPAD_Y_DVALID                           0x00000200 +#define    VIPPAD1_Y__VIPPAD_Y_PSYNC                            0x00000400 +#define    VIPPAD1_Y__VIPPAD_Y_DVODATA__MASK                    0x0FFF0000 +#define    VIPPAD1_Y__VIPPAD_Y_DVODATA__SHIFT                   16 +#define    VIPPAD1_Y__VIPPAD_Y_DVOCNTL__MASK                    0x70000000 +#define    VIPPAD1_Y__VIPPAD_Y_DVOCNTL__SHIFT                   28 +#define GPIO_DDC1                                           0x00000060 +#define    GPIO_DDC1__DDC1_DATA_OUTPUT                          0x00000001 +#define    GPIO_DDC1__DDC1_CLK_OUTPUT                           0x00000002 +#define    GPIO_DDC1__DDC1_DATA_INPUT                           0x00000100 +#define    GPIO_DDC1__DDC1_CLK_INPUT                            0x00000200 +#define    GPIO_DDC1__DDC1_DATA_OUT_EN                          0x00010000 +#define    GPIO_DDC1__DDC1_CLK_OUT_EN                           0x00020000 +#define    GPIO_DDC1__SW_WANTS_TO_USE_DVI_I2C                   0x00100000 +#define    GPIO_DDC1__SW_CAN_USE_DVI_I2C                        0x00100000 +#define    GPIO_DDC1__SW_DONE_USING_DVI_I2C                     0x00200000 +#define    GPIO_DDC1__HW_USING_DVI_I2C                          0x00400000 +#define GPIO_DDC2                                           0x00000064 +#define    GPIO_DDC2__DDC2_DATA_OUTPUT                          0x00000001 +#define    GPIO_DDC2__DDC2_CLK_OUTPUT                           0x00000002 +#define    GPIO_DDC2__DDC2_DATA_INPUT                           0x00000100 +#define    GPIO_DDC2__DDC2_CLK_INPUT                            0x00000200 +#define    GPIO_DDC2__DDC2_DATA_OUT_EN                          0x00010000 +#define    GPIO_DDC2__DDC2_CLK_OUT_EN                           0x00020000 +#define    GPIO_DDC2__SW_WANTS_TO_USE_DVI_I2C                   0x00100000 +#define    GPIO_DDC2__SW_CAN_USE_DVI_I2C                        0x00100000 +#define    GPIO_DDC2__SW_DONE_USING_DVI_I2C                     0x00200000 +#define    GPIO_DDC2__HW_USING_DVI_I2C                          0x00400000 +#define GPIO_DVI_DDC                                        0x00000064 +#define    GPIO_DVI_DDC__DVI_DDC_DATA_OUTPUT                    0x00000001 +#define    GPIO_DVI_DDC__DVI_DCC_DATA_OUTPUT                    0x00000001 +#define    GPIO_DVI_DDC__DVI_DDC_CLK_OUTPUT                     0x00000002 +#define    GPIO_DVI_DDC__DVI_DDC_DATA_INPUT                     0x00000100 +#define    GPIO_DVI_DDC__DVI_DDC_CLK_INPUT                      0x00000200 +#define    GPIO_DVI_DDC__DVI_DDC_DATA_OUT_EN                    0x00010000 +#define    GPIO_DVI_DDC__DVI_DDC_CLK_OUT_EN                     0x00020000 +#define    GPIO_DVI_DDC__SW_WANTS_TO_USE_DVI_I2C                0x00100000 +#define    GPIO_DVI_DDC__SW_CAN_USE_DVI_I2C                     0x00100000 +#define    GPIO_DVI_DDC__SW_DONE_USING_DVI_I2C                  0x00200000 +#define    GPIO_DVI_DDC__HW_USING_DVI_I2C                       0x00400000 +#define GPIO_MONID                                          0x00000068 +#define    GPIO_MONID__GPIO_MONID_0_OUTPUT                      0x00000001 +#define    GPIO_MONID__GPIO_MONID_1_OUTPUT                      0x00000002 +#define    GPIO_MONID__GPIO_MONID_0_INPUT                       0x00000100 +#define    GPIO_MONID__GPIO_MONID_1_INPUT                       0x00000200 +#define    GPIO_MONID__GPIO_MONID_0_OUT_EN                      0x00010000 +#define    GPIO_MONID__GPIO_MONID_1_OUT_EN                      0x00020000 +#define GPIO_CRT2_DDC                                       0x0000006C +#define    GPIO_CRT2_DDC__CRT2_DDC_DATA_OUTPUT                  0x00000001 +#define    GPIO_CRT2_DDC__CRT2_DDC_CLK_OUTPUT                   0x00000002 +#define    GPIO_CRT2_DDC__CRT2_DDC_DATA_INPUT                   0x00000100 +#define    GPIO_CRT2_DDC__CRT2_DDC_CLK_INPUT                    0x00000200 +#define    GPIO_CRT2_DDC__CRT2_DDC_DATA_OUT_EN                  0x00010000 +#define    GPIO_CRT2_DDC__CRT2_DDC_CLK_OUT_EN                   0x00020000 +#define CLOCK_CNTL_INDEX                                    0x00000008 +#define    CLOCK_CNTL_INDEX__PLL_ADDR__MASK                     0x0000001F +#define    CLOCK_CNTL_INDEX__PLL_ADDR__SHIFT                    0 +#define    CLOCK_CNTL_INDEX__PLL_WR_EN                          0x00000080 +#define    CLOCK_CNTL_INDEX__PPLL_DIV_SEL__MASK                 0x00000300 +#define    CLOCK_CNTL_INDEX__PPLL_DIV_SEL__SHIFT                8 +#define    CLOCK_CNTL_INDEX__PLL_ADDR_R2__MASK                  0x0000003F +#define    CLOCK_CNTL_INDEX__PLL_ADDR_R2__SHIFT                 0 +#define CLOCK_CNTL_DATA                                     0x0000000C +#define    CLOCK_CNTL_DATA__PLL_DATA__MASK                      0xFFFFFFFF +#define    CLOCK_CNTL_DATA__PLL_DATA__SHIFT                     0 +#define MCLK_CNTL                                           0x00000012 +#define    MCLK_CNTL__MCLKA_SRC_SEL__MASK                       0x00000007 +#define    MCLK_CNTL__MCLKA_SRC_SEL__SHIFT                      0 +#define    MCLK_CNTL__YCLKA_SRC_SEL__MASK                       0x00000070 +#define    MCLK_CNTL__YCLKA_SRC_SEL__SHIFT                      4 +#define    MCLK_CNTL__MCLKB_SRC_SEL__MASK                       0x00000700 +#define    MCLK_CNTL__MCLKB_SRC_SEL__SHIFT                      8 +#define    MCLK_CNTL__YCLKB_SRC_SEL__MASK                       0x00007000 +#define    MCLK_CNTL__YCLKB_SRC_SEL__SHIFT                      12 +#define    MCLK_CNTL__FORCE_MCLKA                               0x00010000 +#define    MCLK_CNTL__FORCE_MCLKB                               0x00020000 +#define    MCLK_CNTL__FORCE_YCLKA                               0x00040000 +#define    MCLK_CNTL__FORCE_YCLKB                               0x00080000 +#define    MCLK_CNTL__FORCE_MC                                  0x00100000 +#define    MCLK_CNTL__FORCE_AIC                                 0x00200000 +#define    MCLK_CNTL__MRDCKA0_SOUTSEL__MASK                     0x03000000 +#define    MCLK_CNTL__MRDCKA0_SOUTSEL__SHIFT                    24 +#define    MCLK_CNTL__MRDCKA1_SOUTSEL__MASK                     0x0C000000 +#define    MCLK_CNTL__MRDCKA1_SOUTSEL__SHIFT                    26 +#define    MCLK_CNTL__MRDCKB0_SOUTSEL__MASK                     0x30000000 +#define    MCLK_CNTL__MRDCKB0_SOUTSEL__SHIFT                    28 +#define    MCLK_CNTL__MRDCKB1_SOUTSEL__MASK                     0xC0000000 +#define    MCLK_CNTL__MRDCKB1_SOUTSEL__SHIFT                    30 +#define    MCLK_CNTL__FORCE_MC_MCLKA                            0x00010000 +#define    MCLK_CNTL__FORCE_MC_MCLKB                            0x00020000 +#define    MCLK_CNTL__FORCE_MC_MCLK                             0x00100000 +#define    MCLK_CNTL__DISABLE_MC_MCLKA                          0x00200000 +#define    MCLK_CNTL__DISABLE_MC_MCLKB                          0x00400000 +#define SCLK_CNTL                                           0x0000000D +#define    SCLK_CNTL__SCLK_SRC_SEL__MASK                        0x00000007 +#define    SCLK_CNTL__SCLK_SRC_SEL__SHIFT                       0 +#define    SCLK_CNTL__TCLK_SRC_SEL__MASK                        0x00000700 +#define    SCLK_CNTL__TCLK_SRC_SEL__SHIFT                       8 +#define    SCLK_CNTL__FORCE_CP                                  0x00010000 +#define    SCLK_CNTL__FORCE_HDP                                 0x00020000 +#define    SCLK_CNTL__FORCE_DISP                                0x00040000 +#define    SCLK_CNTL__FORCE_TOP                                 0x00080000 +#define    SCLK_CNTL__FORCE_E2                                  0x00100000 +#define    SCLK_CNTL__FORCE_SE                                  0x00200000 +#define    SCLK_CNTL__FORCE_IDCT                                0x00400000 +#define    SCLK_CNTL__FORCE_VIP                                 0x00800000 +#define    SCLK_CNTL__FORCE_RE                                  0x01000000 +#define    SCLK_CNTL__FORCE_PB                                  0x02000000 +#define    SCLK_CNTL__FORCE_TAM                                 0x04000000 +#define    SCLK_CNTL__FORCE_TDM                                 0x08000000 +#define    SCLK_CNTL__FORCE_RB                                  0x10000000 +#define    SCLK_CNTL__CP_MAX_DYN_STOP_LAT                       0x00000008 +#define    SCLK_CNTL__HDP_MAX_DYN_STOP_LAT                      0x00000010 +#define    SCLK_CNTL__E2_MAX_DYN_STOP_LAT                       0x00000040 +#define    SCLK_CNTL__SE_MAX_DYN_STOP_LAT                       0x00000080 +#define    SCLK_CNTL__IDCT_MAX_DYN_STOP_LAT                     0x00000100 +#define    SCLK_CNTL__VIP_MAX_DYN_STOP_LAT                      0x00000200 +#define    SCLK_CNTL__RE_MAX_DYN_STOP_LAT                       0x00000400 +#define    SCLK_CNTL__PB_MAX_DYN_STOP_LAT                       0x00000800 +#define    SCLK_CNTL__TAM_MAX_DYN_STOP_LAT                      0x00001000 +#define    SCLK_CNTL__TDM_MAX_DYN_STOP_LAT                      0x00002000 +#define    SCLK_CNTL__RB_MAX_DYN_STOP_LAT                       0x00004000 +#define    SCLK_CNTL__FORCE_DISP2                               0x00008000 +#define    SCLK_CNTL__FORCE_DISP1                               0x00040000 +#define    SCLK_CNTL__FORCE_SUBPIC                              0x40000000 +#define    SCLK_CNTL__FORCE_OV0                                 0x80000000 +#define    SCLK_CNTL__TV_MAX_DYN_STOP_LAT                       0x00000020 +#define    SCLK_CNTL__FORCE_TV_SCLK                             0x20000000 +#define    SCLK_CNTL__VAP_MAX_DYN_STOP_LAT                      0x00000080 +#define    SCLK_CNTL__SR_MAX_DYN_STOP_LAT                       0x00000400 +#define    SCLK_CNTL__PX_MAX_DYN_STOP_LAT                       0x00000800 +#define    SCLK_CNTL__TX_MAX_DYN_STOP_LAT                       0x00001000 +#define    SCLK_CNTL__US_MAX_DYN_STOP_LAT                       0x00002000 +#define    SCLK_CNTL__SU_MAX_DYN_STOP_LAT                       0x00004000 +#define    SCLK_CNTL__FORCE_VAP                                 0x00200000 +#define    SCLK_CNTL__FORCE_SR                                  0x02000000 +#define    SCLK_CNTL__FORCE_PX                                  0x04000000 +#define    SCLK_CNTL__FORCE_TX                                  0x08000000 +#define    SCLK_CNTL__FORCE_US                                  0x10000000 +#define    SCLK_CNTL__FORCE_SU                                  0x40000000 +#define PPLL_CNTL                                           0x00000002 +#define    PPLL_CNTL__PPLL_RESET                                0x00000001 +#define    PPLL_CNTL__PPLL_SLEEP                                0x00000002 +#define    PPLL_CNTL__PPLL_TST_EN                               0x00000004 +#define    PPLL_CNTL__PPLL_REFCLK_SEL                           0x00000010 +#define    PPLL_CNTL__PPLL_FBCLK_SEL                            0x00000020 +#define    PPLL_CNTL__PPLL_TCPOFF                               0x00000040 +#define    PPLL_CNTL__PPLL_TVCOMAX                              0x00000080 +#define    PPLL_CNTL__PPLL_PCP__MASK                            0x00000700 +#define    PPLL_CNTL__PPLL_PCP__SHIFT                           8 +#define    PPLL_CNTL__PPLL_PVG__MASK                            0x00003800 +#define    PPLL_CNTL__PPLL_PVG__SHIFT                           11 +#define    PPLL_CNTL__PPLL_PDC__MASK                            0x0000C000 +#define    PPLL_CNTL__PPLL_PDC__SHIFT                           14 +#define    PPLL_CNTL__PPLL_ATOMIC_UPDATE_EN                     0x00010000 +#define    PPLL_CNTL__PPLL_VGA_ATOMIC_UPDATE_EN                 0x00020000 +#define    PPLL_CNTL__PPLL_ATOMIC_UPDATE_SYNC                   0x00040000 +#define    PPLL_CNTL__PPLL_DISABLE_AUTO_RESET                   0x00080000 +#define    PPLL_CNTL__PPLL_DIV_RESET                            0x00000008 +#define PPLL_REF_DIV                                        0x00000003 +#define    PPLL_REF_DIV__PPLL_REF_DIV__MASK                     0x000003FF +#define    PPLL_REF_DIV__PPLL_REF_DIV__SHIFT                    0 +#define    PPLL_REF_DIV__PPLL_ATOMIC_UPDATE_W                   0x00008000 +#define    PPLL_REF_DIV__PPLL_ATOMIC_UPDATE_R                   0x00008000 +#define    PPLL_REF_DIV__PPLL_REF_DIV_SRC__MASK                 0x00030000 +#define    PPLL_REF_DIV__PPLL_REF_DIV_SRC__SHIFT                16 +#define    PPLL_REF_DIV_SRC__XTALIN                                 0x0 +#define    PPLL_REF_DIV_SRC__PLLSCLK_2                              0x1 +#define    PPLL_REF_DIV_SRC__PLLSCLK_4                              0x2 +#define    PPLL_REF_DIV_SRC__SREFCLK                                0x3 +#define    PPLL_REF_DIV__PPLL_REF_DIV_ACC__MASK                 0x0FFC0000 +#define    PPLL_REF_DIV__PPLL_REF_DIV_ACC__SHIFT                18 +#define PPLL_DIV_0                                          0x00000004 +#define    PPLL_DIV_0__PPLL_FB0_DIV__MASK                       0x000007FF +#define    PPLL_DIV_0__PPLL_FB0_DIV__SHIFT                      0 +#define    PPLL_DIV_0__PPLL_ATOMIC_UPDATE_W                     0x00008000 +#define    PPLL_DIV_0__PPLL_ATOMIC_UPDATE_R                     0x00008000 +#define    PPLL_DIV_0__PPLL_POST0_DIV__MASK                     0x00070000 +#define    PPLL_DIV_0__PPLL_POST0_DIV__SHIFT                    16 +#define    PPLL_DIV_0__PPLL_FB_DIV_FRACTION__MASK               0x00380000 +#define    PPLL_DIV_0__PPLL_FB_DIV_FRACTION__SHIFT              19 +#define    PPLL_DIV_0__PPLL_FB_DIV_FRACTION_UPDATE              0x00400000 +#define    PPLL_DIV_0__PPLL_FB_DIV_FRACTION_EN                  0x00800000 +#define PPLL_DIV_1                                          0x00000005 +#define    PPLL_DIV_1__PPLL_FB1_DIV__MASK                       0x000007FF +#define    PPLL_DIV_1__PPLL_FB1_DIV__SHIFT                      0 +#define    PPLL_DIV_1__PPLL_ATOMIC_UPDATE_W                     0x00008000 +#define    PPLL_DIV_1__PPLL_ATOMIC_UPDATE_R                     0x00008000 +#define    PPLL_DIV_1__PPLL_POST1_DIV__MASK                     0x00070000 +#define    PPLL_DIV_1__PPLL_POST1_DIV__SHIFT                    16 +#define PPLL_DIV_2                                          0x00000006 +#define    PPLL_DIV_2__PPLL_FB2_DIV__MASK                       0x000007FF +#define    PPLL_DIV_2__PPLL_FB2_DIV__SHIFT                      0 +#define    PPLL_DIV_2__PPLL_ATOMIC_UPDATE_W                     0x00008000 +#define    PPLL_DIV_2__PPLL_ATOMIC_UPDATE_R                     0x00008000 +#define    PPLL_DIV_2__PPLL_POST2_DIV__MASK                     0x00070000 +#define    PPLL_DIV_2__PPLL_POST2_DIV__SHIFT                    16 +#define PPLL_DIV_3                                          0x00000007 +#define    PPLL_DIV_3__PPLL_FB3_DIV__MASK                       0x000007FF +#define    PPLL_DIV_3__PPLL_FB3_DIV__SHIFT                      0 +#define    PPLL_DIV_3__PPLL_ATOMIC_UPDATE_W                     0x00008000 +#define    PPLL_DIV_3__PPLL_ATOMIC_UPDATE_R                     0x00008000 +#define    PPLL_DIV_3__PPLL_POST3_DIV__MASK                     0x00070000 +#define    PPLL_DIV_3__PPLL_POST3_DIV__SHIFT                    16 +#define VCLK_ECP_CNTL                                       0x00000008 +#define    VCLK_ECP_CNTL__VCLK_SRC_SEL__MASK                    0x00000003 +#define    VCLK_ECP_CNTL__VCLK_SRC_SEL__SHIFT                   0 +#define    VCLK_SRC_SEL__CPUCLK                                     0x0 +#define    VCLK_SRC_SEL__PSCANCLK                                   0x1 +#define    VCLK_SRC_SEL__BYTE_CLK                                   0x2 +#define    VCLK_SRC_SEL__PPLLCLK                                    0x3 +#define    VCLK_ECP_CNTL__VCLK_INVERT                           0x00000010 +#define    VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb                     0x00000040 +#define    VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb                 0x00000080 +#define    VCLK_ECP_CNTL__ECP_DIV__MASK                         0x00000300 +#define    VCLK_ECP_CNTL__ECP_DIV__SHIFT                        8 +#define    VCLK_ECP_CNTL__ECP_FORCE_ON                          0x00040000 +#define    VCLK_ECP_CNTL__SUBCLK_FORCE_ON                       0x00080000 +#define    VCLK_ECP_CNTL__BYTE_CLK_POST_DIV__MASK               0x00030000 +#define    VCLK_ECP_CNTL__BYTE_CLK_POST_DIV__SHIFT              16 +#define    VCLK_ECP_CNTL__BYTE_CLK_OUT_EN                       0x00100000 +#define    VCLK_ECP_CNTL__BYTE_CLK_SKEW__MASK                   0x07000000 +#define    VCLK_ECP_CNTL__BYTE_CLK_SKEW__SHIFT                  24 +#define    VCLK_ECP_CNTL__PCICLK_INVERT                         0x00000020 +#define    VCLK_ECP_CNTL__PIXCLK_SRC_INVERT                     0x00000020 +#define    VCLK_ECP_CNTL__PIXCLK_SRC_INVERT_R3                  0x08000000 +#define    VCLK_ECP_CNTL__DISP_DAC_PIXCLK_DAC_BLANK_OFF         0x00800000 +#define HTOTAL_CNTL                                         0x00000009 +#define    HTOTAL_CNTL__HTOT_PIX_SLIP__MASK                     0x0000000F +#define    HTOTAL_CNTL__HTOT_PIX_SLIP__SHIFT                    0 +#define    HTOTAL_CNTL__HTOT_VCLK_SLIP__MASK                    0x00000F00 +#define    HTOTAL_CNTL__HTOT_VCLK_SLIP__SHIFT                   8 +#define    HTOTAL_CNTL__HTOT_PPLL_SLIP__MASK                    0x00070000 +#define    HTOTAL_CNTL__HTOT_PPLL_SLIP__SHIFT                   16 +#define    HTOTAL_CNTL__HTOT_CNTL_EDGE                          0x01000000 +#define    HTOTAL_CNTL__HTOT_CNTL_VGA_EN                        0x10000000 +#define FP_H_SYNC_STRT_WID                                  0x000002C4 +#define    FP_H_SYNC_STRT_WID__FP_H_SYNC_STRT_PIX__MASK         0x00000007 +#define    FP_H_SYNC_STRT_WID__FP_H_SYNC_STRT_PIX__SHIFT        0 +#define    FP_H_SYNC_STRT_WID__FP_H_SYNC_STRT_CHAR__MASK        0x00001FF8 +#define    FP_H_SYNC_STRT_WID__FP_H_SYNC_STRT_CHAR__SHIFT       3 +#define    FP_H_SYNC_STRT_WID__FP_H_SYNC_WID__MASK              0x003F0000 +#define    FP_H_SYNC_STRT_WID__FP_H_SYNC_WID__SHIFT             16 +#define    FP_H_SYNC_STRT_WID__FP_H_SYNC_POL                    0x00800000 +#define FP_V_SYNC_STRT_WID                                  0x000002C8 +#define    FP_V_SYNC_STRT_WID__FP_V_SYNC_STRT__MASK             0x00000FFF +#define    FP_V_SYNC_STRT_WID__FP_V_SYNC_STRT__SHIFT            0 +#define    FP_V_SYNC_STRT_WID__FP_V_SYNC_WID__MASK              0x001F0000 +#define    FP_V_SYNC_STRT_WID__FP_V_SYNC_WID__SHIFT             16 +#define    FP_V_SYNC_STRT_WID__FP_V_SYNC_POL                    0x00800000 +#define FP_CRTC_H_TOTAL_DISP                                0x00000250 +#define    FP_CRTC_H_TOTAL_DISP__FP_CRTC_H_TOTAL__MASK          0x000003FF +#define    FP_CRTC_H_TOTAL_DISP__FP_CRTC_H_TOTAL__SHIFT         0 +#define    FP_CRTC_H_TOTAL_DISP__FP_CRTC_H_DISP__MASK           0x01FF0000 +#define    FP_CRTC_H_TOTAL_DISP__FP_CRTC_H_DISP__SHIFT          16 +#define FP_CRTC_V_TOTAL_DISP                                0x00000254 +#define    FP_CRTC_V_TOTAL_DISP__FP_CRTC_V_TOTAL__MASK          0x00000FFF +#define    FP_CRTC_V_TOTAL_DISP__FP_CRTC_V_TOTAL__SHIFT         0 +#define    FP_CRTC_V_TOTAL_DISP__FP_CRTC_V_DISP__MASK           0x0FFF0000 +#define    FP_CRTC_V_TOTAL_DISP__FP_CRTC_V_DISP__SHIFT          16 +#define PALETTE_INDEX                                       0x000000B0 +#define    PALETTE_INDEX__PALETTE_W_INDEX__MASK                 0x000000FF +#define    PALETTE_INDEX__PALETTE_W_INDEX__SHIFT                0 +#define    PALETTE_INDEX__PALETTE_R_INDEX__MASK                 0x00FF0000 +#define    PALETTE_INDEX__PALETTE_R_INDEX__SHIFT                16 +#define PALETTE_DATA                                        0x000000B4 +#define    PALETTE_DATA__PALETTE_DATA_B__MASK                   0x000000FF +#define    PALETTE_DATA__PALETTE_DATA_B__SHIFT                  0 +#define    PALETTE_DATA__PALETTE_DATA_G__MASK                   0x0000FF00 +#define    PALETTE_DATA__PALETTE_DATA_G__SHIFT                  8 +#define    PALETTE_DATA__PALETTE_DATA_R__MASK                   0x00FF0000 +#define    PALETTE_DATA__PALETTE_DATA_R__SHIFT                  16 +#define PALETTE_30_DATA                                     0x000000B8 +#define    PALETTE_30_DATA__PALETTE_DATA_B__MASK                0x000003FF +#define    PALETTE_30_DATA__PALETTE_DATA_B__SHIFT               0 +#define    PALETTE_30_DATA__PALETTE_DATA_G__MASK                0x000FFC00 +#define    PALETTE_30_DATA__PALETTE_DATA_G__SHIFT               10 +#define    PALETTE_30_DATA__PALETTE_DATA_R__MASK                0x3FF00000 +#define    PALETTE_30_DATA__PALETTE_DATA_R__SHIFT               20 +#define SURFACE_CNTL                                        0x00000B00 +#define    SURFACE_CNTL__SURF_TRANSLATION_DIS                   0x00000100 +#define    SURFACE_CNTL__NONSURF_AP0_SWP__MASK                  0x00300000 +#define    SURFACE_CNTL__NONSURF_AP0_SWP__SHIFT                 20 +#define    SURFACE_CNTL__NONSURF_AP1_SWP__MASK                  0x00C00000 +#define    SURFACE_CNTL__NONSURF_AP1_SWP__SHIFT                 22 +#define SURFACE0_INFO                                       0x00000B0C +#define    SURFACE0_INFO__SURF0_PITCHSEL__MASK                  0x000003FF +#define    SURFACE0_INFO__SURF0_PITCHSEL__SHIFT                 0 +#define    SURFACE0_INFO__SURF0_TILE_MODE__MASK                 0x00030000 +#define    SURFACE0_INFO__SURF0_TILE_MODE__SHIFT                16 +#define    SURF0_TILE_MODE__NO_TILING(p)                            0x0 +#define    SURF0_TILE_MODE__MACRO_TILING(p)                         0x0 +#define    SURF0_TILE_MODE__MICRO_TILING(p)                         0x0 +#define    SURF0_TILE_MODE__MACRO_MICRO_TILING(p)                   0x0 +#define    SURF0_TILE_MODE__32_BIT_Z_TILING(p)                      0x0 +#define    SURF0_TILE_MODE__16_BIT_Z_TILING(p)                      0x0 +#define    SURFACE0_INFO__SURF0_AP0_SWP__MASK                   0x00300000 +#define    SURFACE0_INFO__SURF0_AP0_SWP__SHIFT                  20 +#define    SURFACE0_INFO__SURF0_AP1_SWP__MASK                   0x00C00000 +#define    SURFACE0_INFO__SURF0_AP1_SWP__SHIFT                  22 +#define    SURFACE0_INFO__SURF0_WRITE_FLAG                      0x01000000 +#define    SURFACE0_INFO__SURF0_READ_FLAG                       0x02000000 +#define    SURFACE0_INFO__SURF0_TILE_MODE_R2__MASK              0x00070000 +#define    SURFACE0_INFO__SURF0_TILE_MODE_R2__SHIFT             16 +#define    SURFACE0_INFO__SURF0_PITCHSEL_R3__MASK               0x00001FFF +#define    SURFACE0_INFO__SURF0_PITCHSEL_R3__SHIFT              0 +#define SURFACE0_LOWER_BOUND                                0x00000B04 +#define    SURFACE0_LOWER_BOUND__SURF_LOWER__MASK               0x0FFFFFFF +#define    SURFACE0_LOWER_BOUND__SURF_LOWER__SHIFT              0 +#define SURFACE0_UPPER_BOUND                                0x00000B08 +#define    SURFACE0_UPPER_BOUND__SURF_UPPER__MASK               0x0FFFFFFF +#define    SURFACE0_UPPER_BOUND__SURF_UPPER__SHIFT              0 +#define SURFACE1_INFO                                       0x00000B1C +#define    SURFACE1_INFO__SURF1_PITCHSEL__MASK                  0x000003FF +#define    SURFACE1_INFO__SURF1_PITCHSEL__SHIFT                 0 +#define    SURFACE1_INFO__SURF1_TILE_MODE__MASK                 0x00030000 +#define    SURFACE1_INFO__SURF1_TILE_MODE__SHIFT                16 +#define    SURFACE1_INFO__SURF1_AP0_SWP__MASK                   0x00300000 +#define    SURFACE1_INFO__SURF1_AP0_SWP__SHIFT                  20 +#define    SURFACE1_INFO__SURF1_AP1_SWP__MASK                   0x00C00000 +#define    SURFACE1_INFO__SURF1_AP1_SWP__SHIFT                  22 +#define    SURFACE1_INFO__SURF1_WRITE_FLAG                      0x01000000 +#define    SURFACE1_INFO__SURF1_READ_FLAG                       0x02000000 +#define    SURFACE1_INFO__SURF1_TILE_MODE_R2__MASK              0x00070000 +#define    SURFACE1_INFO__SURF1_TILE_MODE_R2__SHIFT             16 +#define    SURFACE1_INFO__SURF1_PITCHSEL_R3__MASK               0x00001FFF +#define    SURFACE1_INFO__SURF1_PITCHSEL_R3__SHIFT              0 +#define SURFACE1_LOWER_BOUND                                0x00000B14 +#define    SURFACE1_LOWER_BOUND__SURF_LOWER__MASK               0x0FFFFFFF +#define    SURFACE1_LOWER_BOUND__SURF_LOWER__SHIFT              0 +#define SURFACE1_UPPER_BOUND                                0x00000B18 +#define    SURFACE1_UPPER_BOUND__SURF_UPPER__MASK               0x0FFFFFFF +#define    SURFACE1_UPPER_BOUND__SURF_UPPER__SHIFT              0 +#define SURFACE2_INFO                                       0x00000B2C +#define    SURFACE2_INFO__SURF2_PITCHSEL__MASK                  0x000003FF +#define    SURFACE2_INFO__SURF2_PITCHSEL__SHIFT                 0 +#define    SURFACE2_INFO__SURF2_TILE_MODE__MASK                 0x00030000 +#define    SURFACE2_INFO__SURF2_TILE_MODE__SHIFT                16 +#define    SURFACE2_INFO__SURF2_AP0_SWP__MASK                   0x00300000 +#define    SURFACE2_INFO__SURF2_AP0_SWP__SHIFT                  20 +#define    SURFACE2_INFO__SURF2_AP1_SWP__MASK                   0x00C00000 +#define    SURFACE2_INFO__SURF2_AP1_SWP__SHIFT                  22 +#define    SURFACE2_INFO__SURF2_WRITE_FLAG                      0x01000000 +#define    SURFACE2_INFO__SURF2_READ_FLAG                       0x02000000 +#define    SURFACE2_INFO__SURF2_TILE_MODE_R2__MASK              0x00070000 +#define    SURFACE2_INFO__SURF2_TILE_MODE_R2__SHIFT             16 +#define    SURFACE2_INFO__SURF2_PITCHSEL_R3__MASK               0x00001FFF +#define    SURFACE2_INFO__SURF2_PITCHSEL_R3__SHIFT              0 +#define SURFACE2_LOWER_BOUND                                0x00000B24 +#define    SURFACE2_LOWER_BOUND__SURF_LOWER__MASK               0x0FFFFFFF +#define    SURFACE2_LOWER_BOUND__SURF_LOWER__SHIFT              0 +#define SURFACE2_UPPER_BOUND                                0x00000B28 +#define    SURFACE2_UPPER_BOUND__SURF_UPPER__MASK               0x0FFFFFFF +#define    SURFACE2_UPPER_BOUND__SURF_UPPER__SHIFT              0 +#define SURFACE3_INFO                                       0x00000B3C +#define    SURFACE3_INFO__SURF3_PITCHSEL__MASK                  0x000003FF +#define    SURFACE3_INFO__SURF3_PITCHSEL__SHIFT                 0 +#define    SURFACE3_INFO__SURF3_TILE_MODE__MASK                 0x00030000 +#define    SURFACE3_INFO__SURF3_TILE_MODE__SHIFT                16 +#define    SURFACE3_INFO__SURF3_AP0_SWP__MASK                   0x00300000 +#define    SURFACE3_INFO__SURF3_AP0_SWP__SHIFT                  20 +#define    SURFACE3_INFO__SURF3_AP1_SWP__MASK                   0x00C00000 +#define    SURFACE3_INFO__SURF3_AP1_SWP__SHIFT                  22 +#define    SURFACE3_INFO__SURF3_WRITE_FLAG                      0x01000000 +#define    SURFACE3_INFO__SURF3_READ_FLAG                       0x02000000 +#define    SURFACE3_INFO__SURF3_TILE_MODE_R2__MASK              0x00070000 +#define    SURFACE3_INFO__SURF3_TILE_MODE_R2__SHIFT             16 +#define    SURFACE3_INFO__SURF3_PITCHSEL_R3__MASK               0x00001FFF +#define    SURFACE3_INFO__SURF3_PITCHSEL_R3__SHIFT              0 +#define SURFACE3_LOWER_BOUND                                0x00000B34 +#define    SURFACE3_LOWER_BOUND__SURF_LOWER__MASK               0x0FFFFFFF +#define    SURFACE3_LOWER_BOUND__SURF_LOWER__SHIFT              0 +#define SURFACE3_UPPER_BOUND                                0x00000B38 +#define    SURFACE3_UPPER_BOUND__SURF_UPPER__MASK               0x0FFFFFFF +#define    SURFACE3_UPPER_BOUND__SURF_UPPER__SHIFT              0 +#define SURFACE4_INFO                                       0x00000B4C +#define    SURFACE4_INFO__SURF4_PITCHSEL__MASK                  0x000003FF +#define    SURFACE4_INFO__SURF4_PITCHSEL__SHIFT                 0 +#define    SURFACE4_INFO__SURF4_TILE_MODE__MASK                 0x00030000 +#define    SURFACE4_INFO__SURF4_TILE_MODE__SHIFT                16 +#define    SURFACE4_INFO__SURF4_AP0_SWP__MASK                   0x00300000 +#define    SURFACE4_INFO__SURF4_AP0_SWP__SHIFT                  20 +#define    SURFACE4_INFO__SURF4_AP1_SWP__MASK                   0x00C00000 +#define    SURFACE4_INFO__SURF4_AP1_SWP__SHIFT                  22 +#define    SURFACE4_INFO__SURF4_WRITE_FLAG                      0x01000000 +#define    SURFACE4_INFO__SURF4_READ_FLAG                       0x02000000 +#define    SURFACE4_INFO__SURF4_TILE_MODE_R2__MASK              0x00070000 +#define    SURFACE4_INFO__SURF4_TILE_MODE_R2__SHIFT             16 +#define    SURFACE4_INFO__SURF4_PITCHSEL_R3__MASK               0x00001FFF +#define    SURFACE4_INFO__SURF4_PITCHSEL_R3__SHIFT              0 +#define SURFACE4_LOWER_BOUND                                0x00000B44 +#define    SURFACE4_LOWER_BOUND__SURF_LOWER__MASK               0x0FFFFFFF +#define    SURFACE4_LOWER_BOUND__SURF_LOWER__SHIFT              0 +#define SURFACE4_UPPER_BOUND                                0x00000B48 +#define    SURFACE4_UPPER_BOUND__SURF_UPPER__MASK               0x0FFFFFFF +#define    SURFACE4_UPPER_BOUND__SURF_UPPER__SHIFT              0 +#define SURFACE5_INFO                                       0x00000B5C +#define    SURFACE5_INFO__SURF5_PITCHSEL__MASK                  0x000003FF +#define    SURFACE5_INFO__SURF5_PITCHSEL__SHIFT                 0 +#define    SURFACE5_INFO__SURF5_TILE_MODE__MASK                 0x00030000 +#define    SURFACE5_INFO__SURF5_TILE_MODE__SHIFT                16 +#define    SURFACE5_INFO__SURF5_AP0_SWP__MASK                   0x00300000 +#define    SURFACE5_INFO__SURF5_AP0_SWP__SHIFT                  20 +#define    SURFACE5_INFO__SURF5_AP1_SWP__MASK                   0x00C00000 +#define    SURFACE5_INFO__SURF5_AP1_SWP__SHIFT                  22 +#define    SURFACE5_INFO__SURF5_WRITE_FLAG                      0x01000000 +#define    SURFACE5_INFO__SURF5_READ_FLAG                       0x02000000 +#define    SURFACE5_INFO__SURF5_TILE_MODE_R2__MASK              0x00070000 +#define    SURFACE5_INFO__SURF5_TILE_MODE_R2__SHIFT             16 +#define    SURFACE5_INFO__SURF5_PITCHSEL_R3__MASK               0x00001FFF +#define    SURFACE5_INFO__SURF5_PITCHSEL_R3__SHIFT              0 +#define SURFACE5_LOWER_BOUND                                0x00000B54 +#define    SURFACE5_LOWER_BOUND__SURF_LOWER__MASK               0x0FFFFFFF +#define    SURFACE5_LOWER_BOUND__SURF_LOWER__SHIFT              0 +#define SURFACE5_UPPER_BOUND                                0x00000B58 +#define    SURFACE5_UPPER_BOUND__SURF_UPPER__MASK               0x0FFFFFFF +#define    SURFACE5_UPPER_BOUND__SURF_UPPER__SHIFT              0 +#define SURFACE6_INFO                                       0x00000B6C +#define    SURFACE6_INFO__SURF6_PITCHSEL__MASK                  0x000003FF +#define    SURFACE6_INFO__SURF6_PITCHSEL__SHIFT                 0 +#define    SURFACE6_INFO__SURF6_TILE_MODE__MASK                 0x00030000 +#define    SURFACE6_INFO__SURF6_TILE_MODE__SHIFT                16 +#define    SURFACE6_INFO__SURF6_AP0_SWP__MASK                   0x00300000 +#define    SURFACE6_INFO__SURF6_AP0_SWP__SHIFT                  20 +#define    SURFACE6_INFO__SURF6_AP1_SWP__MASK                   0x00C00000 +#define    SURFACE6_INFO__SURF6_AP1_SWP__SHIFT                  22 +#define    SURFACE6_INFO__SURF6_WRITE_FLAG                      0x01000000 +#define    SURFACE6_INFO__SURF6_READ_FLAG                       0x02000000 +#define    SURFACE6_INFO__SURF6_TILE_MODE_R2__MASK              0x00070000 +#define    SURFACE6_INFO__SURF6_TILE_MODE_R2__SHIFT             16 +#define    SURFACE6_INFO__SURF6_PITCHSEL_R3__MASK               0x00001FFF +#define    SURFACE6_INFO__SURF6_PITCHSEL_R3__SHIFT              0 +#define SURFACE6_LOWER_BOUND                                0x00000B64 +#define    SURFACE6_LOWER_BOUND__SURF_LOWER__MASK               0x0FFFFFFF +#define    SURFACE6_LOWER_BOUND__SURF_LOWER__SHIFT              0 +#define SURFACE6_UPPER_BOUND                                0x00000B68 +#define    SURFACE6_UPPER_BOUND__SURF_UPPER__MASK               0x0FFFFFFF +#define    SURFACE6_UPPER_BOUND__SURF_UPPER__SHIFT              0 +#define SURFACE7_INFO                                       0x00000B7C +#define    SURFACE7_INFO__SURF7_PITCHSEL__MASK                  0x000003FF +#define    SURFACE7_INFO__SURF7_PITCHSEL__SHIFT                 0 +#define    SURFACE7_INFO__SURF7_TILE_MODE__MASK                 0x00030000 +#define    SURFACE7_INFO__SURF7_TILE_MODE__SHIFT                16 +#define    SURFACE7_INFO__SURF7_AP0_SWP__MASK                   0x00300000 +#define    SURFACE7_INFO__SURF7_AP0_SWP__SHIFT                  20 +#define    SURFACE7_INFO__SURF7_AP1_SWP__MASK                   0x00C00000 +#define    SURFACE7_INFO__SURF7_AP1_SWP__SHIFT                  22 +#define    SURFACE7_INFO__SURF7_WRITE_FLAG                      0x01000000 +#define    SURFACE7_INFO__SURF7_READ_FLAG                       0x02000000 +#define    SURFACE7_INFO__SURF7_TILE_MODE_R2__MASK              0x00070000 +#define    SURFACE7_INFO__SURF7_TILE_MODE_R2__SHIFT             16 +#define    SURFACE7_INFO__SURF7_PITCHSEL_R3__MASK               0x00001FFF +#define    SURFACE7_INFO__SURF7_PITCHSEL_R3__SHIFT              0 +#define SURFACE7_LOWER_BOUND                                0x00000B74 +#define    SURFACE7_LOWER_BOUND__SURF_LOWER__MASK               0x0FFFFFFF +#define    SURFACE7_LOWER_BOUND__SURF_LOWER__SHIFT              0 +#define SURFACE7_UPPER_BOUND                                0x00000B78 +#define    SURFACE7_UPPER_BOUND__SURF_UPPER__MASK               0x0FFFFFFF +#define    SURFACE7_UPPER_BOUND__SURF_UPPER__SHIFT              0 +#define ISYNC_CNTL                                          0x00001724 +#define    ISYNC_CNTL__ISYNC_ANY2D_IDLE3D                       0x00000001 +#define    ISYNC_CNTL__ISYNC_ANY3D_IDLE2D                       0x00000002 +#define    ISYNC_CNTL__ISYNC_TRIG2D_IDLE3D                      0x00000004 +#define    ISYNC_CNTL__ISYNC_TRIG3D_IDLE2D                      0x00000008 +#define    ISYNC_CNTL__ISYNC_WAIT_IDLEGUI                       0x00000010 +#define    ISYNC_CNTL__ISYNC_CPSCRATCH_IDLEGUI                  0x00000020 +#define RBBM_STATUS                                         0x00000E40 +#define    RBBM_STATUS__CMDFIFO_AVAIL__MASK                     0x0000007F +#define    RBBM_STATUS__CMDFIFO_AVAIL__SHIFT                    0 +#define    RBBM_STATUS__HIRQ_ON_RBB                             0x00000100 +#define    RBBM_STATUS__CPRQ_ON_RBB                             0x00000200 +#define    RBBM_STATUS__CFRQ_ON_RBB                             0x00000400 +#define    RBBM_STATUS__HIRQ_IN_RTBUF                           0x00000800 +#define    RBBM_STATUS__CPRQ_IN_RTBUF                           0x00001000 +#define    RBBM_STATUS__CFRQ_IN_RTBUF                           0x00002000 +#define    RBBM_STATUS__CF_PIPE_BUSY                            0x00004000 +#define    RBBM_STATUS__ENG_EV_BUSY                             0x00008000 +#define    RBBM_STATUS__CP_CMDSTRM_BUSY                         0x00010000 +#define    RBBM_STATUS__E2_BUSY                                 0x00020000 +#define    RBBM_STATUS__RB2D_BUSY                               0x00040000 +#define    RBBM_STATUS__RB3D_BUSY                               0x00080000 +#define    RBBM_STATUS__SE_BUSY                                 0x00100000 +#define    RBBM_STATUS__RE_BUSY                                 0x00200000 +#define    RBBM_STATUS__TAM_BUSY                                0x00400000 +#define    RBBM_STATUS__TDM_BUSY                                0x00800000 +#define    RBBM_STATUS__PB_BUSY                                 0x01000000 +#define    RBBM_STATUS__GUI_ACTIVE                              0x80000000 +#define    RBBM_STATUS__VAP_BUSY                                0x00100000 +#define    RBBM_STATUS__TIM_BUSY                                0x02000000 +#define    RBBM_STATUS__GA_BUSY                                 0x04000000 +#define    RBBM_STATUS__CBA2D_BUSY                              0x08000000 +#define RBBM_SOFT_RESET                                     0x000000F0 +#define    RBBM_SOFT_RESET__SOFT_RESET_CP                       0x00000001 +#define    RBBM_SOFT_RESET__SOFT_RESET_HI                       0x00000002 +#define    RBBM_SOFT_RESET__SOFT_RESET_SE                       0x00000004 +#define    RBBM_SOFT_RESET__SOFT_RESET_RE                       0x00000008 +#define    RBBM_SOFT_RESET__SOFT_RESET_PP                       0x00000010 +#define    RBBM_SOFT_RESET__SOFT_RESET_E2                       0x00000020 +#define    RBBM_SOFT_RESET__SOFT_RESET_RB                       0x00000040 +#define    RBBM_SOFT_RESET__SOFT_RESET_HDP                      0x00000080 +#define    RBBM_SOFT_RESET__SOFT_RESET_MC                       0x00000100 +#define    RBBM_SOFT_RESET__SOFT_RESET_AIC                      0x00000200 +#define    RBBM_SOFT_RESET__SOFT_RESET_VIP                      0x00000400 +#define    RBBM_SOFT_RESET__SOFT_RESET_DISP                     0x00000800 +#define    RBBM_SOFT_RESET__SOFT_RESET_CG                       0x00001000 +#define    RBBM_SOFT_RESET__SOFT_RESET_VAP                      0x00000004 +#define    RBBM_SOFT_RESET__SOFT_RESET_GA                       0x00002000 +#define    RBBM_SOFT_RESET__SOFT_RESET_IDCT                     0x00004000 +#define WAIT_UNTIL                                          0x00001720 +#define    WAIT_UNTIL__WAIT_CRTC_PFLIP                          0x00000001 +#define    WAIT_UNTIL__WAIT_RE_CRTC_VLINE                       0x00000002 +#define    WAIT_UNTIL__WAIT_FE_CRTC_VLINE                       0x00000004 +#define    WAIT_UNTIL__WAIT_CRTC_VLINE                          0x00000008 +#define    WAIT_UNTIL__WAIT_DMA_VIPH0_IDLE                      0x00000010 +#define    WAIT_UNTIL__WAIT_DMA_VIPH1_IDLE                      0x00000020 +#define    WAIT_UNTIL__WAIT_DMA_VIPH2_IDLE                      0x00000040 +#define    WAIT_UNTIL__WAIT_DMA_VIPH3_IDLE                      0x00000080 +#define    WAIT_UNTIL__WAIT_DMA_VID_IDLE                        0x00000100 +#define    WAIT_UNTIL__WAIT_DMA_GUI_IDLE                        0x00000200 +#define    WAIT_UNTIL__WAIT_CMDFIFO                             0x00000400 +#define    WAIT_UNTIL__WAIT_OV0_FLIP                            0x00000800 +#define    WAIT_UNTIL__WAIT_OV0_SLICEDONE                       0x00001000 +#define    WAIT_UNTIL__WAIT_2D_IDLE                             0x00004000 +#define    WAIT_UNTIL__WAIT_3D_IDLE                             0x00008000 +#define    WAIT_UNTIL__WAIT_2D_IDLECLEAN                        0x00010000 +#define    WAIT_UNTIL__WAIT_3D_IDLECLEAN                        0x00020000 +#define    WAIT_UNTIL__WAIT_HOST_IDLECLEAN                      0x00040000 +#define    WAIT_UNTIL__WAIT_EXTERN_SIG                          0x00080000 +#define    WAIT_UNTIL__CMDFIFO_ENTRIES__MASK                    0x07F00000 +#define    WAIT_UNTIL__CMDFIFO_ENTRIES__SHIFT                   20 +#define    WAIT_UNTIL__WAIT_BOTH_CRTC_PFLIP                     0x40000000 +#define    WAIT_UNTIL__ENG_DISPLAY_SELECT                       0x80000000 +#define    WAIT_UNTIL__WAIT_AGP_FLUSH                           0x00002000 +#define    WAIT_UNTIL__WAIT_IDCT_SEMAPHORE                      0x08000000 +#define    WAIT_UNTIL__WAIT_VAP_IDLE                            0x10000000 +#define DISPLAY_BASE_ADDR                                   0x0000023C +#define    DISPLAY_BASE_ADDR__DISPLAY_BASE_ADDR__MASK           0xFFFFFFFF +#define    DISPLAY_BASE_ADDR__DISPLAY_BASE_ADDR__SHIFT          0 +#define CRTC2_DISPLAY_BASE_ADDR                             0x0000033C +#define    CRTC2_DISPLAY_BASE_ADDR__CRTC2_DISPLAY_BASE_ADDR__MASK 0xFFFFFFFF +#define    CRTC2_DISPLAY_BASE_ADDR__CRTC2_DISPLAY_BASE_ADDR__SHIFT 0 +#define AIC_CTRL                                            0x000001D0 +#define    AIC_CTRL__TRANSLATE_EN                               0x00000001 +#define    AIC_CTRL__HW_0_DEBUG                                 0x00000002 +#define    AIC_CTRL__HW_1_DEBUG                                 0x00000004 +#define    AIC_CTRL__HW_2_DEBUG                                 0x00000008 +#define    AIC_CTRL__HW_3_DEBUG                                 0x00000010 +#define    AIC_CTRL__HW_4_DEBUG                                 0x00000020 +#define    AIC_CTRL__HW_5_DEBUG                                 0x00000040 +#define    AIC_CTRL__HW_6_DEBUG                                 0x00000080 +#define    AIC_CTRL__HW_7_DEBUG                                 0x00000100 +#define    AIC_CTRL__HW_8_DEBUG                                 0x00000200 +#define    AIC_CTRL__HW_9_DEBUG                                 0x00000400 +#define    AIC_CTRL__HW_A_DEBUG                                 0x00000800 +#define    AIC_CTRL__HW_B_DEBUG                                 0x00001000 +#define    AIC_CTRL__HW_C_DEBUG                                 0x00002000 +#define    AIC_CTRL__HW_D_DEBUG                                 0x00004000 +#define    AIC_CTRL__HW_E_DEBUG                                 0x00008000 +#define    AIC_CTRL__HW_F_DEBUG                                 0x00010000 +#define    AIC_CTRL__HW_10_DEBUG                                0x00020000 +#define    AIC_CTRL__HW_11_DEBUG                                0x00040000 +#define    AIC_CTRL__HW_12_DEBUG                                0x00080000 +#define    AIC_CTRL__HW_13_DEBUG                                0x00100000 +#define    AIC_CTRL__HW_14_DEBUG                                0x00200000 +#define    AIC_CTRL__HW_15_DEBUG                                0x00400000 +#define    AIC_CTRL__HW_16_DEBUG                                0x00800000 +#define    AIC_CTRL__HW_17_DEBUG                                0x01000000 +#define    AIC_CTRL__HW_18_DEBUG                                0x02000000 +#define    AIC_CTRL__HW_19_DEBUG                                0x04000000 +#define    AIC_CTRL__HW_1A_DEBUG                                0x08000000 +#define    AIC_CTRL__HW_1B_DEBUG                                0x10000000 +#define    AIC_CTRL__HW_1C_DEBUG                                0x20000000 +#define    AIC_CTRL__HW_1D_DEBUG                                0x40000000 +#define    AIC_CTRL__HW_1E_DEBUG                                0x80000000 +#define    AIC_CTRL__DIS_OUT_OF_PCI_GART_ACCESS                 0x00000002 +#define    AIC_CTRL__HW_02_DEBUG                                0x00000004 +#define    AIC_CTRL__HW_03_DEBUG                                0x00000008 +#define    AIC_CTRL__TEST_RBF_DIV_VAL__MASK                     0x00000070 +#define    AIC_CTRL__TEST_RBF_DIV_VAL__SHIFT                    4 +#define    AIC_CTRL__TEST_RBF_EN                                0x00000080 +#define    AIC_CTRL__HW_08_DEBUG                                0x00000100 +#define    AIC_CTRL__HW_09_DEBUG                                0x00000200 +#define    AIC_CTRL__HW_10_DEBUG_R3                             0x00000400 +#define    AIC_CTRL__HW_11_DEBUG_R3                             0x00000800 +#define    AIC_CTRL__HW_12_DEBUG_R3                             0x00001000 +#define    AIC_CTRL__HW_13_DEBUG_R3                             0x00002000 +#define    AIC_CTRL__HW_14_DEBUG_R3                             0x00004000 +#define    AIC_CTRL__HW_15_DEBUG_R3                             0x00008000 +#define    AIC_CTRL__HW_16_DEBUG_R3                             0x00010000 +#define    AIC_CTRL__HW_17_DEBUG_R3                             0x00020000 +#define    AIC_CTRL__HW_18_DEBUG_R3                             0x00040000 +#define    AIC_CTRL__HW_19_DEBUG_R3                             0x00080000 +#define    AIC_CTRL__HW_20_DEBUG                                0x00100000 +#define    AIC_CTRL__HW_21_DEBUG                                0x00200000 +#define    AIC_CTRL__HW_22_DEBUG                                0x00400000 +#define    AIC_CTRL__HW_23_DEBUG                                0x00800000 +#define    AIC_CTRL__HW_24_DEBUG                                0x01000000 +#define    AIC_CTRL__HW_25_DEBUG                                0x02000000 +#define    AIC_CTRL__HW_26_DEBUG                                0x04000000 +#define    AIC_CTRL__HW_27_DEBUG                                0x08000000 +#define    AIC_CTRL__HW_28_DEBUG                                0x10000000 +#define    AIC_CTRL__HW_29_DEBUG                                0x20000000 +#define    AIC_CTRL__HW_30_DEBUG                                0x40000000 +#define    AIC_CTRL__HW_31_DEBUG                                0x80000000 +#define BUS_CNTL                                            0x00000030 +#define    BUS_CNTL__BUS_DBL_RESYNC                             0x00000001 +#define    BUS_CNTL__BUS_MSTR_RESET                             0x00000002 +#define    BUS_CNTL__BUS_FLUSH_BUF                              0x00000004 +#define    BUS_CNTL__BUS_STOP_REQ_DIS                           0x00000008 +#define    BUS_CNTL__BUS_READ_COMBINE_EN                        0x00000010 +#define    BUS_CNTL__BUS_WRT_COMBINE_EN                         0x00000020 +#define    BUS_CNTL__BUS_MASTER_DIS                             0x00000040 +#define    BUS_CNTL__BIOS_ROM_WRT_EN                            0x00000080 +#define    BUS_CNTL__BUS_PREFETCH_MODE__MASK                    0x00000300 +#define    BUS_CNTL__BUS_PREFETCH_MODE__SHIFT                   8 +#define    BUS_CNTL__BUS_VGA_PREFETCH_EN                        0x00000400 +#define    BUS_CNTL__BUS_SGL_READ_DISABLE                       0x00000800 +#define    BUS_CNTL__BIOS_DIS_ROM                               0x00001000 +#define    BUS_CNTL__BUS_PCI_READ_RETRY_EN                      0x00002000 +#define    BUS_CNTL__BUS_AGP_AD_STEPPING_EN                     0x00004000 +#define    BUS_CNTL__BUS_PCI_WRT_RETRY_EN                       0x00008000 +#define    BUS_CNTL__BUS_RETRY_WS__MASK                         0x000F0000 +#define    BUS_CNTL__BUS_RETRY_WS__SHIFT                        16 +#define    BUS_CNTL__BUS_MSTR_RD_MULT                           0x00100000 +#define    BUS_CNTL__BUS_MSTR_RD_LINE                           0x00200000 +#define    BUS_CNTL__BUS_SUSPEND                                0x00400000 +#define    BUS_CNTL__LAT_16X                                    0x00800000 +#define    BUS_CNTL__BUS_RD_DISCARD_EN                          0x01000000 +#define    BUS_CNTL__ENFRCWRDY                                  0x02000000 +#define    BUS_CNTL__BUS_MSTR_WS                                0x04000000 +#define    BUS_CNTL__BUS_PARKING_DIS                            0x08000000 +#define    BUS_CNTL__BUS_MSTR_DISCONNECT_EN                     0x10000000 +#define    BUS_CNTL__SERR_EN                                    0x20000000 +#define    BUS_CNTL__BUS_READ_BURST                             0x40000000 +#define    BUS_CNTL__BUS_RDY_READ_DLY                           0x80000000 +#define    BUS_CNTL__BUS_PM4_READ_COMBINE_EN                    0x00000010 +#define    BUS_CNTL__BM_DAC_CRIPPLE                             0x00000100 +#define    BUS_CNTL__BUS_NON_PM4_READ_COMBINE_EN                0x00000200 +#define    BUS_CNTL__BUS_XFERD_DISCARD_EN                       0x00000400 +#define MC_STATUS                                           0x00000150 +#define    MC_STATUS__MEM_PWRUP_COMPL_A                         0x00000001 +#define    MC_STATUS__MEM_PWRUP_COMPL_B                         0x00000002 +#define    MC_STATUS__MC_IDLE                                   0x00000004 +#define    MC_STATUS__SPARE__MASK                               0x0000FFF8 +#define    MC_STATUS__SPARE__SHIFT                              3 +#define    MC_STATUS__IMP_N_VALUE_R_BACK__MASK                  0x00000078 +#define    MC_STATUS__IMP_N_VALUE_R_BACK__SHIFT                 3 +#define    MC_STATUS__IMP_P_VALUE_R_BACK__MASK                  0x00000780 +#define    MC_STATUS__IMP_P_VALUE_R_BACK__SHIFT                 7 +#define    MC_STATUS__TEST_OUT_R_BACK                           0x00000800 +#define    MC_STATUS__DUMMY_OUT_R_BACK                          0x00001000 +#define    MC_STATUS__IMP_N_VALUE_A_R_BACK__MASK                0x0001E000 +#define    MC_STATUS__IMP_N_VALUE_A_R_BACK__SHIFT               13 +#define    MC_STATUS__IMP_P_VALUE_A_R_BACK__MASK                0x001E0000 +#define    MC_STATUS__IMP_P_VALUE_A_R_BACK__SHIFT               17 +#define    MC_STATUS__IMP_N_VALUE_CK_R_BACK__MASK               0x01E00000 +#define    MC_STATUS__IMP_N_VALUE_CK_R_BACK__SHIFT              21 +#define    MC_STATUS__IMP_P_VALUE_CK_R_BACK__MASK               0x1E000000 +#define    MC_STATUS__IMP_P_VALUE_CK_R_BACK__SHIFT              25 +#define    MC_STATUS__MEM_PWRUP_COMPL_C                         0x00000004 +#define    MC_STATUS__MEM_PWRUP_COMPL_D                         0x00000008 +#define    MC_STATUS__MC_IDLE_R3                                0x00000010 +#define    MC_STATUS__IMP_CAL_COUNT__MASK                       0x0000F000 +#define    MC_STATUS__IMP_CAL_COUNT__SHIFT                      12 +#define OV0_SCALE_CNTL                                      0x00000420 +#define    OV0_SCALE_CNTL__OV0_NO_READ_BEHIND_SCAN              0x00000002 +#define    OV0_SCALE_CNTL__OV0_HORZ_PICK_NEAREST                0x00000004 +#define    OV0_SCALE_CNTL__OV0_VERT_PICK_NEAREST                0x00000008 +#define    OV0_SCALE_CNTL__OV0_SIGNED_UV                        0x00000010 +#define    OV0_SCALE_CNTL__OV0_GAMMA_SEL__MASK                  0x000000E0 +#define    OV0_SCALE_CNTL__OV0_GAMMA_SEL__SHIFT                 5 +#define    OV0_SCALE_CNTL__OV0_SURFACE_FORMAT__MASK             0x00000F00 +#define    OV0_SCALE_CNTL__OV0_SURFACE_FORMAT__SHIFT            8 +#define    OV0_SURFACE_FORMAT__RESERVED0                            0x0 +#define    OV0_SURFACE_FORMAT__RESERVED1                            0x100 +#define    OV0_SURFACE_FORMAT__RESERVED2                            0x200 +#define    OV0_SURFACE_FORMAT__16BPP_ARGB                           0x300 +#define    OV0_SURFACE_FORMAT__16BPP_RGB                            0x400 +#define    OV0_SURFACE_FORMAT__RESERVED5                            0x500 +#define    OV0_SURFACE_FORMAT__32BPP_ARGB                           0x600 +#define    OV0_SURFACE_FORMAT__RESERVED7                            0x700 +#define    OV0_SURFACE_FORMAT__RESERVED8                            0x800 +#define    OV0_SURFACE_FORMAT__IF09_PLANAR                          0x900 +#define    OV0_SURFACE_FORMAT__YV12_PLANAR                          0xA00 +#define    OV0_SURFACE_FORMAT__YUY2_PACKED                          0xB00 +#define    OV0_SURFACE_FORMAT__UYVY_PACKED                          0xC00 +#define    OV0_SURFACE_FORMAT__YYUV9_PLANAR                         0xD00 +#define    OV0_SURFACE_FORMAT__YYUV12_PLANAR                        0xE00 +#define    OV0_SURFACE_FORMAT__RESERVED15                           0xF00 +#define    OV0_SCALE_CNTL__OV0_ADAPTIVE_DEINT                   0x00001000 +#define    OV0_SCALE_CNTL__OV0_CRTC_SEL                         0x00004000 +#define    OV0_SCALE_CNTL__OV0_BURST_PER_PLANE__MASK            0x007F0000 +#define    OV0_SCALE_CNTL__OV0_BURST_PER_PLANE__SHIFT           16 +#define    OV0_SCALE_CNTL__OV0_DOUBLE_BUFFER_REGS               0x01000000 +#define    OV0_SCALE_CNTL__OV0_BANDWIDTH                        0x04000000 +#define    OV0_SCALE_CNTL__OV0_LIN_TRANS_BYPASS                 0x10000000 +#define    OV0_SCALE_CNTL__OV0_INT_EMU                          0x20000000 +#define    OV0_SCALE_CNTL__OV0_OVERLAY_EN__MASK                 0x40000000 +#define    OV0_SCALE_CNTL__OV0_OVERLAY_EN__SHIFT                30 +#define    OV0_OVERLAY_EN__ENABLE                                   0x40000000 +#define    OV0_SCALE_CNTL__OV0_SOFT_RESET__MASK                 0x80000000 +#define    OV0_SCALE_CNTL__OV0_SOFT_RESET__SHIFT                31 +#define    OV0_SOFT_RESET__RESET                                    0x80000000 +#define    OV0_SCALE_CNTL__OV0_TEMPORAL_DEINT                   0x00002000 +#define    OV0_SCALE_CNTL__OV0_PULLDOWN_ON_P1_ONLY              0x00008000 +#define    OV0_SCALE_CNTL__OV0_FULL_BYPASS                      0x00000020 +#define    OV0_SCALE_CNTL__OV0_DYNAMIC_EXT                      0x00000040 +#define    OV0_SCALE_CNTL__OV0_RGB30_ON                         0x00000080 +#define CRTC2_GEN_CNTL                                      0x000003F8 +#define    CRTC2_GEN_CNTL__CRTC2_DBL_SCAN_EN                    0x00000001 +#define    CRTC2_GEN_CNTL__CRTC2_INTERLACE_EN                   0x00000002 +#define    CRTC2_GEN_CNTL__CRTC2_SYNC_TRISTATE                  0x00000010 +#define    CRTC2_GEN_CNTL__CRTC2_HSYNC_TRISTATE                 0x00000020 +#define    CRTC2_GEN_CNTL__CRTC2_VSYNC_TRISTATE                 0x00000040 +#define    CRTC2_GEN_CNTL__CRT2_ON                              0x00000080 +#define    CRTC2_GEN_CNTL__CRTC2_PIX_WIDTH__MASK                0x00000F00 +#define    CRTC2_GEN_CNTL__CRTC2_PIX_WIDTH__SHIFT               8 +#define    CRTC2_GEN_CNTL__CRTC2_ICON_EN                        0x00008000 +#define    CRTC2_GEN_CNTL__CRTC2_CUR_EN                         0x00010000 +#define    CRTC2_GEN_CNTL__CRTC2_CUR_MODE__MASK                 0x00700000 +#define    CRTC2_GEN_CNTL__CRTC2_CUR_MODE__SHIFT                20 +#define    CRTC2_GEN_CNTL__CRTC2_DISPLAY_DIS                    0x00800000 +#define    CRTC2_GEN_CNTL__CRTC2_EN                             0x02000000 +#define    CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B                  0x04000000 +#define    CRTC2_GEN_CNTL__CRTC2_C_SYNC_EN                      0x08000000 +#define    CRTC2_GEN_CNTL__CRTC2_HSYNC_DIS                      0x10000000 +#define    CRTC2_GEN_CNTL__CRTC2_VSYNC_DIS                      0x20000000 +#define    CRTC2_GEN_CNTL__CRTC2_MODE9_COLOR_ORDER              0x00001000 +#define    CRTC2_GEN_CNTL__CRTC2_FIX_VSYNC_EDGE_POSITION_EN     0x40000000 +#define CRTC2_OFFSET                                        0x00000324 +#define    CRTC2_OFFSET__CRTC2_OFFSET__MASK                     0x07FFFFFF +#define    CRTC2_OFFSET__CRTC2_OFFSET__SHIFT                    0 +#define    CRTC2_OFFSET__CRTC2_GUI_TRIG_OFFSET                  0x40000000 +#define    CRTC2_OFFSET__CRTC2_OFFSET_LOCK                      0x80000000 +#define    CRTC2_OFFSET__CRTC2_OFFSET_R3__MASK                  0x0FFFFFFF +#define    CRTC2_OFFSET__CRTC2_OFFSET_R3__SHIFT                 0 +#define CRTC2_OFFSET_CNTL                                   0x00000328 +#define    CRTC2_OFFSET_CNTL__CRTC2_TILE_LINE__MASK             0x0000000F +#define    CRTC2_OFFSET_CNTL__CRTC2_TILE_LINE__SHIFT            0 +#define    CRTC2_OFFSET_CNTL__CRTC2_TILE_EN                     0x00008000 +#define    CRTC2_OFFSET_CNTL__CRTC2_OFFSET_FLIP_CNTL            0x00010000 +#define    CRTC2_OFFSET_CNTL__CRTC2_GUI_TRIG_OFFSET_LEFT_EN     0x10000000 +#define    CRTC2_OFFSET_CNTL__CRTC2_GUI_TRIG_OFFSET             0x40000000 +#define    CRTC2_OFFSET_CNTL__CRTC2_OFFSET_LOCK                 0x80000000 +#define    CRTC2_OFFSET_CNTL__CRTC2_TILE_LINE_RIGHT__MASK       0x000000F0 +#define    CRTC2_OFFSET_CNTL__CRTC2_TILE_LINE_RIGHT__SHIFT      4 +#define    CRTC2_OFFSET_CNTL__CRTC2_TILE_EN_RIGHT               0x00004000 +#define    CRTC2_OFFSET_CNTL__CRTC2_STEREO_OFFSET_EN            0x00020000 +#define    CRTC2_OFFSET_CNTL__CRTC2_STEREO_SYNC_EN__MASK        0x000C0000 +#define    CRTC2_OFFSET_CNTL__CRTC2_STEREO_SYNC_EN__SHIFT       18 +#define    CRTC2_OFFSET_CNTL__CRTC2_STEREO_SYNC                 0x00200000 +#define    CRTC2_OFFSET_CNTL__CRTC2_GUI_TRIG_OFFSET_RIGHT_EN    0x20000000 +#define    CRTC2_OFFSET_CNTL__CRTC2_X_Y_MODE_EN_RIGHT           0x00000100 +#define    CRTC2_OFFSET_CNTL__CRTC2_X_Y_MODE_EN                 0x00000200 +#define    CRTC2_OFFSET_CNTL__CRTC2_MICRO_TILE_EN_RIGHT         0x00001000 +#define    CRTC2_OFFSET_CNTL__CRTC2_MICRO_TILE_EN               0x00002000 +#define    CRTC2_OFFSET_CNTL__CRTC2_MACRO_TILE_EN_RIGHT         0x00004000 +#define    CRTC2_OFFSET_CNTL__CRTC2_MACRO_TILE_EN               0x00008000 +#define CUR_OFFSET                                          0x00000260 +#define    CUR_OFFSET__CUR_OFFSET__MASK                         0x07FFFFFF +#define    CUR_OFFSET__CUR_OFFSET__SHIFT                        0 +#define    CUR_OFFSET__CUR_LOCK                                 0x80000000 +#define CUR2_OFFSET                                         0x00000360 +#define    CUR2_OFFSET__CUR2_OFFSET__MASK                       0x07FFFFFF +#define    CUR2_OFFSET__CUR2_OFFSET__SHIFT                      0 +#define    CUR2_OFFSET__CUR2_LOCK                               0x80000000 +#define HOST_PATH_CNTL                                      0x00000130 +#define    HOST_PATH_CNTL__HDP_APER_CNTL                        0x00800000 +#define    HOST_PATH_CNTL__HP_LIN_RD_CACHE_DIS                  0x01000000 +#define    HOST_PATH_CNTL__HP_RBBM_LOCK_DIS                     0x02000000 +#define    HOST_PATH_CNTL__HDP_SOFT_RESET                       0x04000000 +#define    HOST_PATH_CNTL__HDP_WRITE_COMBINER_TIMEOUT__MASK     0x70000000 +#define    HOST_PATH_CNTL__HDP_WRITE_COMBINER_TIMEOUT__SHIFT    28 +#define    HOST_PATH_CNTL__HP_TEST_RST_CNTL                     0x80000000 +#define    HOST_PATH_CNTL__HDP_WRITE_THROUGH_CACHE_DIS          0x00400000 +#define    HOST_PATH_CNTL__HDP_READ_BUFFER_INVALIDATE           0x08000000 +#define DST_PITCH_OFFSET                                    0x0000142C +#define    DST_PITCH_OFFSET__DST_OFFSET__MASK                   0x003FFFFF +#define    DST_PITCH_OFFSET__DST_OFFSET__SHIFT                  0 +#define    DST_PITCH_OFFSET__DST_PITCH__MASK                    0x3FC00000 +#define    DST_PITCH_OFFSET__DST_PITCH__SHIFT                   22 +#define    DST_PITCH_OFFSET__DST_TILE__MASK                     0xC0000000 +#define    DST_PITCH_OFFSET__DST_TILE__SHIFT                    30 +#define    DST_TILE__MACRO                                          0x1 +#define    DST_TILE__MICRO                                          0x2 +#define SRC_PITCH_OFFSET                                    0x00001428 +#define    SRC_PITCH_OFFSET__SRC_OFFSET__MASK                   0x003FFFFF +#define    SRC_PITCH_OFFSET__SRC_OFFSET__SHIFT                  0 +#define    SRC_PITCH_OFFSET__SRC_PITCH__MASK                    0x3FC00000 +#define    SRC_PITCH_OFFSET__SRC_PITCH__SHIFT                   22 +#define    SRC_PITCH_OFFSET__SRC_TILE                           0x40000000 +#define DEFAULT_SC_BOTTOM_RIGHT                             0x000016E8 +#define    DEFAULT_SC_BOTTOM_RIGHT__DEFAULT_SC_RIGHT__MASK      0x00003FFF +#define    DEFAULT_SC_BOTTOM_RIGHT__DEFAULT_SC_RIGHT__SHIFT     0 +#define    DEFAULT_SC_BOTTOM_RIGHT__DEFAULT_SC_BOTTOM__MASK     0x3FFF0000 +#define    DEFAULT_SC_BOTTOM_RIGHT__DEFAULT_SC_BOTTOM__SHIFT    16 +#define DEFAULT2_SC_BOTTOM_RIGHT                            0x000016DC +#define    DEFAULT2_SC_BOTTOM_RIGHT__DEFAULT_SC_RIGHT__MASK     0x00003FFF +#define    DEFAULT2_SC_BOTTOM_RIGHT__DEFAULT_SC_RIGHT__SHIFT    0 +#define    DEFAULT2_SC_BOTTOM_RIGHT__DEFAULT_SC_BOTTOM__MASK    0x3FFF0000 +#define    DEFAULT2_SC_BOTTOM_RIGHT__DEFAULT_SC_BOTTOM__SHIFT   16 +#define DP_DATATYPE                                         0x000016C4 +#define    DP_DATATYPE__DP_DST_DATATYPE__MASK                   0x0000000F +#define    DP_DATATYPE__DP_DST_DATATYPE__SHIFT                  0 +#define    DP_DATATYPE__DP_BRUSH_DATATYPE__MASK                 0x00000F00 +#define    DP_DATATYPE__DP_BRUSH_DATATYPE__SHIFT                8 +#define    DP_DATATYPE__DP_SRC_DATATYPE__MASK                   0x00070000 +#define    DP_DATATYPE__DP_SRC_DATATYPE__SHIFT                  16 +#define    DP_DATATYPE__DP_BYTE_PIX_ORDER                       0x40000000 +#define DP_GUI_MASTER_CNTL                                  0x0000146C +#define    DP_GUI_MASTER_CNTL__GMC_SRC_PITCH_OFFSET_CNTL        0x00000001 +#define    DP_GUI_MASTER_CNTL__GMC_DST_PITCH_OFFSET_CNTL        0x00000002 +#define    DP_GUI_MASTER_CNTL__GMC_SRC_CLIPPING                 0x00000004 +#define    DP_GUI_MASTER_CNTL__GMC_DST_CLIPPING                 0x00000008 +#define    DP_GUI_MASTER_CNTL__GMC_BRUSH_DATATYPE__MASK         0x000000F0 +#define    DP_GUI_MASTER_CNTL__GMC_BRUSH_DATATYPE__SHIFT        4 +#define    GMC_BRUSH_DATATYPE__8X8_MONO_FG_BG                       0x0 +#define    GMC_BRUSH_DATATYPE__8X8_MONO_FG                          0x1 +#define    GMC_BRUSH_DATATYPE__32X1_MONO_LINE_FG_BG                 0x6 +#define    GMC_BRUSH_DATATYPE__32X1_MONO_LINE_FG                    0x7 +#define    GMC_BRUSH_DATATYPE__8X8_COLOR                            0xA +#define    GMC_BRUSH_DATATYPE__SOLID_COLOR_FG                       0xD +#define    GMC_BRUSH_DATATYPE__SOLID_COLOR_RESERVED                 0xF +#define    GMC_BRUSH_DATATYPE__SOLID                                0xD0 +#define    GMC_BRUSH_DATATYPE__MONO8x8                              0x0 +#define    GMC_BRUSH_DATATYPE__COLOR8x8                             0xA0 +#define    DP_GUI_MASTER_CNTL__GMC_DST_DATATYPE__MASK           0x00000F00 +#define    DP_GUI_MASTER_CNTL__GMC_DST_DATATYPE__SHIFT          8 +#define    GMC_DST_DATATYPE__8BPP_CLUT                              0x2 +#define    GMC_DST_DATATYPE__16BPP_1555                             0x3 +#define    GMC_DST_DATATYPE__16BPP_565                              0x4 +#define    GMC_DST_DATATYPE__32BPP_8888                             0x6 +#define    GMC_DST_DATATYPE__CI8                                    0x200 +#define    GMC_DST_DATATYPE__RGB16_1555                             0x300 +#define    GMC_DST_DATATYPE__RGB16_565                              0x400 +#define    GMC_DST_DATATYPE__RGB32                                  0x600 +#define    DP_GUI_MASTER_CNTL__GMC_SRC_DATATYPE__MASK           0x00003000 +#define    DP_GUI_MASTER_CNTL__GMC_SRC_DATATYPE__SHIFT          12 +#define    GMC_SRC_DATATYPE__BUILD(x)                               0x0 +#define    GMC_SRC_DATATYPE__MONO_OPAQUE                            0x0 +#define    GMC_SRC_DATATYPE__MONO_TRANSPARENT                       0x0 +#define    GMC_SRC_DATATYPE__SAME_AS_DST                            0x0 +#define    GMC_SRC_DATATYPE__8BPP_CLUT_XLAT                         0x0 +#define    GMC_SRC_DATATYPE__32BPP_CLUT_XLAT                        0x0 +#define    GMC_SRC_DATATYPE__MONO_FG_BG                             0x0 +#define    GMC_SRC_DATATYPE__MONO_FG                                0x1000 +#define    GMC_SRC_DATATYPE__COLOR                                  0x3000 +#define    GMC_SRC_DATATYPE__DST                                    0x3000 +#define    DP_GUI_MASTER_CNTL__GMC_BYTE_PIX_ORDER               0x00004000 +#define    DP_GUI_MASTER_CNTL__GMC_DEFAULT_SEL                  0x00008000 +#define    DP_GUI_MASTER_CNTL__GMC_ROP3__MASK                   0x00FF0000 +#define    DP_GUI_MASTER_CNTL__GMC_ROP3__SHIFT                  16 +#define    GMC_ROP3__SRCCPY                                         0xCC +#define    GMC_ROP3__WHITENESS                                      0xFF +#define    GMC_ROP3__BLACKNESS                                      0x0 +#define    DP_GUI_MASTER_CNTL__GMC_DP_SRC_SOURCE__MASK          0x07000000 +#define    DP_GUI_MASTER_CNTL__GMC_DP_SRC_SOURCE__SHIFT         24 +#define    GMC_DP_SRC_SOURCE__VIDEO_MEM                             0x2 +#define    GMC_DP_SRC_SOURCE__HOSTDATA                              0x3 +#define    GMC_DP_SRC_SOURCE__HOSTDATA_BYTE                         0x4 +#define    DP_GUI_MASTER_CNTL__GMC_SRC_DATATYPE2                0x08000000 +#define    DP_GUI_MASTER_CNTL__GMC_CLR_CMP_FCN_DIS              0x10000000 +#define    DP_GUI_MASTER_CNTL__GMC_WR_MSK_DIS                   0x40000000 +#define DP_BRUSH_FRGD_CLR                                   0x0000147C +#define    DP_BRUSH_FRGD_CLR__DP_BRUSH_FRGD_CLR__MASK           0xFFFFFFFF +#define    DP_BRUSH_FRGD_CLR__DP_BRUSH_FRGD_CLR__SHIFT          0 +#define DP_BRUSH_BKGD_CLR                                   0x00001478 +#define    DP_BRUSH_BKGD_CLR__DP_BRUSH_BKGD_CLR__MASK           0xFFFFFFFF +#define    DP_BRUSH_BKGD_CLR__DP_BRUSH_BKGD_CLR__SHIFT          0 +#define DP_SRC_FRGD_CLR                                     0x000015D8 +#define    DP_SRC_FRGD_CLR__DP_SRC_FRGD_CLR__MASK               0xFFFFFFFF +#define    DP_SRC_FRGD_CLR__DP_SRC_FRGD_CLR__SHIFT              0 +#define DP_SRC_BKGD_CLR                                     0x000015DC +#define    DP_SRC_BKGD_CLR__DP_SRC_BKGD_CLR__MASK               0xFFFFFFFF +#define    DP_SRC_BKGD_CLR__DP_SRC_BKGD_CLR__SHIFT              0 +#define DP_WRITE_MSK                                        0x000016CC +#define    DP_WRITE_MSK__DP_WRITE_MSK__MASK                     0xFFFFFFFF +#define    DP_WRITE_MSK__DP_WRITE_MSK__SHIFT                    0 + +#endif diff --git a/shared-core/radeon_ms_rom.c b/shared-core/radeon_ms_rom.c new file mode 100644 index 00000000..5054a390 --- /dev/null +++ b/shared-core/radeon_ms_rom.c @@ -0,0 +1,91 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: + *    Jerome Glisse <glisse@freedesktop.org> + */ +#include "radeon_ms.h" + +int radeon_ms_rom_get_properties(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; + +	switch (dev_priv->rom.type) { +	case ROM_COMBIOS: +		return radeon_ms_combios_get_properties(dev); +	} +	return 0; +} + +int radeon_ms_rom_init(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_ms_rom *rom = &dev_priv->rom; +	void *rom_mapped; +	char atomstr[5] = {0, 0, 0, 0, 0}; +	uint16_t *offset; + +	dev_priv->rom.type = ROM_UNKNOWN; +	/* copy rom if any */ +	rom_mapped = pci_map_rom_copy(dev->pdev, &rom->rom_size); +	if (rom->rom_size) { +		rom->rom_image = drm_alloc(rom->rom_size, DRM_MEM_DRIVER); +		if (rom->rom_image == NULL) { +			return -1; +		} +		memcpy(rom->rom_image, rom_mapped, rom->rom_size); +		DRM_INFO("[radeon_ms] ROM %d bytes copied\n", rom->rom_size); +	} else { +		DRM_INFO("[radeon_ms] no ROM\n"); +		return 0; +	} +	pci_unmap_rom(dev->pdev, rom_mapped); + +	if (rom->rom_image[0] != 0x55 || rom->rom_image[1] != 0xaa) { +		DRM_INFO("[radeon_ms] no ROM\n"); +		DRM_INFO("[radeon_ms] ROM signature 0x55 0xaa missing\n"); +		return 0; +	} +	offset = (uint16_t *)&rom->rom_image[ROM_HEADER]; +	memcpy(atomstr, &rom->rom_image[*offset + 4], 4); +	if (!strcpy(atomstr, "ATOM") || !strcpy(atomstr, "MOTA")) { +		DRM_INFO("[radeon_ms] ATOMBIOS ROM detected\n"); +		return 0; +	} else { +		struct combios_header **header; +		 +		header = &rom->rom.combios_header; +		if ((*offset + sizeof(struct combios_header)) > rom->rom_size) { +			DRM_INFO("[radeon_ms] wrong COMBIOS header offset\n"); +			return -1; +		} +		dev_priv->rom.type = ROM_COMBIOS; +		*header = (struct combios_header *)&rom->rom_image[*offset]; +		DRM_INFO("[radeon_ms] COMBIOS type  : %d\n", +		         (*header)->ucTypeDefinition); +		DRM_INFO("[radeon_ms] COMBIOS  OEM ID: %02x %02x\n", +		         (*header)->ucOemID1, (*header)->ucOemID2); +	} +	return 0; +} diff --git a/shared-core/radeon_ms_rom.h b/shared-core/radeon_ms_rom.h new file mode 100644 index 00000000..36a54cbb --- /dev/null +++ b/shared-core/radeon_ms_rom.h @@ -0,0 +1,51 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: + *    Jerome Glisse <glisse@freedesktop.org> + */ +#ifndef __RADEON_MS_ROM_H__ +#define __RADEON_MS_ROM_H__ + +#include "radeon_ms_combios.h" + +enum radeon_rom_type { +	ROM_COMBIOS, +	ROM_ATOMBIOS, +	ROM_UNKNOWN +}; + +union radeon_ms_rom_type { +	struct combios_header *combios_header;  +}; + +struct radeon_ms_rom { +	uint8_t                  type; +	size_t                   rom_size; +	uint8_t                  *rom_image; +	union radeon_ms_rom_type rom; +}; + +#endif + diff --git a/shared-core/radeon_ms_state.c b/shared-core/radeon_ms_state.c new file mode 100644 index 00000000..17f8b764 --- /dev/null +++ b/shared-core/radeon_ms_state.c @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: + *    Jerome Glisse <glisse@freedesktop.org> + */ +#include "drmP.h" +#include "drm.h" +#include "radeon_ms.h" + +void radeon_ms_state_restore(struct drm_device *dev, struct radeon_state *state) +{ +	radeon_ms_irq_restore(dev, state); +	radeon_ms_gpu_restore(dev, state); +	radeon_ms_cp_restore(dev, state); +	radeon_ms_crtc1_restore(dev, state); +} + +void radeon_ms_state_save(struct drm_device *dev, struct radeon_state *state) +{ +	radeon_ms_crtc1_save(dev, state); +	radeon_ms_cp_save(dev, state); +	radeon_ms_gpu_save(dev, state); +	radeon_ms_irq_save(dev, state); +} diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index 6f2e05b3..289fddc7 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -3057,7 +3057,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil  		 */  	case RADEON_PARAM_SAREA_HANDLE:  		/* The lock is the first dword in the sarea. */ -		value = (long)dev->lock.hw_lock; +		value = (long)dev->primary->master->lock.hw_lock;  		break;  #endif  	case RADEON_PARAM_GART_TEX_HANDLE: diff --git a/tests/dristat.c b/tests/dristat.c index 89853164..48c3b51b 100644 --- a/tests/dristat.c +++ b/tests/dristat.c @@ -263,7 +263,7 @@ int main(int argc, char **argv)      for (i = 0; i < 16; i++) if (!minor || i == minor) {  	sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, i); -	fd = drmOpenMinor(i, 1); +	fd = drmOpenMinor(i, 1, DRM_NODE_RENDER);  	if (fd >= 0) {  	    printf("%s\n", buf);  	    if (mask & DRM_BUSID)   getbusid(fd); diff --git a/tests/mode/Makefile b/tests/mode/Makefile new file mode 100644 index 00000000..7a9c3c24 --- /dev/null +++ b/tests/mode/Makefile @@ -0,0 +1,14 @@ + +all: app + +#CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \ +#        -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \ + +app: modetest.c +	@gcc $(CFLAGS) -o app -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm modetest.c + +clean: +	@rm -f app + +run: app +	@sudo ./test diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c new file mode 100644 index 00000000..ab0cdc9c --- /dev/null +++ b/tests/mode/modetest.c @@ -0,0 +1,380 @@ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> + +#include "xf86drm.h" +#include "xf86drmMode.h" + +int dpms_prop_id = 0; +const char* getConnectionText(drmModeConnection conn) +{ +	switch (conn) { +	case DRM_MODE_CONNECTED: +		return "connected"; +	case DRM_MODE_DISCONNECTED: +		return "disconnected"; +	default: +		return "unknown"; +	} + +} + +int printMode(struct drm_mode_modeinfo *mode) +{ +#if 1 +	printf("Mode: %s\n", mode->name); +	printf("\tclock       : %i\n", mode->clock); +	printf("\thdisplay    : %i\n", mode->hdisplay); +	printf("\thsync_start : %i\n", mode->hsync_start); +	printf("\thsync_end   : %i\n", mode->hsync_end); +	printf("\thtotal      : %i\n", mode->htotal); +	printf("\thskew       : %i\n", mode->hskew); +	printf("\tvdisplay    : %i\n", mode->vdisplay); +	printf("\tvsync_start : %i\n", mode->vsync_start); +	printf("\tvsync_end   : %i\n", mode->vsync_end); +	printf("\tvtotal      : %i\n", mode->vtotal); +	printf("\tvscan       : %i\n", mode->vscan); +	printf("\tvrefresh    : %i\n", mode->vrefresh); +	printf("\tflags       : %i\n", mode->flags); +#else +	printf("Mode: \"%s\" %ix%i %.0f\n", mode->name, +		mode->hdisplay, mode->vdisplay, mode->vrefresh / 1000.0); +#endif +	return 0; +} + +int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) +{ +	int i = 0, j; +	struct drm_mode_modeinfo *mode = NULL; +	drmModePropertyPtr props; +	unsigned char *name = NULL; + +	printf("Output: %d-%d\n", output->output_type, output->output_type_id); +	printf("\tid           : %i\n", id); +	printf("\tcrtc id      : %i\n", output->crtc); +	printf("\tconn         : %s\n", getConnectionText(output->connection)); +	printf("\tsize         : %ix%i (mm)\n", output->mmWidth, output->mmHeight); +	printf("\tcount_crtcs  : %i\n", output->count_crtcs); +	printf("\tcrtcs        : %i\n", output->crtcs); +	printf("\tcount_clones : %i\n", output->count_clones); +	printf("\tclones       : %i\n", output->clones); +	printf("\tcount_modes  : %i\n", output->count_modes); +	printf("\tcount_props  : %i\n", output->count_props); + +	for (i = 0; i < output->count_props; i++) { +		props = drmModeGetProperty(fd, output->props[i]); +		name = NULL; +		if (props) { +			printf("Property: %s\n", props->name); +			printf("\tid:        %i\n", props->prop_id); +			printf("\tflags:     %i\n", props->flags); +			printf("\tvalues %d: ", props->count_values); +			for (j = 0; j < props->count_values; j++) +				printf("%lld ", props->values[j]); + +			printf("\n\tenums %d: \n", props->count_enums); +			 +			if (props->flags & DRM_MODE_PROP_BLOB) { +				drmModePropertyBlobPtr blob; + +				blob = drmModeGetPropertyBlob(fd, output->prop_values[i]); +				if (blob) { +					printf("blob is %d length, %08X\n", blob->length, *(uint32_t *)blob->data); +					drmModeFreePropertyBlob(blob); +				} + +			} else { +				if (!strncmp(props->name, "DPMS", 4)) +					dpms_prop_id = props->prop_id; + +				for (j = 0; j < props->count_enums; j++) { +				  printf("\t\t%lld = %s\n", props->enums[j].value, props->enums[j].name); +					if (output->prop_values[i] == props->enums[j].value) +						name = props->enums[j].name; + +				} + +				if (props->count_enums && name) { +					printf("\toutput property name %s %s\n", props->name, name); +				} else { +					printf("\toutput property id %s %lli\n", props->name, output->prop_values[i]); +				} +			} + +			drmModeFreeProperty(props); +		} +	} + +	for (i = 0; i < output->count_modes; i++) { +		mode = &output->modes[i]; +		if (mode) +			printMode(mode); +		else +			printf("\t\tmode: Invalid mode %p\n", &output->modes[i]); +	} + +	return 0; +} + +int printCrtc(int fd, drmModeResPtr res, drmModeCrtcPtr crtc, uint32_t id) +{ +	printf("Crtc\n"); +	printf("\tid           : %i\n", id); +	printf("\tx            : %i\n", crtc->x); +	printf("\ty            : %i\n", crtc->y); +	printf("\twidth        : %i\n", crtc->width); +	printf("\theight       : %i\n", crtc->height); +	printf("\tmode         : %p\n", &crtc->mode); +	printf("\tnum outputs  : %i\n", crtc->count_outputs); +	printf("\toutputs      : %i\n", crtc->outputs); +	printf("\tnum possible : %i\n", crtc->count_possibles); +	printf("\tpossibles    : %i\n", crtc->possibles); + +	return 0; +} + +int printFrameBuffer(int fd, drmModeResPtr res, drmModeFBPtr fb) +{ +	printf("Framebuffer\n"); +	printf("\thandle    : %i\n", fb->handle); +	printf("\twidth     : %i\n", fb->width); +	printf("\theight    : %i\n", fb->height); +	printf("\tpitch     : %i\n", fb->pitch);; +	printf("\tbpp       : %i\n", fb->bpp); +	printf("\tdepth     : %i\n", fb->depth); +	printf("\tbuffer_id : %i\n", fb->buffer_id); + +	return 0; +} + +int printRes(int fd, drmModeResPtr res) +{ +	int i; +	drmModeOutputPtr output; +	drmModeCrtcPtr crtc; +	drmModeFBPtr fb; + +	for (i = 0; i < res->count_outputs; i++) { +		output = drmModeGetOutput(fd, res->outputs[i]); + +		if (!output) +			printf("Could not get output %i\n", i); +		else { +			printOutput(fd, res, output, res->outputs[i]); +			drmModeFreeOutput(output); +		} +	} + +	for (i = 0; i < res->count_crtcs; i++) { +		crtc = drmModeGetCrtc(fd, res->crtcs[i]); + +		if (!crtc) +			printf("Could not get crtc %i\n", i); +		else { +			printCrtc(fd, res, crtc, res->crtcs[i]); +			drmModeFreeCrtc(crtc); +		} +	} + +	for (i = 0; i < res->count_fbs; i++) { +		fb = drmModeGetFB(fd, res->fbs[i]); + +		if (!fb) +			printf("Could not get fb %i\n", res->fbs[i]); +		else { +			printFrameBuffer(fd, res, fb); +			drmModeFreeFB(fb); +		} +	} + +	return 0; +} + +static struct drm_mode_modeinfo mode = { +	.name = "Test mode", +	.clock = 25200, +	.hdisplay = 640, +	.hsync_start = 656, +	.hsync_end = 752, +	.htotal = 800, +	.hskew = 0, +	.vdisplay = 480, +	.vsync_start = 490, +	.vsync_end = 492, +	.vtotal = 525, +	.vscan = 0, +	.vrefresh = 60000, /* vertical refresh * 1000 */ +	.flags = 10, +}; + +int testMode(int fd, drmModeResPtr res) +{ +	uint32_t output = res->outputs[0]; +	uint32_t newMode = 0; +	int ret = 0; +	int error = 0; + +	printf("Test: adding mode to output %i\n", output); + +	/* printMode(&mode); */ + +	printf("\tAttaching mode %i to output %i\n", newMode, output); + +	ret = drmModeAttachMode(fd, output, &mode); + +	if (ret) +		goto err_mode; + +	printf("\tDetaching mode %i from output %i\n", newMode, output); +	ret = drmModeDetachMode(fd, output, &mode); + +	if (ret) +		goto err_mode; +	return 0; + +err_mode: + +	printf("\tFailed\n"); + +	if (error) +		printf("\tFailed to delete mode %i\n", newMode); +	return 1; +} + +/* +int testFrameBufferGet(int fd, uint32_t fb) +{ +	drmModeFBPtr frame; + +	printf("Test: get framebuffer %i\n", fb); + +	frame = drmModeGetFB(fd, fb); + +	if (!frame) { +		printf("\tFailed\n"); +	} else { +		printFrameBuffer(fd, frame); +		drmModeFreeFB(frame); +	} + +	return 0; +} +*/ + +int testFrameBufferAdd(int fd, drmModeResPtr res) +{ +	uint32_t fb = 0; +	int ret = 0; +	drmModeFBPtr frame = 0; +	drmBO bo; + +	printf("Test: adding framebuffer\n"); + +	printf("\tCreating BO\n"); + +	/* TODO */ +	ret = drmBOCreate(fd, 800 * 600 * 4, 0, 0, +		DRM_BO_FLAG_READ | +		DRM_BO_FLAG_WRITE | +		DRM_BO_FLAG_MEM_TT | +		DRM_BO_FLAG_MEM_VRAM | +		DRM_BO_FLAG_NO_EVICT, +		DRM_BO_HINT_DONT_FENCE, &bo); + +	printf("\tgot %i\n", ret); +	if (ret) +		goto err; + +	printf("\tAdding FB\n"); +	ret = drmModeAddFB(fd, 800, 600, 32, 8, 0, &bo, &fb); +	if (ret) +		goto err_bo; + +	frame = drmModeGetFB(fd, fb); + +	if (!frame) { +		printf("Couldn't retrive created framebuffer\n"); +	} else { +		printFrameBuffer(fd, res, frame); +		drmModeFreeFB(frame); +	} + +	printf("\tRemoveing FB\n"); + +	ret = drmModeRmFB(fd, fb); + +	if (ret) { +		printf("\tFailed this shouldn't happen!\n"); +		goto err_bo; +	} + +	printf("\tRemoveing BO\n"); + +	ret = drmBOUnreference(fb, &bo); + +	return 0; +	 +err_bo: +	drmBOUnreference(fd, &bo); + +err: +	printf("\tFailed\n"); + +	return 1; +} + +int testDPMS(int fd, drmModeResPtr res) +{ +	int output_id; +	int i; + +	for (i = 0; i < res->count_outputs; i++) { +		output_id = res->outputs[i]; +		/* turn output off */ +		drmModeOutputSetProperty(fd, output_id, dpms_prop_id, 3); +		sleep(2); +		drmModeOutputSetProperty(fd, output_id, dpms_prop_id, 0); +	} +	return 1; + +} + +int main(int argc, char **argv) +{ +	int fd; +	drmModeResPtr res; + +	printf("Starting test\n"); + +	fd = drmOpenControl(0); + +	if (fd < 0) { +		printf("Failed to open the card fb (%d)\n",fd); +		return 1; +	} + +	res = drmModeGetResources(fd); +	if (res == 0) { +		printf("Failed to get resources from card\n"); +		drmClose(fd); +		return 1; +	} + +	printRes(fd, res); + +	testMode(fd, res); + +	testFrameBufferAdd(fd, res); + +	/* try dpms test */ +	testDPMS(fd, res); +	drmModeFreeResources(res); +	printf("Ok\n"); + +	return 0; +} diff --git a/tests/mode/test b/tests/mode/test new file mode 100755 index 00000000..f98e3708 --- /dev/null +++ b/tests/mode/test @@ -0,0 +1 @@ +LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app diff --git a/tests/modedemo/Makefile b/tests/modedemo/Makefile new file mode 100644 index 00000000..467fb11a --- /dev/null +++ b/tests/modedemo/Makefile @@ -0,0 +1,14 @@ + +all: app + +#CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \ +#        -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \ + +app: demo.c +	@gcc $(CFLAGS) -o app -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm demo.c + +clean: +	@rm -f app + +run: app +	sudo ./test diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c new file mode 100644 index 00000000..474f04a5 --- /dev/null +++ b/tests/modedemo/demo.c @@ -0,0 +1,538 @@ +/* + * Some defines to define the behavior of the program + */ + +#define CLEAN_FBDEV +#undef DEMO_CLONE + +#define SIZE_X 2048 +#define SIZE_Y 2048 +/* Pitch needs to be power of two */ +#define PITCH 2048 + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> + +#include "xf86drm.h" +#include "xf86drmMode.h" + +/* old functions to be replaced */ +drmModeFBPtr createFB(int fd, drmModeResPtr res); +void testCursor(int fd, uint32_t crtc); +void prettyColors(int fd, unsigned int handle); +void prettyCursor(int fd, unsigned int handle, unsigned int color); + +/* structs for the demo_driver */ + +struct demo_driver; + +struct demo_screen +{ +	/* drm stuff */ +	drmBO buffer; +	drmModeFBPtr fb; +	drmModeCrtcPtr crtc; + +	size_t num_outputs; +	uint32_t outputs_id[8]; +	drmModeOutputPtr outputs[8]; + +	struct drm_mode_modeinfo *mode; + +	/* virtual buffer */ +	uint32_t virt_x; +	uint32_t virt_y; +	uint32_t pitch; + +	/* parent */ +	struct demo_driver *driver; +}; + +#define DEMO_MAX_SCREENS 4 +#define MAX_FIND_OUTPUTS 8 + +struct demo_driver +{ +	/* drm stuff */ +	int fd; +	drmModeResPtr res; + +	/* screens */ +	size_t numScreens; +	struct demo_screen screens[DEMO_MAX_SCREENS]; +}; + +struct demo_driver* demoCreateDriver(void); +void demoUpdateRes(struct demo_driver *driver); +int demoCreateScreens(struct demo_driver *driver); +int demoCreateScreenCloned(struct demo_driver *driver); +void demoTakeDownScreen(struct demo_screen *screen); +int demoFindConnectedOutputs(struct demo_driver *driver, drmModeOutputPtr *out, size_t max_out); +drmModeCrtcPtr demoFindFreeCrtc(struct demo_driver *driver, drmModeOutputPtr output); +void demoPanScreen(struct demo_screen *screen, uint16_t x, uint16_t y); +/* yet to be implemented */ +void demoMouseActivate(struct demo_screen *screen); +void demoMouseMove(struct demo_screen *screen, uint16_t x, uint16_t y); + +static struct drm_mode_modeinfo mode = { +	.name = "Test mode", +	.clock = 25200, +	.hdisplay = 640, +	.hsync_start = 656, +	.hsync_end = 752, +	.htotal = 800, +	.hskew = 0, +	.vdisplay = 480, +	.vsync_start = 490, +	.vsync_end = 492, +	.vtotal = 525, +	.vscan = 0, +	.vrefresh = 60000, /* vertical refresh * 1000 */ +	.flags = 10, +}; + +int main(int argc, char **argv) +{ +	struct demo_driver *driver; +	int num; +	int i; + +	printf("starting demo\n"); + +	driver = demoCreateDriver(); + +	if (!driver) { +		printf("failed to create driver\n"); +		return 1; +	} + +#ifndef DEMO_CLONE +	num = demoCreateScreens(driver); +#else +	num = demoCreateScreenCloned(driver); +#endif + +	if (num < 1) { +		printf("no screens attached or an error occured\n"); +		return 1; +	} +	printf("created %i screens\n", num); + +	for (i = 0; i < num; i++) { +		prettyColors(driver->fd, driver->screens[i].fb->handle); +	} +	sleep(1); + +	for (i = 0; i < num; i++) { +		printf("%i: 100 0\n", i); +		demoPanScreen(&driver->screens[i], 100, 0); +		sleep(1); + +		printf("%i: 0 100\n", i); +		demoPanScreen(&driver->screens[i], 0, 100); +		sleep(1); + +		printf("%i: 100 100\n", i); +		demoPanScreen(&driver->screens[i], 100, 100); +		sleep(1); + +		printf("%i: 0 0\n", i); +		demoPanScreen(&driver->screens[i], 0, 1); +		sleep(1); +		testCursor(driver->fd, driver->screens[i].crtc->crtc_id); +	} + +	sleep(2); +	printf("taking down screens\n"); +	for (i = 0; i < num; i++) { +		demoTakeDownScreen(&driver->screens[i]); +	} + +#ifdef CLEAN_FBDEV +	if (ioctl(fbdev_fd, FBIOPUT_VSCREENINFO, &var)) +		printf("var  %s\n", strerror(errno)); +#endif + +    printf("ok\n"); +    return 0; +} + +int demoCreateScreens(struct demo_driver *driver) +{ +	drmModeOutputPtr out[MAX_FIND_OUTPUTS]; +	int num; +	int num_screens = 0; +	struct demo_screen *screen; +	int ret = 0; +	int i; + +	num = demoFindConnectedOutputs(driver, out, MAX_FIND_OUTPUTS); +	if (num < 0) +		return 0; + +	printf("found %i connected outputs\n", num); + +	for (i = 0; i < num; i++) { +		screen = &driver->screens[i]; + +		screen->crtc = demoFindFreeCrtc(driver, out[i]); +		if (!screen->crtc) { +			printf("found no free crtc for output\n"); +			drmModeFreeOutput(out[i]); +			continue; +		} + +		screen->fb = createFB(driver->fd, driver->res); +		if (!screen->fb) { +			drmModeFreeOutput(out[i]); +			drmModeFreeCrtc(screen->crtc); +			screen->crtc = 0; +			printf("could not create framebuffer\n"); +			continue; +		} + +		screen->virt_x = SIZE_X; +		screen->virt_y = SIZE_Y; +		screen->pitch = PITCH; + +		screen->outputs[0] = out[i]; +		screen->outputs_id[0] = out[i]->output_id; +		screen->num_outputs = 1; + +		screen->mode = &mode; +		screen->driver = driver; + +		ret = drmModeSetCrtc( +			driver->fd, +			screen->crtc->crtc_id, +			screen->fb->buffer_id, +			0, 0, +			screen->outputs_id, screen->num_outputs, +			screen->mode); + +		if (ret) { +			printf("failed to set mode\n"); +			demoTakeDownScreen(screen); +		} else { +			num_screens++; +		} + +		demoUpdateRes(driver); +	} + +	return num_screens; +} + +int demoCreateScreenCloned(struct demo_driver *driver) +{ +	drmModeOutputPtr out[MAX_FIND_OUTPUTS]; +	int num; +	struct demo_screen *screen; +	int ret = 0; +	int i; + +	num = demoFindConnectedOutputs(driver, out, MAX_FIND_OUTPUTS); +	if (num < 0) +		return 0; + +	printf("found %i connected outputs\n", num); + +	screen = &driver->screens[0]; + +	screen->fb = createFB(driver->fd, driver->res); +	if (!screen->fb) { +		printf("could not create framebuffer\n"); +		return 0; +	} + +	screen->mode = &mode; +	screen->driver = driver; + +	screen->virt_x = SIZE_X; +	screen->virt_y = SIZE_Y; +	screen->pitch = PITCH; + +	screen->num_outputs = 0; +	for (i = 0; i < num; i++) { +		screen->crtc = demoFindFreeCrtc(driver, out[i]); +		if (!screen->crtc) { +			printf("found no free crtc for output\n"); +			drmModeFreeOutput(out[i]); +			continue; +		} + +		screen->outputs[screen->num_outputs] = out[i]; +		screen->outputs_id[screen->num_outputs] = out[i]->output_id; +		screen->num_outputs++; +		printf("%u, %u\n", out[i]->output_id, screen->num_outputs); +	} + +	ret = drmModeSetCrtc( +			driver->fd, +			screen->crtc->crtc_id, +			screen->fb->buffer_id, +			0, 0, +			screen->outputs_id, screen->num_outputs, +			screen->mode); + +	if (ret) { +		printf("failed to set mode\n"); +		demoTakeDownScreen(screen); +		return 0; +	} + +	demoUpdateRes(driver); + +	return 1; +} + +void demoTakeDownScreen(struct demo_screen *screen) +{ +	int fd = screen->driver->fd; +	int i; +	drmBO bo; + +	if (screen->crtc) +		drmModeSetCrtc(fd, screen->crtc->crtc_id, 0, 0, 0, 0, 0, 0); + +	if (screen->fb) +		drmModeRmFB(fd, screen->fb->buffer_id); + +	/* maybe we should keep a pointer to the bo on the screen */ +	if (screen->fb && !drmBOReference(fd, screen->fb->handle, &bo)) { +		drmBOUnreference(fd, &bo); +		drmBOUnreference(fd, &bo); +	} else { +		printf("bo error\n"); +	} + +	for (i = 0; i < screen->num_outputs; i++) { +		drmModeFreeOutput(screen->outputs[i]); +		screen->outputs[i] = NULL; +	} + +	drmModeFreeCrtc(screen->crtc); +	drmModeFreeFB(screen->fb); + +	screen->crtc = NULL; +	screen->fb = NULL; +} + +drmModeCrtcPtr demoFindFreeCrtc(struct demo_driver *driver, drmModeOutputPtr output) +{ +	drmModeCrtcPtr crtc; +	int i, j, used = 0; +	drmModeResPtr res = driver->res; + +	for (i = 0; i < res->count_crtcs; i++) { +		used = 0; +		for (j = 0; j < DEMO_MAX_SCREENS; j++) { +			crtc = driver->screens[j].crtc; + +			if (crtc && crtc->crtc_id == res->crtcs[i]) +				used = 1; +		} + +		if (!used) { +			crtc = drmModeGetCrtc(driver->fd, res->crtcs[i]); +			break; +		} else { +			crtc = 0; +		} +	} + +	return crtc; +} + +struct demo_driver* demoCreateDriver(void) +{ +	struct demo_driver* driver = malloc(sizeof(struct demo_driver)); + +	memset(driver, 0, sizeof(struct demo_driver)); + +	driver->fd = drmOpenControl(0); + +	if (driver->fd < 0) { +		printf("Failed to open the card fb\n"); +		goto err_driver; +	} + +	demoUpdateRes(driver); +	if (!driver->res) { +		printf("could not retrive resources\n"); +		goto err_res; +	} + +	return driver; + +err_res: +	drmClose(driver->fd); +err_driver: +	free(driver); +	return NULL; +} + +void demoUpdateRes(struct demo_driver *driver) +{ +	if (driver->res) +		drmModeFreeResources(driver->res); + +	driver->res = drmModeGetResources(driver->fd); + +	if (!driver->res) +		printf("failed to get resources from kernel\n"); +} + +int demoFindConnectedOutputs(struct demo_driver *driver, drmModeOutputPtr *out, size_t max_out) +{ +	int count = 0; +	int i; +	int fd = driver->fd; +	drmModeResPtr res = driver->res; + +	drmModeOutputPtr output; + +	for (i = 0; i < res->count_outputs && count < max_out; i++) { +		output = drmModeGetOutput(fd, res->outputs[i]); + +		if (!output) +			continue; + +		if (output->connection != DRM_MODE_CONNECTED) { +			drmModeFreeOutput(output); +			continue; +		} + +		out[count++] = output; +	} + +	return count; +} + +void demoPanScreen(struct demo_screen *screen, uint16_t x, uint16_t y) +{ +	drmModeSetCrtc( +		screen->driver->fd, +		screen->crtc->crtc_id, +		screen->fb->buffer_id, +		x, y, +		screen->outputs_id, screen->num_outputs, +		screen->mode); +} + +drmModeFBPtr createFB(int fd, drmModeResPtr res) +{ +	drmModeFBPtr frame; +	unsigned int fb = 0; +	int ret = 0; +	drmBO bo; + +	ret = drmBOCreate(fd, SIZE_X * SIZE_Y * 4, 0, 0, +		DRM_BO_FLAG_READ | +		DRM_BO_FLAG_WRITE | +		DRM_BO_FLAG_MEM_TT | +		DRM_BO_FLAG_MEM_VRAM | +		DRM_BO_FLAG_NO_EVICT, +		DRM_BO_HINT_DONT_FENCE, &bo); + +	if (ret) { +		printf("failed to create framebuffer (ret %d)\n",ret); +		goto err; +	} + +	ret = drmModeAddFB(fd, SIZE_X, SIZE_Y, 32, 32, PITCH * 4, &bo, &fb); + +	if (ret) +		goto err_bo; + +	frame = drmModeGetFB(fd, fb); + +	if (!frame) +		goto err_bo; + +	return frame; + +err_bo: +	drmBOUnreference(fd, &bo); +err: +	return 0; +} + +void draw(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int v, unsigned int *ptr) +{ +	int i, j; + +	for (i = x; i < x + w; i++) +		for(j = y; j < y + h; j++) +			ptr[(i * PITCH) + j] = v; + +} + +void prettyColors(int fd, unsigned int handle) +{ +	drmBO bo; +	unsigned int *ptr; +	int i; + +	drmBOReference(fd, handle, &bo); +	drmBOMap(fd, &bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, (void**)&ptr); + +	for (i = 0; i < (SIZE_X*SIZE_Y); i++) +		ptr[i] = 0xFFFFFFFF; + +	for (i = 0; i < 8; i++) +		draw(i * 40, i * 40, 40, 40, 0, ptr); + + +	draw(200, 100, 40, 40, 0xff00ff, ptr); +	draw(100, 200, 40, 40, 0xff00ff, ptr); + +	drmBOUnmap(fd, &bo); +} + +void testCursor(int fd, uint32_t crtc) +{ +	drmBO bo; +	int ret; +	ret = drmBOCreate(fd, 64 * 64 * 4, 0, 0, +		DRM_BO_FLAG_READ | +		DRM_BO_FLAG_WRITE | +		DRM_BO_FLAG_MEM_VRAM | +		DRM_BO_FLAG_NO_EVICT, +		DRM_BO_HINT_DONT_FENCE, &bo); + +	prettyCursor(fd, bo.handle, 0xFFFF00FF); +	printf("set cursor\n"); +	drmModeSetCursor(fd, crtc, &bo, 64, 64); +	printf("move cursor 0, 0\n"); +	drmModeMoveCursor(fd, crtc, 0, 0); +	sleep(1); +	prettyCursor(fd, bo.handle, 0xFFFF0000); +	printf("move cursor 40, 40\n"); +	drmModeMoveCursor(fd, crtc, 40, 40); +	sleep(1); +	printf("move cursor 100, 100\n"); +	drmModeMoveCursor(fd, crtc, 100, 100); +	sleep(1); +	drmModeSetCursor(fd, crtc, NULL, 0, 0); +} + +void prettyCursor(int fd, unsigned int handle, unsigned int color) +{ +	drmBO bo; +	unsigned int *ptr; +	int i; + +	drmBOReference(fd, handle, &bo); +	drmBOMap(fd, &bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, (void**)&ptr); + +	for (i = 0; i < (64 * 64); i++) +		ptr[i] = color; + +	drmBOUnmap(fd, &bo); +	drmBOUnreference(fd, &bo); +} diff --git a/tests/modedemo/test b/tests/modedemo/test new file mode 100755 index 00000000..f98e3708 --- /dev/null +++ b/tests/modedemo/test @@ -0,0 +1 @@ +LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app diff --git a/tests/modefb/Makefile b/tests/modefb/Makefile new file mode 100644 index 00000000..467fb11a --- /dev/null +++ b/tests/modefb/Makefile @@ -0,0 +1,14 @@ + +all: app + +#CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \ +#        -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \ + +app: demo.c +	@gcc $(CFLAGS) -o app -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm demo.c + +clean: +	@rm -f app + +run: app +	sudo ./test diff --git a/tests/modefb/demo.c b/tests/modefb/demo.c new file mode 100644 index 00000000..7fa3b93f --- /dev/null +++ b/tests/modefb/demo.c @@ -0,0 +1,229 @@ +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <fcntl.h> +#include <string.h> +#include "linux/fb.h" +#include <sys/mman.h> +#include "sys/ioctl.h" +#include "xf86drm.h" +#include "xf86drmMode.h" + +void pretty(int fd); +void setMode(struct fb_var_screeninfo *var); +void pan(int fd, struct fb_var_screeninfo *var, int x, int y); +void cursor(int fd, int drmfd); +void prettyColors(int fd); +void prettyCursor(int fd, unsigned int handle, unsigned int color); + +extern void sleep(int); + +struct fb_var_screeninfo var; +struct fb_fix_screeninfo fix; + +int main(int argc, char **argv) +{ +	char name[100]; +	int i,d; +	int fd; +	int drmfd = drmOpenControl(0); + +	/* try four devices */ +	for (d = 0; d < 4; d++) { +		snprintf(name, 100, "/dev/fb%d", d); +		fd = open(name, O_RDWR); + +		if (fd == -1) { +			printf("open %s : %s\n", name, strerror(errno)); +			return 1; +		} + +		if (drmfd < 0) { +			printf("drmOpenControl failed\n"); +			return 1; +		} + +		memset(&var, 0, sizeof(struct fb_var_screeninfo)); +		memset(&fix, 0, sizeof(struct fb_fix_screeninfo)); + +		if (ioctl(fd, FBIOGET_VSCREENINFO, &var)) +			printf("var  %s\n", strerror(errno)); +		if	(ioctl(fd, FBIOGET_FSCREENINFO, &fix)) +			printf("fix %s\n", strerror(errno)); + +		setMode(&var); + +		if (ioctl(fd, FBIOPUT_VSCREENINFO, &var)) +			printf("var  %s\n", strerror(errno)); + +		for (i = 0; i < 1; i++) { +			prettyColors(fd); +		} +		sleep(1); + +		printf("pan: 0, 0\n"); +		pan(fd, &var, 0, 0); +		sleep(2); +		printf("pan: 100, 0\n"); +		pan(fd, &var, 100, 0); +		sleep(2); +		printf("pan: 0, 100\n"); +		pan(fd, &var, 0, 100); +		sleep(2); +		printf("pan: 100, 100\n"); +		pan(fd, &var, 100, 100); +		sleep(2); +		printf("pan: 0, 0\n"); +		pan(fd, &var, 0, 0); +		sleep(2); + +		printf("cursor (may show up on wrong CRTC - fixme)\n"); +		cursor(fd, drmfd); +	} +	return 0; +} + +void pan(int fd, struct fb_var_screeninfo *var, int x, int y) +{ +	var->xoffset = x; +	var->yoffset = y; + +	if (ioctl(fd, FBIOPAN_DISPLAY, var)) +		printf("pan error: %s\n", strerror(errno)); +} + +void draw(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int v, unsigned int *ptr) +{ +	int i, j; + +	for (i = x; i < x + w; i++) +		for(j = y; j < y + h; j++) +			ptr[(i * var.xres_virtual) + j] = v; +} + +void prettyColors(int fd) +{ +	unsigned int *ptr; +	int i; +	int size = var.xres * var.yres * var.bits_per_pixel; + +	ptr = (unsigned int *)mmap(NULL, size, +				PROT_READ|PROT_WRITE, MAP_SHARED, fd, +				0); +	if (ptr < 0) { +		printf("FAILED MMAP %d\n",errno); +		exit(1); +	} + +	memset(ptr, 0xFF, size); +		 +	for (i = 0; i < 8; i++) +		draw(i * 40, i * 40, 40, 40, 0, ptr); + + +	draw(200, 100, 40, 40, 0xff00ff, ptr); +	draw(100, 200, 40, 40, 0xff00ff, ptr); + +	munmap(ptr, size); +} + +/* + * Cursor support removed from the fb kernel interface + * using drm instead. + */ +void cursor(int fd, int drmfd) +{ +	drmModeResPtr res = drmModeGetResources(drmfd); +	uint32_t crtc = res->crtcs[1]; /* select crtc here */ +	drmBO bo; +	int ret; +	ret = drmBOCreate(drmfd, 64 * 64 * 4, 0, 0, +		DRM_BO_FLAG_READ | +		DRM_BO_FLAG_WRITE | +		DRM_BO_FLAG_MEM_VRAM | +		DRM_BO_FLAG_NO_EVICT, +		DRM_BO_HINT_DONT_FENCE, &bo); + +	if (ret) { +		printf("failed to create buffer: %s\n", strerror(ret)); +		return; +	} + +	prettyCursor(drmfd, bo.handle, 0xFFFF00FF); +	drmModeSetCursor(drmfd, crtc, &bo, 64, 64); +	drmModeMoveCursor(drmfd, crtc, 0, 0); +	sleep(1); +	prettyCursor(drmfd, bo.handle, 0xFFFF0000); +	drmModeMoveCursor(drmfd, crtc, 40, 40); +	sleep(1); +	drmModeMoveCursor(drmfd, crtc, 100, 100); +	sleep(1); +	drmModeSetCursor(drmfd, crtc, NULL, 0, 0); +	drmBOUnreference(drmfd, &bo); +} + +void prettyCursor(int drmfd, unsigned int handle, unsigned int color) +{ +	drmBO bo; +	unsigned int *ptr; +	int i; + +	drmBOReference(drmfd, handle, &bo); +	drmBOMap(drmfd, &bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, (void**)&ptr); + +	for (i = 0; i < (64 * 64); i++) +		ptr[i] = color; + +	drmBOUnmap(drmfd, &bo); +	drmBOUnreference(drmfd, &bo); +} + +struct drm_mode +{ +	int clock; +	int hdisplay; +	int hsync_start; +	int hsync_end; +	int htotal; +	int hskew; +	int vdisplay; +	int vsync_start; +	int vsync_end; +	int vtotal; +	int vscan; +	int vrefresh; +	int flags; +}; + +struct drm_mode mode = +{ +	.clock = 25200, +	.hdisplay = 640, +	.hsync_start = 656, +	.hsync_end = 752, +	.htotal = 800, +	.hskew = 0, +	.vdisplay = 480, +	.vsync_start = 490, +	.vsync_end = 492, +	.vtotal = 525, +	.vscan = 0, +	.vrefresh = 60000, /* vertical refresh * 1000 */ +	.flags = 10, +}; + +void setMode(struct fb_var_screeninfo *var) { +	var->activate = FB_ACTIVATE_NOW; +	var->xres = mode.hdisplay; +	var->right_margin = mode.hsync_start - mode.hdisplay; +	var->hsync_len = mode.hsync_end - mode.hsync_start; +	var->left_margin = mode.htotal - mode.hsync_end; +	var->yres = mode.vdisplay; +	var->lower_margin = mode.vsync_start - mode.vdisplay; +	var->vsync_len = mode.vsync_end - mode.vsync_start; +	var->upper_margin = mode.vtotal - mode.vsync_end; +	var->pixclock = 10000000 / mode.htotal * 1000 / mode.vtotal * 100; +	/* avoid overflow */ +	var->pixclock = var->pixclock * 1000 / mode.vrefresh; +	var->bits_per_pixel = 32; +} diff --git a/tests/modefb/test b/tests/modefb/test new file mode 100755 index 00000000..f98e3708 --- /dev/null +++ b/tests/modefb/test @@ -0,0 +1 @@ +LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app diff --git a/tests/modehotplug/Makefile b/tests/modehotplug/Makefile new file mode 100644 index 00000000..467fb11a --- /dev/null +++ b/tests/modehotplug/Makefile @@ -0,0 +1,14 @@ + +all: app + +#CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \ +#        -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \ + +app: demo.c +	@gcc $(CFLAGS) -o app -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm demo.c + +clean: +	@rm -f app + +run: app +	sudo ./test diff --git a/tests/modehotplug/demo.c b/tests/modehotplug/demo.c new file mode 100644 index 00000000..1518e84c --- /dev/null +++ b/tests/modehotplug/demo.c @@ -0,0 +1,157 @@ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> + +#include "xf86drm.h" +#include "xf86drmMode.h" + +/* structs for the demo_driver */ + +#define DEMO_MAX_OUTPUTS 8 + +struct demo_driver +{ +	/* drm stuff */ +	int fd; +	drmModeResPtr res; +	uint32_t counter; + +	drmModeOutputPtr outputs[DEMO_MAX_OUTPUTS]; +}; + +struct demo_driver* demoCreateDriver(void); +void demoUpdateRes(struct demo_driver *driver); + +void demoPopulateOutputs(struct demo_driver *driver); +void demoHotplug(struct demo_driver *driver); + +const char* demoGetStatus(drmModeOutputPtr out); + +int main(int argc, char **argv) +{ +	struct demo_driver *driver; +	uint32_t temp; +	int i; + +	printf("starting demo\n"); + +	driver = demoCreateDriver(); + +	if (!driver) { +		printf("failed to create driver\n"); +		return 1; +	} + +	driver->counter = drmModeGetHotplug(driver->fd); +	demoPopulateOutputs(driver); +	while (driver->counter != (temp = drmModeGetHotplug(driver->fd))) { +		demoPopulateOutputs(driver); +		driver->counter = temp; +	} + +	for (i = 0; i < driver->res->count_outputs && i < DEMO_MAX_OUTPUTS; i++) { +		printf("Output %u is %s\n", +			driver->outputs[i]->output_id, +			demoGetStatus(driver->outputs[i])); +	} + +	while(1) { +		usleep(100000); +		temp = drmModeGetHotplug(driver->fd); +		if (temp == driver->counter) +			continue; + +		demoHotplug(driver); +		driver->counter = temp; +	} + +	return 0; +} + +const char* demoGetStatus(drmModeOutputPtr output) +{ +	switch (output->connection) { +		case DRM_MODE_CONNECTED: +			return "connected"; +		case DRM_MODE_DISCONNECTED: +			return "disconnected"; +		default: +			return "unknown"; +	} +} + +void demoHotplug(struct demo_driver *driver) +{ +	drmModeResPtr res = driver->res; +	int i; +	drmModeOutputPtr temp, current; + +	for (i = 0; i < res->count_outputs && i < DEMO_MAX_OUTPUTS; i++) { +		temp = drmModeGetOutput(driver->fd, res->outputs[i]); +		current = driver->outputs[i]; + +		if (temp->connection != current->connection) { +			printf("Output %u became %s was %s\n", +				temp->output_id, +				demoGetStatus(temp), +				demoGetStatus(current)); +		} + +		drmModeFreeOutput(current); +		driver->outputs[i] = temp; +	} +} + +void demoPopulateOutputs(struct demo_driver *driver) +{ +	drmModeResPtr res = driver->res; +	int i; + +	for (i = 0; i < res->count_outputs && i < DEMO_MAX_OUTPUTS; i++) { +		drmModeFreeOutput(driver->outputs[i]); +		driver->outputs[i] = drmModeGetOutput(driver->fd, res->outputs[i]); +	} +} + +struct demo_driver* demoCreateDriver(void) +{ +	struct demo_driver* driver = malloc(sizeof(struct demo_driver)); + +	memset(driver, 0, sizeof(struct demo_driver)); + +	driver->fd = drmOpenControl(0); + +	if (driver->fd < 0) { +		printf("Failed to open the card fb\n"); +		goto err_driver; +	} + +	demoUpdateRes(driver); +	if (!driver->res) { +		printf("could not retrive resources\n"); +		goto err_res; +	} + +	return driver; + +err_res: +	drmClose(driver->fd); +err_driver: +	free(driver); +	return NULL; +} + +void demoUpdateRes(struct demo_driver *driver) +{ +	if (driver->res) +		drmModeFreeResources(driver->res); + +	driver->res = drmModeGetResources(driver->fd); + +	if (!driver->res) +		printf("failed to get resources from kernel\n"); +} diff --git a/tests/modehotplug/test b/tests/modehotplug/test new file mode 100755 index 00000000..f98e3708 --- /dev/null +++ b/tests/modehotplug/test @@ -0,0 +1 @@ +LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app  | 
