Merge remote branch 'origin/modesetting-101' into modesetting-101

This commit is contained in:
Alan Hourihane 2007-04-12 15:10:08 +01:00
commit 9420ab4b41
30 changed files with 8288 additions and 85 deletions

View file

@ -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

412
libdrm/xf86drmMode.c Normal file
View file

@ -0,0 +1,412 @@
/*
* \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>
/*
* 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->modes);
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 = drmMalloc(res.count_fbs*sizeof(uint32_t));
if (res.count_crtcs)
res.crtc_id = drmMalloc(res.count_crtcs*sizeof(uint32_t));
if (res.count_outputs)
res.output_id = drmMalloc(res.count_outputs*sizeof(uint32_t));
if (res.count_modes)
res.modes = drmMalloc(res.count_modes*sizeof(*res.modes));
if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) {
r = NULL;
goto err_allocs;
}
/*
* return
*/
if (!(r = drmMalloc(sizeof(*r))))
return 0;
r->count_fbs = res.count_fbs;
r->count_crtcs = res.count_crtcs;
r->count_outputs = res.count_outputs;
r->count_modes = res.count_modes;
/* TODO we realy should test if these allocs fails. */
r->fbs = drmAllocCpy(res.fb_id, res.count_fbs, sizeof(uint32_t));
r->crtcs = drmAllocCpy(res.crtc_id, res.count_crtcs, sizeof(uint32_t));
r->outputs = drmAllocCpy(res.output_id, res.count_outputs, sizeof(uint32_t));
r->modes = drmAllocCpy(res.modes, res.count_modes, sizeof(struct drm_mode_modeinfo));
err_allocs:
drmFree(res.fb_id);
drmFree(res.crtc_id);
drmFree(res.output_id);
drmFree(res.modes);
return r;
}
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;
}
#if 0
int drmModeForceProbe(int fd, uint32_t outputId)
{
/* TODO impl/keep? */
}
#endif
/*
* Crtc function.
*/
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->x = crtc.x;
r->y = crtc.y;
r->mode = crtc.mode;
// r->width = crtc.width;
// r->height = crtc.height;
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 modeId,
uint32_t *outputs, int count)
{
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 = outputs;
crtc.count_outputs = count;
crtc.mode = modeId;
return ioctl(fd, DRM_IOCTL_MODE_SETCRTC, &crtc);
}
#if 0
drmModeGammaTriplePtr drmModeGetCrtcGamma(int fd, uint32_t crtc, int *count)
{
/* TODO impl */
}
int drmModeSetCrtcGamma(int fd, uint32_t crtcId,
drmModeGammaTriplePtr ptr, int count)
{
/* TODO impl */
}
#endif
/*
* Output manipulation
*/
drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id)
{
struct drm_mode_get_output out;
drmModeOutputPtr r = 0;
out.output = output_id;
out.count_crtcs = 0;
out.crtcs = 0;
out.count_clones = 0;
out.clones = 0;
out.count_modes = 0;
out.modes = 0;
if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out))
return 0;
if (out.count_modes)
out.modes = drmMalloc(out.count_modes*sizeof(uint32_t));
if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out))
goto err_allocs;
if(!(r = drmMalloc(sizeof(*r))))
return 0;
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->modes = drmAllocCpy(out.modes, out.count_modes, sizeof(uint32_t));
strncpy(r->name, out.name, DRM_OUTPUT_NAME_LEN);
r->name[DRM_OUTPUT_NAME_LEN-1] = 0;
return r;
err_allocs:
drmFree(out.modes);
return 0;
}
#if 0
uint32_t drmModeNewMode(int fd, struct drm_mode_modeinfo *modeInfo)
{
/* TODO impl */
}
int drmModeDesMode(int fd, uint32_t modeId)
{
// return ioctl(fd, DRM_IOCTL_MODE_DESMODE, modeId);
}
int drmModeAddMode(int fd, uint32_t outputId, uint32_t modeId)
{
drm_mode_outputmode_t res;
res.outputId = outputId;
res.modeId = modeId;
// return ioctl(fd, DRM_IOCTL_MODE_ADDMODE, &res);
}
int drmModeDelMode(int fd, uint32_t outputId, uint32_t modeId)
{
drm_mode_outputmode_t res;
res.outputId = outputId;
res.modeId = modeId;
// return ioctl(fd, DRM_IOCTL_MODE_DELMODE, &res);
}
#endif

284
libdrm/xf86drmMode.h Normal file
View file

@ -0,0 +1,284 @@
/*
* \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 randr 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
*
* All framebuffer, crtc and output ids start at 1 while 0 is either an invalid
* parameter or used to indicate that the command should disconnect from the
* currently bound target, as with drmModeMapOutput.
*
* Currently only one framebuffer exist and has a id of 1, which is also the
* default framebuffer and should allways be avaible to the client, unless
* it is locked/used or any other limiting state is applied on it.
*
*/
typedef struct _drmModeGammaTriple {
uint16_t r, g, b;
} drmModeGammaTriple, *drmModeGammaTriplePtr;
typedef struct _drmModeRes {
int count_fbs;
uint32_t *fbs;
int count_crtcs;
uint32_t *crtcs;
int count_outputs;
uint32_t *outputs;
int count_modes;
struct drm_mode_modeinfo *modes;
} drmModeRes, *drmModeResPtr;
typedef struct drm_mode_fb_cmd drmModeFB, *drmModeFBPtr;
typedef struct _drmModeCrtc {
unsigned int buffer_id; /**< FB id to connect to 0 = disconnect*/
uint32_t x, y; /**< Position on the frameuffer */
uint32_t width, height;
uint32_t mode; /**< Current mode used */
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 crtc; /**< Crtc currently connected to */
unsigned char name[DRM_OUTPUT_NAME_LEN];
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;
uint32_t *modes; /**< List of modes ids */
} drmModeOutput, *drmModeOutputPtr;
/*
* RRSetScreenConfig o
* RRGetScreenInfo o
*
* RRGetScreenSizeRange - see frameBuffer info
* RRSetScreenSize
* RRGetScreenResources
*
* RRGetOutputInfo
*
* RRListOutputProperties *
* RRQueryOutputProperty *
* RRConfigureOutputProperty *
* RRChangeOutputProperty *
* RRDeleteOutputProperty *
* RRGetOutputProperty *
*
* RRCreateMode
* RRDestroyMode
* RRAddOutputMode
* RRDeleteOutputMode
*
* RRGetCrtcInfo
* RRSetCrtcConfig
*
* RRGetCrtcGammaSize - see crtc info
* RRGetCrtcGamma
* RRSetCrtcGamma
*
* drmModeGetResources
* drmModeForceProbe
*
* drmModeGetFrameBufferInfo
* drmModeSetFrameBufferSize
*
* drmModeGetCrtcInfo
* drmModeSetCrtcConfig
* drmModeGetCrtcGamma
* drmModeSetCrtcGamma
*
* drmModeGetOutputInfo
*
* drmModeAddMode
* drmModeDestroyMode
* drmModeAddOutputMode
* drmModeDeleteOutputMode
*/
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);
/**
* Forces a probe of the give output outputId, on 0 all will be probed.
*/
extern int drmModeForceProbe(int fd, uint32_t outputId);
/*
* 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);
/**
* Changes the scanout buffer to the given buffer object.
*/
extern int drmModeFlipFrameBuffer(int fd, uint32_t bufferId, drmBO *bo);
/*
* Crtc function.
*/
/**
* 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.
*/
extern int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
uint32_t x, uint32_t y, uint32_t modeId,
uint32_t *outputs, int count);
/**
* Gets the gamma from a crtc
*/
extern drmModeGammaTriplePtr drmModeGetCrtcGamma(int fd, uint32_t crtcId,
int *count);
/**
* Sets the gamma on a crtc
*/
extern int drmModeSetCrtcGamma(int fd, uint32_t crtcId,
drmModeGammaTriplePtr ptr, int count);
/*
* Output manipulation
*/
/**
* Retrive information about the output outputId.
*/
extern drmModeOutputPtr drmModeGetOutput(int fd,
uint32_t outputId);
/**
* Creates a new mode from the given mode info.
* Name must be unique.
*/
extern uint32_t drmModeNewMode(int fd, struct drm_mode_modeinfo *modeInfo);
/**
* Destroys a mode created with CreateMode, must be unused.
*/
extern int drmModeDesMode(int fd, uint32_t modeId);
/**
* Adds the given mode to an output.
*/
extern int drmModeAddMode(int fd, uint32_t outputId, uint32_t modeId);
/**
* Deletes a mode Added with AddOutputMode from the output,
* must be unused, by the given mode.
*/
extern int drmModeDelMode(int fd, uint32_t outputId, uint32_t modeId);

View file

@ -13,13 +13,15 @@ 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_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_crtc.o \
drm_edid.o drm_modes.o drm_fb.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_buffer.o intel_display.o intel_crt.o intel_lvds.o \
intel_sdvo.o intel_modes.o intel_i2c.o i915_init.o
nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \
nouveau_object.o nouveau_irq.o \
nv04_timer.o \

View file

@ -75,6 +75,7 @@
#include <linux/poll.h>
#include <asm/pgalloc.h>
#include "drm.h"
#include "drm_crtc.h"
#include <linux/slab.h>
#define __OS_HAS_AGP (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE)))
@ -164,6 +165,8 @@
#include "drm_compat.h"
#include "drm_crtc.h"
/***********************************************************************/
/** \name Macros to make printk easier */
/*@{*/
@ -831,6 +834,9 @@ typedef struct drm_device {
unsigned int drw_info_length;
drm_drawable_info_t **drw_info;
/*@} */
/* DRM mode setting */
struct drm_mode_config mode_config;
} drm_device_t;
#if __OS_HAS_AGP

View file

@ -89,6 +89,9 @@ static int drm_bo_vm_pre_move(drm_buffer_object_t * bo, int old_is_pci)
#ifdef DRM_ODD_MM_COMPAT
int ret;
if (!bo->map_list.map)
return 0;
ret = drm_bo_lock_kmm(bo);
if (ret)
return ret;
@ -96,6 +99,9 @@ static int drm_bo_vm_pre_move(drm_buffer_object_t * bo, int old_is_pci)
if (old_is_pci)
drm_bo_finish_unmap(bo);
#else
if (!bo->map_list.map)
return 0;
drm_bo_unmap_virtual(bo);
#endif
return 0;
@ -106,6 +112,9 @@ static void drm_bo_vm_post_move(drm_buffer_object_t * bo)
#ifdef DRM_ODD_MM_COMPAT
int ret;
if (!bo->map_list.map)
return;
ret = drm_bo_remap_bound(bo);
if (ret) {
DRM_ERROR("Failed to remap a bound buffer object.\n"
@ -131,6 +140,11 @@ static int drm_bo_add_ttm(drm_buffer_object_t * bo)
if (!bo->ttm)
ret = -ENOMEM;
break;
case drm_bo_type_kernel:
bo->ttm = drm_ttm_init(dev, bo->mem.num_pages << PAGE_SHIFT);
if (!bo->ttm)
ret = -ENOMEM;
break;
case drm_bo_type_user:
case drm_bo_type_fake:
break;
@ -1530,7 +1544,7 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle,
return ret;
}
int drm_buffer_object_create(drm_file_t * priv,
int drm_buffer_object_create(drm_device_t *dev,
unsigned long size,
drm_bo_type_t type,
uint32_t mask,
@ -1539,7 +1553,6 @@ int drm_buffer_object_create(drm_file_t * priv,
unsigned long buffer_start,
drm_buffer_object_t ** buf_obj)
{
drm_device_t *dev = priv->head->dev;
drm_buffer_manager_t *bm = &dev->bm;
drm_buffer_object_t *bo;
int ret = 0;
@ -1615,6 +1628,7 @@ int drm_buffer_object_create(drm_file_t * priv,
drm_bo_usage_deref_unlocked(bo);
return ret;
}
EXPORT_SYMBOL(drm_buffer_object_create);
static int drm_bo_add_user_object(drm_file_t * priv, drm_buffer_object_t * bo,
int shareable)
@ -1670,7 +1684,8 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS)
switch (req->op) {
case drm_bo_create:
rep.ret =
drm_buffer_object_create(priv, req->size,
drm_buffer_object_create(priv->head->dev,
req->size,
req->type,
req->mask,
req->hint,

View file

@ -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

1107
linux-core/drm_crtc.c Normal file

File diff suppressed because it is too large Load diff

480
linux-core/drm_crtc.h Normal file
View file

@ -0,0 +1,480 @@
/*
* 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_BAD = -2, /* unspecified reason */
MODE_ERROR = -1 /* error condition */
};
#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)
#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;
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
enum drm_output_status {
output_status_connected,
output_status_disconnected,
output_status_unknown,
};
enum subpixel_order {
SubPixelUnknown = 0,
SubPixelHorizontalRGB,
SubPixelHorizontalBGR,
SubPixelVerticalRGB,
SubPixelVerticalBGR,
SubPixelNone,
};
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 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);
/* Set gamma on the CRTC */
void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
int size);
/* 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 CRTC 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, int prop, void *val);
void (*cleanup)(struct drm_output *output);
};
#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
* @name: name of output (should be one of a few standard names)
* @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 */
unsigned long possible_crtcs;
unsigned long possible_clones;
bool interlace_allowed;
bool doublescan_allowed;
spinlock_t modes_lock;
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 edid *monitor_info;
char name[DRM_OUTPUT_LEN];
const struct drm_output_funcs *funcs;
void *driver_private;
/* RROutputPtr randr_output? */
};
/**
* 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 {
spinlock_t config_lock;
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;
int min_width, min_height;
int max_width, max_height;
/* DamagePtr rotationDamage? */
/* DGA stuff? */
struct drm_mode_config_funcs *funcs;
int fb_base;
};
struct drm_output *drm_output_create(struct drm_device *dev,
const struct drm_output_funcs *funcs,
const char *name);
extern void drm_output_destroy(struct drm_output *output);
extern bool drm_output_rename(struct drm_output *output, const char *name);
extern int drm_add_edid_modes(struct drm_output *output,
struct i2c_adapter *adapter);
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_disable_unused_functions(struct drm_device *dev);
extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev);
extern void drm_crtc_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 struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev);
extern bool drm_initial_config(struct drm_device *dev,
struct drm_framebuffer *fb, bool cangrow);
extern void drm_framebuffer_set_object(struct drm_device *dev,
unsigned long handle);
extern bool drm_set_desired_modes(struct drm_device *dev);
extern int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb);
extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
/* IOCTLs */
extern int drm_mode_getresources(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_mode_getcrtc(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_mode_getoutput(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_mode_setcrtc(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_mode_addfb(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_mode_rmfb(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_mode_getfb(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
#endif /* __DRM_CRTC_H__ */

View file

@ -123,6 +123,13 @@ static drm_ioctl_desc_t drm_ioctls[] = {
DRM_AUTH },
[DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_IOCTL_MODE_GETRESOURCES)] = {drm_mode_getresources, DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_IOCTL_MODE_GETCRTC)] = {drm_mode_getcrtc, DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_IOCTL_MODE_GETOUTPUT)] = {drm_mode_getoutput, DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_IOCTL_MODE_SETCRTC)] = {drm_mode_setcrtc, DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_IOCTL_MODE_ADDFB)] = {drm_mode_addfb, DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_IOCTL_MODE_RMFB)] = {drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_IOCTL_MODE_GETFB)] = {drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY},
};
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
@ -150,8 +157,6 @@ int drm_lastclose(drm_device_t * dev)
* 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");
@ -394,6 +399,8 @@ static void drm_cleanup(drm_device_t * dev)
DRM_DEBUG("mtrr_del=%d\n", retval);
}
drm_bo_driver_finish(dev);
if (drm_core_has_AGP(dev) && dev->agp) {
drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
dev->agp = NULL;

468
linux-core/drm_edid.c Normal file
View file

@ -0,0 +1,468 @@
/*
* 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_crtc_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;
snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d", hsize, vsize);
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(drm_device_t *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_crtc_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);
snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d", mode->hdisplay,
mode->vdisplay);
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_add_edid_modes - add modes from 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. If we
* get any, 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 i2c_adapter *adapter)
{
struct edid *edid;
int num_modes = 0;
edid = (struct edid *)drm_ddc_read(adapter);
if (!edid) {
dev_warn(&output->dev->pdev->dev, "%s: no EDID data\n",
output->name);
goto out_err;
}
if (!edid_valid(edid)) {
dev_warn(&output->dev->pdev->dev, "%s: EDID invalid.\n",
output->name);
goto out_err;
}
num_modes += add_established_modes(output, edid);
num_modes += add_standard_modes(output, edid);
num_modes += add_detailed_info(output, edid);
return num_modes;
out_err:
kfree(edid);
return 0;
}
EXPORT_SYMBOL(drm_add_edid_modes);

176
linux-core/drm_edid.h Normal file
View file

@ -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__ */

201
linux-core/drm_fb.c Normal file
View file

@ -0,0 +1,201 @@
/*
* 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"
struct drmfb_par {
struct drm_device *dev;
struct drm_framebuffer *fb;
};
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->fb;
if (regno > 17)
return 1;
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;
}
/* 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_device *dev = par->dev;
drm_set_desired_modes(dev);
}
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_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_framebuffer *fb)
{
struct fb_info *info;
struct drmfb_par *par;
struct device *device = &dev->pdev->dev;
struct fb_var_screeninfo *var_info;
unsigned long base, size;
info = framebuffer_alloc(sizeof(struct drmfb_par), device);
if (!info){
return -EINVAL;
}
fb->fbdev = info;
par = info->par;
par->dev = dev;
par->fb = fb;
info->fbops = &drmfb_ops;
strcpy(info->fix.id, "drmfb");
info->fix.smem_start = fb->offset + dev->mode_config.fb_base;
info->fix.smem_len = (8*1024*1024);
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = FB_VISUAL_DIRECTCOLOR;
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 * ((fb->bits_per_pixel + 1) / 8);
info->flags = FBINFO_DEFAULT;
base = fb->bo->offset + dev->mode_config.fb_base;
size = (fb->bo->mem.num_pages * PAGE_SIZE);
DRM_DEBUG("remapping %08X %d\n", base, size);
fb->virtual_base = ioremap_nocache(base, size);
info->screen_base = fb->virtual_base;
info->screen_size = size;
info->pseudo_palette = fb->pseudo_palette;
info->var.xres = fb->width;
info->var.xres_virtual = fb->pitch;
info->var.yres = fb->height;
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;
DRM_DEBUG("fb depth is %d\n", fb->depth);
switch(fb->depth) {
case 8:
case 15:
case 16:
break;
default:
case 24:
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;
if (fb->depth == 32) {
info->var.transp.offset = 24;
info->var.transp.length = 8;
}
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(drmfb_probe);
int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
{
struct fb_info *info = fb->fbdev;
if (info) {
iounmap(fb->virtual_base);
unregister_framebuffer(info);
framebuffer_release(info);
}
return 0;
}
EXPORT_SYMBOL(drmfb_remove);
MODULE_LICENSE("GPL");

View file

@ -41,7 +41,7 @@
static int drm_open_helper(struct inode *inode, struct file *filp,
drm_device_t * dev);
static int drm_setup(drm_device_t * dev)
int drm_setup(drm_device_t * dev)
{
drm_local_map_t *map;
int i;
@ -121,6 +121,7 @@ static int drm_setup(drm_device_t * dev)
return 0;
}
EXPORT_SYMBOL(drm_setup);
/**
* Open file.

338
linux-core/drm_modes.c Normal file
View file

@ -0,0 +1,338 @@
/*
* 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"
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\n",
mode->mode_id, mode->name, mode->vrefresh / 1000, mode->clock,
mode->hdisplay, mode->hsync_start,
mode->hsync_end, mode->htotal,
mode->vdisplay, mode->vsync_start,
mode->vsync_end, mode->vtotal);
}
EXPORT_SYMBOL(drm_mode_debug_printmodeline);
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);
}
}
int drm_mode_width(struct drm_display_mode *mode)
{
return mode->hdisplay;
}
EXPORT_SYMBOL(drm_mode_width);
int drm_mode_height(struct drm_display_mode *mode)
{
return mode->vdisplay;
}
EXPORT_SYMBOL(drm_mode_height);
int drm_mode_vrefresh(struct drm_display_mode *mode)
{
int refresh = 0;
if (mode->vrefresh > 0)
refresh = mode->vrefresh;
else if (mode->htotal > 0 && mode->vtotal > 0) {
refresh = ((mode->clock * 1000) * 1000) / mode->htotal / mode->vtotal;
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);
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
*
* 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_crtc_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);
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);
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);
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);
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_DEBUG("Not using %s mode %d\n", mode->name, mode->status);
kfree(mode);
}
}
}
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;
}
/* 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;
}
void drm_mode_sort(struct list_head *mode_list)
{
list_sort(mode_list, drm_mode_compare);
}

138
linux-core/edid.h Normal file
View file

@ -0,0 +1,138 @@
/*
* drivers/video/edid.h - EDID/DDC Header
*
* Based on:
* 1. XFree86 4.3.0, edid.h
* Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
*
* 2. John Fremlin <vii@users.sourceforge.net> and
* Ani Joshi <ajoshi@unixbox.com>
*
* DDC is a Trademark of VESA (Video Electronics Standard Association).
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*/
#ifndef __EDID_H__
#define __EDID_H__
#define EDID_LENGTH 0x80
#define EDID_HEADER 0x00
#define EDID_HEADER_END 0x07
#define ID_MANUFACTURER_NAME 0x08
#define ID_MANUFACTURER_NAME_END 0x09
#define ID_MODEL 0x0a
#define ID_SERIAL_NUMBER 0x0c
#define MANUFACTURE_WEEK 0x10
#define MANUFACTURE_YEAR 0x11
#define EDID_STRUCT_VERSION 0x12
#define EDID_STRUCT_REVISION 0x13
#define EDID_STRUCT_DISPLAY 0x14
#define DPMS_FLAGS 0x18
#define ESTABLISHED_TIMING_1 0x23
#define ESTABLISHED_TIMING_2 0x24
#define MANUFACTURERS_TIMINGS 0x25
/* standard timings supported */
#define STD_TIMING 8
#define STD_TIMING_DESCRIPTION_SIZE 2
#define STD_TIMING_DESCRIPTIONS_START 0x26
#define DETAILED_TIMING_DESCRIPTIONS_START 0x36
#define DETAILED_TIMING_DESCRIPTION_SIZE 18
#define NO_DETAILED_TIMING_DESCRIPTIONS 4
#define DETAILED_TIMING_DESCRIPTION_1 0x36
#define DETAILED_TIMING_DESCRIPTION_2 0x48
#define DETAILED_TIMING_DESCRIPTION_3 0x5a
#define DETAILED_TIMING_DESCRIPTION_4 0x6c
#define DESCRIPTOR_DATA 5
#define UPPER_NIBBLE( x ) \
(((128|64|32|16) & (x)) >> 4)
#define LOWER_NIBBLE( x ) \
((1|2|4|8) & (x))
#define COMBINE_HI_8LO( hi, lo ) \
( (((unsigned)hi) << 8) | (unsigned)lo )
#define COMBINE_HI_4LO( hi, lo ) \
( (((unsigned)hi) << 4) | (unsigned)lo )
#define PIXEL_CLOCK_LO (unsigned)block[ 0 ]
#define PIXEL_CLOCK_HI (unsigned)block[ 1 ]
#define PIXEL_CLOCK (COMBINE_HI_8LO( PIXEL_CLOCK_HI,PIXEL_CLOCK_LO )*10000)
#define H_ACTIVE_LO (unsigned)block[ 2 ]
#define H_BLANKING_LO (unsigned)block[ 3 ]
#define H_ACTIVE_HI UPPER_NIBBLE( (unsigned)block[ 4 ] )
#define H_ACTIVE COMBINE_HI_8LO( H_ACTIVE_HI, H_ACTIVE_LO )
#define H_BLANKING_HI LOWER_NIBBLE( (unsigned)block[ 4 ] )
#define H_BLANKING COMBINE_HI_8LO( H_BLANKING_HI, H_BLANKING_LO )
#define V_ACTIVE_LO (unsigned)block[ 5 ]
#define V_BLANKING_LO (unsigned)block[ 6 ]
#define V_ACTIVE_HI UPPER_NIBBLE( (unsigned)block[ 7 ] )
#define V_ACTIVE COMBINE_HI_8LO( V_ACTIVE_HI, V_ACTIVE_LO )
#define V_BLANKING_HI LOWER_NIBBLE( (unsigned)block[ 7 ] )
#define V_BLANKING COMBINE_HI_8LO( V_BLANKING_HI, V_BLANKING_LO )
#define H_SYNC_OFFSET_LO (unsigned)block[ 8 ]
#define H_SYNC_WIDTH_LO (unsigned)block[ 9 ]
#define V_SYNC_OFFSET_LO UPPER_NIBBLE( (unsigned)block[ 10 ] )
#define V_SYNC_WIDTH_LO LOWER_NIBBLE( (unsigned)block[ 10 ] )
#define V_SYNC_WIDTH_HI ((unsigned)block[ 11 ] & (1|2))
#define V_SYNC_OFFSET_HI (((unsigned)block[ 11 ] & (4|8)) >> 2)
#define H_SYNC_WIDTH_HI (((unsigned)block[ 11 ] & (16|32)) >> 4)
#define H_SYNC_OFFSET_HI (((unsigned)block[ 11 ] & (64|128)) >> 6)
#define V_SYNC_WIDTH COMBINE_HI_4LO( V_SYNC_WIDTH_HI, V_SYNC_WIDTH_LO )
#define V_SYNC_OFFSET COMBINE_HI_4LO( V_SYNC_OFFSET_HI, V_SYNC_OFFSET_LO )
#define H_SYNC_WIDTH COMBINE_HI_4LO( H_SYNC_WIDTH_HI, H_SYNC_WIDTH_LO )
#define H_SYNC_OFFSET COMBINE_HI_4LO( H_SYNC_OFFSET_HI, H_SYNC_OFFSET_LO )
#define H_SIZE_LO (unsigned)block[ 12 ]
#define V_SIZE_LO (unsigned)block[ 13 ]
#define H_SIZE_HI UPPER_NIBBLE( (unsigned)block[ 14 ] )
#define V_SIZE_HI LOWER_NIBBLE( (unsigned)block[ 14 ] )
#define H_SIZE COMBINE_HI_8LO( H_SIZE_HI, H_SIZE_LO )
#define V_SIZE COMBINE_HI_8LO( V_SIZE_HI, V_SIZE_LO )
#define H_BORDER (unsigned)block[ 15 ]
#define V_BORDER (unsigned)block[ 16 ]
#define FLAGS (unsigned)block[ 17 ]
#define INTERLACED (FLAGS&128)
#define SYNC_TYPE (FLAGS&3<<3) /* bits 4,3 */
#define SYNC_SEPARATE (3<<3)
#define HSYNC_POSITIVE (FLAGS & 4)
#define VSYNC_POSITIVE (FLAGS & 2)
#define V_MIN_RATE block[ 5 ]
#define V_MAX_RATE block[ 6 ]
#define H_MIN_RATE block[ 7 ]
#define H_MAX_RATE block[ 8 ]
#define MAX_PIXEL_CLOCK (((int)block[ 9 ]) * 10)
#define GTF_SUPPORT block[10]
#define DPMS_ACTIVE_OFF (1 << 5)
#define DPMS_SUSPEND (1 << 6)
#define DPMS_STANDBY (1 << 7)
#endif /* __EDID_H__ */

View file

@ -79,6 +79,7 @@ static struct drm_driver driver = {
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL |
DRIVER_IRQ_VBL2,
.load = i915_driver_load,
.unload = i915_driver_unload,
.firstopen = i915_driver_firstopen,
.lastclose = i915_driver_lastclose,
.preclose = i915_driver_preclose,

1
linux-core/i915_init.c Symbolic link
View file

@ -0,0 +1 @@
../shared-core/i915_init.c

269
linux-core/intel_crt.c Normal file
View file

@ -0,0 +1,269 @@
/*
* 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)
{
drm_device_t *dev = output->dev;
drm_i915_private_t *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)
{
drm_device_t *dev = output->dev;
struct drm_crtc *crtc = output->crtc;
struct intel_crtc *intel_crtc = crtc->driver_private;
drm_i915_private_t *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)
{
drm_device_t *dev = output->dev;
// struct intel_output *intel_output = output->driver_private;
drm_i915_private_t *dev_priv = dev->dev_private;
u32 temp;
// const int timeout_ms = 1000;
// int starttime, curtime;
temp = I915_READ(PORT_HOTPLUG_EN);
I915_WRITE(PORT_HOTPLUG_EN, temp | CRT_HOTPLUG_FORCE_DETECT | (1 << 5));
#if 0
for (curtime = starttime = GetTimeInMillis();
(curtime - starttime) < timeout_ms; curtime = GetTimeInMillis())
{
if ((I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT) == 0)
break;
}
#endif
if ((I915_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) ==
CRT_HOTPLUG_MONITOR_COLOR)
{
return true;
} else {
return false;
}
}
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)
{
drm_device_t *dev = output->dev;
struct intel_output *intel_output = output->driver_private;
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;
}
/* 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 0;
}
if (intel_crt_detect_ddc(output)) {
intel_i2c_destroy(intel_output->ddc_bus);
return output_status_connected;
}
intel_i2c_destroy(intel_output->ddc_bus);
/* TODO use load detect */
return output_status_unknown;
}
static void intel_crt_destroy(struct drm_output *output)
{
if (output->driver_private)
kfree(output->driver_private);
}
static int intel_crt_get_modes(struct drm_output *output)
{
struct drm_device *dev = output->dev;
struct intel_output *intel_output = output->driver_private;
int ret;
/* 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 0;
}
ret = intel_ddc_get_modes(output);
intel_i2c_destroy(intel_output->ddc_bus);
return ret;
}
/*
* 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,
};
void intel_crt_init(drm_device_t *dev)
{
struct drm_output *output;
struct intel_output *intel_output;
output = drm_output_create(dev, &intel_crt_output_funcs, "VGA");
intel_output = kmalloc(sizeof(struct intel_output), GFP_KERNEL);
if (!intel_output) {
drm_output_destroy(output);
return;
}
intel_output->type = INTEL_OUTPUT_ANALOG;
output->driver_private = intel_output;
output->interlace_allowed = 0;
output->doublescan_allowed = 0;
}

1203
linux-core/intel_display.c Normal file

File diff suppressed because it is too large Load diff

78
linux-core/intel_drv.h Normal file
View file

@ -0,0 +1,78 @@
/*
* 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 {
drm_device_t *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_tmp;
void *dev_priv;
};
struct intel_crtc {
int pipe;
u8 lut_r[256], lut_g[256], lut_b[256];
};
struct intel_i2c_chan *intel_i2c_create(drm_device_t *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(drm_device_t *dev);
extern void intel_sdvo_init(drm_device_t *dev, int output_device);
extern void intel_lvds_init(drm_device_t *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(drm_device_t *dev,
struct drm_crtc *crtc);
extern void intel_wait_for_vblank(drm_device_t *dev);
#endif /* __INTEL_DRV_H__ */

187
linux-core/intel_i2c.c Normal file
View file

@ -0,0 +1,187 @@
/*
* 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;
drm_i915_private_t *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;
drm_i915_private_t *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;
drm_device_t *dev = chan->drm_dev;
drm_i915_private_t *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;
drm_device_t *dev = chan->drm_dev;
drm_i915_private_t *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(drm_device_t *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;
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);
}

472
linux-core/intel_lvds.c Normal file
View file

@ -0,0 +1,472 @@
/*
* 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)
{
drm_i915_private_t *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)
{
drm_i915_private_t *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)
{
drm_i915_private_t *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;
drm_i915_private_t *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;
drm_i915_private_t *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;
drm_i915_private_t *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;
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = output->crtc->driver_private;
struct drm_output *tmp_output;
#if 0 /* FIXME: Check for other outputs on this pipe */
spin_lock(&dev->mode_config.config_lock);
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;
}
}
spin_lock(&dev->mode_config.config_lock);
#endif
if (intel_crtc->pipe == 0) {
printk(KERN_ERR "Can't support LVDS on pipe A\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_mode_set(struct drm_output *output,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct drm_device *dev = output->dev;
drm_i915_private_t *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.
*/
pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
VERT_INTERP_BILINEAR | HORIZ_INTERP_BILINEAR);
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 intel_output *intel_output = output->driver_private;
struct drm_device *dev = output->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct edid *edid_info;
int ret = 0;
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 0;
}
ret = intel_ddc_get_modes(output);
intel_i2c_destroy(intel_output->ddc_bus);
if (ret)
return ret;
/* Didn't get an EDID */
if (!output->monitor_info) {
struct detailed_data_monitor_range *edid_range;
edid_info = kzalloc(sizeof(*output->monitor_info), GFP_KERNEL);
if (!edid_info)
goto out;
edid_info->detailed_timings[0].data.other_data.type =
EDID_DETAIL_MONITOR_RANGE;
edid_range = &edid_info->detailed_timings[0].data.other_data.data.range;
/* Set wide sync ranges so we get all modes
* handed to valid_mode for checking
*/
edid_range->min_vfreq = 0;
edid_range->max_vfreq = 200;
edid_range->min_hfreq_khz = 0;
edid_range->max_hfreq_khz = 200;
output->monitor_info = edid_info;
}
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;
}
static void intel_lvds_destroy(struct drm_output *output)
{
if (output->driver_private)
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_output_prepare,
.mode_set = intel_lvds_mode_set,
.commit = intel_output_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)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_output *output;
struct intel_output *intel_output;
struct drm_display_mode *scan; /* *modes, *bios_mode; */
output = drm_output_create(dev, &intel_lvds_output_funcs, "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);
intel_i2c_destroy(intel_output->ddc_bus);
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);
break;
}
}
#if 0
/*
* 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.
*/
if (!dev_priv->panel_fixed_mode) {
u32 lvds = I915_READ(LVDS);
int pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_crtc *crtc;
/* FIXME: need drm_crtc_from_pipe */
//crtc = drm_crtc_from_pipe(mode_config, pipe);
if (lvds & LVDS_PORT_EN && 0) {
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;
}
}
/* No BIOS poking yet... */
/* 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) {
if (dev_priv->PciInfo->subsysVendor == 0xa0a0) /* aopen mini pc */
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
return;
}

55
linux-core/intel_modes.c Normal file
View file

@ -0,0 +1,55 @@
/*
* 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;
return drm_add_edid_modes(output, &intel_output->ddc_bus->adapter);
}

1059
linux-core/intel_sdvo.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,324 @@
/*
* 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 << 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

View file

@ -795,6 +795,7 @@ typedef struct drm_fence_arg {
typedef enum {
drm_bo_type_dc,
drm_bo_type_kernel, /* for initial kernel allocations */
drm_bo_type_user,
drm_bo_type_fake
}drm_bo_type_t;
@ -888,6 +889,91 @@ typedef union drm_mm_init_arg{
} rep;
} drm_mm_init_arg_t;
/*
* Drm mode setting
*/
#define DRM_OUTPUT_NAME_LEN 32
#define DRM_DISPLAY_MODE_LEN 32
struct drm_mode_modeinfo {
unsigned int id;
unsigned int clock;
unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew;
unsigned short vdisplay, vsync_start, vsync_end, vtotal, vscan;
unsigned int flags;
char name[DRM_DISPLAY_MODE_LEN];
};
struct drm_mode_card_res {
int count_fbs;
unsigned int __user *fb_id;
int count_crtcs;
unsigned int __user *crtc_id;
int count_outputs;
unsigned int __user *output_id;
int count_modes;
struct drm_mode_modeinfo __user *modes;
};
struct drm_mode_crtc {
unsigned int crtc_id; /**< Id */
unsigned int fb_id; /**< Id of framebuffer */
int x, y; /**< Position on the frameuffer */
unsigned int mode; /**< Current mode used */
int count_outputs;
unsigned int outputs; /**< Outputs that are connected */
int count_possibles;
unsigned int possibles; /**< Outputs that can be connected */
unsigned int __user *set_outputs; /**< Outputs to be connected */
int gamma_size;
};
struct drm_mode_get_output {
unsigned int output; /**< Id */
unsigned int crtc; /**< Id of crtc */
unsigned char name[DRM_OUTPUT_NAME_LEN];
unsigned int connection;
unsigned int mm_width, mm_height; /**< HxW in millimeters */
unsigned int subpixel;
int count_crtcs;
unsigned int crtcs; /**< possible crtc to connect to */
int count_clones;
unsigned int clones; /**< list of clones */
int count_modes;
unsigned int __user *modes; /**< list of modes it supports */
};
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;
};
/**
* \name Ioctls Definitions
*/
@ -959,6 +1045,13 @@ typedef union drm_mm_init_arg{
#define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, drm_update_draw_t)
#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)
/*@}*/
/**

View file

@ -31,13 +31,6 @@
#include "i915_drm.h"
#include "i915_drv.h"
#define IS_I965G(dev) (dev->pci_device == 0x2972 || \
dev->pci_device == 0x2982 || \
dev->pci_device == 0x2992 || \
dev->pci_device == 0x29A2 || \
dev->pci_device == 0x2A02)
/* Really want an OS-independent resettable timer. Would like to have
* this loop run for (eg) 3 sec, but have the timer reset every time
* the head pointer changes, so that EBUSY only happens if the ring
@ -85,8 +78,9 @@ void i915_kernel_lost_context(drm_device_t * dev)
dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;
}
static int i915_dma_cleanup(drm_device_t * dev)
int i915_dma_cleanup(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) 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.
@ -94,25 +88,16 @@ static int i915_dma_cleanup(drm_device_t * dev)
if (dev->irq)
drm_irq_uninstall(dev);
if (dev->dev_private) {
drm_i915_private_t *dev_priv =
(drm_i915_private_t *) dev->dev_private;
if (dev_priv->ring.virtual_start) {
drm_core_ioremapfree(&dev_priv->ring.map, dev);
}
if (dev_priv->status_page_dmah) {
drm_pci_free(dev, dev_priv->status_page_dmah);
/* Need to rewrite hardware status page */
I915_WRITE(0x02080, 0x1ffff000);
}
drm_free(dev->dev_private, sizeof(drm_i915_private_t),
DRM_MEM_DRIVER);
dev->dev_private = NULL;
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(0x02080, 0x1ffff000);
}
dev_priv->sarea_priv = NULL;
return 0;
}
@ -121,8 +106,6 @@ static int i915_initialize(drm_device_t * dev,
drm_i915_private_t * dev_priv,
drm_i915_init_t * init)
{
memset(dev_priv, 0, sizeof(drm_i915_private_t));
DRM_GETSAREA();
if (!dev_priv->sarea) {
DRM_ERROR("can not find sarea!\n");
@ -131,14 +114,6 @@ static int i915_initialize(drm_device_t * dev,
return DRM_ERR(EINVAL);
}
dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
if (!dev_priv->mmio_map) {
dev->dev_private = (void *)dev_priv;
i915_dma_cleanup(dev);
DRM_ERROR("can not find mmio map!\n");
return DRM_ERR(EINVAL);
}
dev_priv->sarea_priv = (drm_i915_sarea_t *)
((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset);
@ -195,7 +170,9 @@ static int i915_initialize(drm_device_t * dev,
I915_WRITE(0x02080, dev_priv->dma_status_page);
DRM_DEBUG("Enabled hardware status page\n");
dev->dev_private = (void *)dev_priv;
//drm_set_desired_modes(dev);
return 0;
}
@ -237,7 +214,7 @@ static int i915_dma_resume(drm_device_t * dev)
static int i915_dma_init(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
drm_i915_init_t init;
int retcode = 0;
@ -246,10 +223,6 @@ static int i915_dma_init(DRM_IOCTL_ARGS)
switch (init.func) {
case I915_INIT_DMA:
dev_priv = drm_alloc(sizeof(drm_i915_private_t),
DRM_MEM_DRIVER);
if (dev_priv == NULL)
return DRM_ERR(ENOMEM);
retcode = i915_initialize(dev, dev_priv, &init);
break;
case I915_CLEANUP_DMA:
@ -878,36 +851,6 @@ static int i915_mmio(DRM_IOCTL_ARGS)
return 0;
}
int i915_driver_load(drm_device_t *dev, unsigned long 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;
return 0;
}
void i915_driver_lastclose(drm_device_t * dev)
{
if (dev->dev_private) {
drm_i915_private_t *dev_priv = dev->dev_private;
i915_do_cleanup_pageflip(dev);
i915_mem_takedown(&(dev_priv->agp_heap));
}
i915_dma_cleanup(dev);
}
void i915_driver_preclose(drm_device_t * dev, DRMFILE filp)
{
if (dev->dev_private) {
drm_i915_private_t *dev_priv = dev->dev_private;
i915_mem_release(dev, filp, dev_priv->agp_heap);
}
}
drm_ioctl_desc_t i915_ioctls[] = {
[DRM_IOCTL_NR(DRM_I915_INIT)] = {i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_I915_FLUSH)] = {i915_flush_ioctl, DRM_AUTH},
@ -948,8 +891,21 @@ int i915_driver_device_is_agp(drm_device_t * dev)
int i915_driver_firstopen(struct drm_device *dev)
{
#ifdef I915_HAVE_BUFFER
drm_bo_driver_init(dev);
#endif
drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
DRM_DEBUG("\n");
if (!dev_priv->mmio_map) {
ret = drm_addmap(dev, dev_priv->mmiobase, dev_priv->mmiolen,
_DRM_REGISTERS, _DRM_READ_ONLY, &dev_priv->mmio_map);
if (ret != 0) {
DRM_ERROR("Cannot add mapping for MMIO registers\n");
return ret;
}
}
DRM_DEBUG("dev_priv->mmio map is %p\n", dev_priv->mmio_map);
return 0;
}

View file

@ -92,6 +92,10 @@ typedef struct drm_i915_private {
drm_local_map_t *sarea;
drm_local_map_t *mmio_map;
unsigned long baseaddr;
unsigned long mmiobase;
unsigned long mmiolen;
drm_i915_sarea_t *sarea_priv;
drm_i915_ring_buffer_t ring;
@ -130,6 +134,67 @@ typedef struct drm_i915_private {
spinlock_t swaps_lock;
drm_i915_vbl_swap_t 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;
/* Register state */
u32 saveDSPACNTR;
u32 saveDSPBCNTR;
u32 savePIPEACONF;
u32 savePIPEBCONF;
u32 savePIPEASRC;
u32 savePIPEBSRC;
u32 saveFPA0;
u32 saveFPA1;
u32 saveDPLL_A;
u32 saveDPLL_A_MD;
u32 saveHTOTAL_A;
u32 saveHBLANK_A;
u32 saveHSYNC_A;
u32 saveVTOTAL_A;
u32 saveVBLANK_A;
u32 saveVSYNC_A;
u32 saveDSPASTRIDE;
u32 saveDSPASIZE;
u32 saveDSPAPOS;
u32 saveDSPABASE;
u32 saveDSPASURF;
u32 saveFPB0;
u32 saveFPB1;
u32 saveDPLL_B;
u32 saveDPLL_B_MD;
u32 saveHTOTAL_B;
u32 saveHBLANK_B;
u32 saveHSYNC_B;
u32 saveVTOTAL_B;
u32 saveVBLANK_B;
u32 saveVSYNC_B;
u32 saveDSPBSTRIDE;
u32 saveDSPBSIZE;
u32 saveDSPBPOS;
u32 saveDSPBBASE;
u32 saveDSPBSURF;
u32 saveVCLK_DIVISOR_VGA0;
u32 saveVCLK_DIVISOR_VGA1;
u32 saveVCLK_POST_DIV;
u32 saveVGACNTRL;
u32 saveADPA;
u32 saveLVDS;
u32 saveDVOA;
u32 saveDVOB;
u32 saveDVOC;
u32 savePP_ON;
u32 savePP_OFF;
u32 savePP_CONTROL;
u32 savePP_CYCLE;
u32 savePFIT_CONTROL;
u32 savePaletteA[256];
u32 savePaletteB[256];
u32 saveSWF[17];
u32 saveBLC_PWM_CTL;
} drm_i915_private_t;
enum intel_chip_family {
@ -145,6 +210,8 @@ extern int i915_max_ioctl;
/* i915_dma.c */
extern void i915_kernel_lost_context(drm_device_t * dev);
extern int i915_driver_load(struct drm_device *, unsigned long flags);
extern int i915_driver_unload(drm_device_t *dev);
extern int i915_driver_firstopen(struct drm_device *dev);
extern void i915_driver_lastclose(drm_device_t * dev);
extern void i915_driver_preclose(drm_device_t * dev, DRMFILE filp);
extern int i915_driver_device_is_agp(drm_device_t * dev);
@ -206,6 +273,12 @@ extern int i915_move(drm_buffer_object_t *bo, int evict,
#endif
/* modesetting */
extern void intel_modeset_init(drm_device_t *dev);
extern void intel_modeset_cleanup(drm_device_t *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))
@ -245,6 +318,27 @@ extern int i915_move(drm_buffer_object_t *bo, int evict,
extern int i915_wait_ring(drm_device_t * 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)
#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23))
#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23))
#define CMD_REPORT_HEAD (7<<23)
@ -273,6 +367,30 @@ extern int i915_wait_ring(drm_device_t * 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)
#define SRX_INDEX 0x3c4
#define SRX_DATA 0x3c5
#define SR01 1
@ -281,6 +399,8 @@ extern int i915_wait_ring(drm_device_t * 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
@ -363,4 +483,443 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[5])
#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg])
#define BLC_PWM_CTL 0x61254
#define BACKLIGHT_MODULATION_FREQ_SHIFT (17)
/**
* This is the most significant 15 bits of the number of backlight cycles in a
* complete cycle of the modulated backlight control.
*
* The actual value is this field multiplied by two.
*/
#define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17)
#define BLM_LEGACY_MODE (1 << 16)
/**
* This is the number of cycles out of the backlight modulation cycle for which
* the backlight is on.
*
* This field must be no greater than the number of cycles in the complete
* backlight modulation cycle.
*/
#define BACKLIGHT_DUTY_CYCLE_SHIFT (0)
#define BACKLIGHT_DUTY_CYCLE_MASK (0xffff)
#define I915_GCFGC 0xf0
#define I915_LOW_FREQUENCY_ENABLE (1 << 7)
#define I915_DISPLAY_CLOCK_190_200_MHZ (0 << 4)
#define I915_DISPLAY_CLOCK_333_MHZ (4 << 4)
#define I915_DISPLAY_CLOCK_MASK (7 << 4)
#define I855_HPLLCC 0xc0
#define I855_CLOCK_CONTROL_MASK (3 << 0)
#define I855_CLOCK_133_200 (0 << 0)
#define I855_CLOCK_100_200 (1 << 0)
#define I855_CLOCK_100_133 (2 << 0)
#define I855_CLOCK_166_250 (3 << 0)
/* I830 CRTC registers */
#define HTOTAL_A 0x60000
#define HBLANK_A 0x60004
#define HSYNC_A 0x60008
#define VTOTAL_A 0x6000c
#define VBLANK_A 0x60010
#define VSYNC_A 0x60014
#define PIPEASRC 0x6001c
#define BCLRPAT_A 0x60020
#define VSYNCSHIFT_A 0x60028
#define HTOTAL_B 0x61000
#define HBLANK_B 0x61004
#define HSYNC_B 0x61008
#define VTOTAL_B 0x6100c
#define VBLANK_B 0x61010
#define VSYNC_B 0x61014
#define PIPEBSRC 0x6101c
#define BCLRPAT_B 0x61020
#define VSYNCSHIFT_B 0x61028
#define PP_STATUS 0x61200
# define PP_ON (1 << 31)
/**
* Indicates that all dependencies of the panel are on:
*
* - PLL enabled
* - pipe enabled
* - LVDS/DVOB/DVOC on
*/
# define PP_READY (1 << 30)
# define PP_SEQUENCE_NONE (0 << 28)
# define PP_SEQUENCE_ON (1 << 28)
# define PP_SEQUENCE_OFF (2 << 28)
# define PP_SEQUENCE_MASK 0x30000000
#define PP_CONTROL 0x61204
# define POWER_TARGET_ON (1 << 0)
#define LVDSPP_ON 0x61208
#define LVDSPP_OFF 0x6120c
#define PP_CYCLE 0x61210
#define PFIT_CONTROL 0x61230
# define PFIT_ENABLE (1 << 31)
# define PFIT_PIPE_MASK (3 << 29)
# define PFIT_PIPE_SHIFT 29
# define VERT_INTERP_DISABLE (0 << 10)
# define VERT_INTERP_BILINEAR (1 << 10)
# define VERT_INTERP_MASK (3 << 10)
# define VERT_AUTO_SCALE (1 << 9)
# define HORIZ_INTERP_DISABLE (0 << 6)
# define HORIZ_INTERP_BILINEAR (1 << 6)
# define HORIZ_INTERP_MASK (3 << 6)
# define HORIZ_AUTO_SCALE (1 << 5)
# define PANEL_8TO6_DITHER_ENABLE (1 << 3)
#define PFIT_PGM_RATIOS 0x61234
# define PFIT_VERT_SCALE_MASK 0xfff00000
# define PFIT_HORIZ_SCALE_MASK 0x0000fff0
#define PFIT_AUTO_RATIOS 0x61238
#define DPLL_A 0x06014
#define DPLL_B 0x06018
# define DPLL_VCO_ENABLE (1 << 31)
# define DPLL_DVO_HIGH_SPEED (1 << 30)
# define DPLL_SYNCLOCK_ENABLE (1 << 29)
# define DPLL_VGA_MODE_DIS (1 << 28)
# define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */
# define DPLLB_MODE_LVDS (2 << 26) /* i915 */
# define DPLL_MODE_MASK (3 << 26)
# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */
# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */
# define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */
# define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */
# define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */
# define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */
/**
* The i830 generation, in DAC/serial mode, defines p1 as two plus this
* bitfield, or just 2 if PLL_P1_DIVIDE_BY_TWO is set.
*/
# define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000
/**
* The i830 generation, in LVDS mode, defines P1 as the bit number set within
* this field (only one bit may be set).
*/
# define DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS 0x003f0000
# define DPLL_FPA01_P1_POST_DIV_SHIFT 16
# define PLL_P2_DIVIDE_BY_4 (1 << 23) /* i830, required in DVO non-gang */
# define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */
# define PLL_REF_INPUT_DREFCLK (0 << 13)
# define PLL_REF_INPUT_TVCLKINA (1 << 13) /* i830 */
# define PLL_REF_INPUT_TVCLKINBC (2 << 13) /* SDVO TVCLKIN */
# define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13)
# define PLL_REF_INPUT_MASK (3 << 13)
# define PLL_LOAD_PULSE_PHASE_SHIFT 9
/*
* Parallel to Serial Load Pulse phase selection.
* Selects the phase for the 10X DPLL clock for the PCIe
* digital display port. The range is 4 to 13; 10 or more
* is just a flip delay. The default is 6
*/
# define PLL_LOAD_PULSE_PHASE_MASK (0xf << PLL_LOAD_PULSE_PHASE_SHIFT)
# define DISPLAY_RATE_SELECT_FPA1 (1 << 8)
/**
* SDVO multiplier for 945G/GM. Not used on 965.
*
* \sa DPLL_MD_UDI_MULTIPLIER_MASK
*/
# define SDVO_MULTIPLIER_MASK 0x000000ff
# define SDVO_MULTIPLIER_SHIFT_HIRES 4
# define SDVO_MULTIPLIER_SHIFT_VGA 0
/** @defgroup DPLL_MD
* @{
*/
/** Pipe A SDVO/UDI clock multiplier/divider register for G965. */
#define DPLL_A_MD 0x0601c
/** Pipe B SDVO/UDI clock multiplier/divider register for G965. */
#define DPLL_B_MD 0x06020
/**
* UDI pixel divider, controlling how many pixels are stuffed into a packet.
*
* Value is pixels minus 1. Must be set to 1 pixel for SDVO.
*/
# define DPLL_MD_UDI_DIVIDER_MASK 0x3f000000
# define DPLL_MD_UDI_DIVIDER_SHIFT 24
/** UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */
# define DPLL_MD_VGA_UDI_DIVIDER_MASK 0x003f0000
# define DPLL_MD_VGA_UDI_DIVIDER_SHIFT 16
/**
* SDVO/UDI pixel multiplier.
*
* SDVO requires that the bus clock rate be between 1 and 2 Ghz, and the bus
* clock rate is 10 times the DPLL clock. At low resolution/refresh rate
* modes, the bus rate would be below the limits, so SDVO allows for stuffing
* dummy bytes in the datastream at an increased clock rate, with both sides of
* the link knowing how many bytes are fill.
*
* So, for a mode with a dotclock of 65Mhz, we would want to double the clock
* rate to 130Mhz to get a bus rate of 1.30Ghz. The DPLL clock rate would be
* set to 130Mhz, and the SDVO multiplier set to 2x in this register and
* through an SDVO command.
*
* This register field has values of multiplication factor minus 1, with
* a maximum multiplier of 5 for SDVO.
*/
# define DPLL_MD_UDI_MULTIPLIER_MASK 0x00003f00
# define DPLL_MD_UDI_MULTIPLIER_SHIFT 8
/** SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK.
* This best be set to the default value (3) or the CRT won't work. No,
* I don't entirely understand what this does...
*/
# define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f
# define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0
/** @} */
#define DPLL_TEST 0x606c
# define DPLLB_TEST_SDVO_DIV_1 (0 << 22)
# define DPLLB_TEST_SDVO_DIV_2 (1 << 22)
# define DPLLB_TEST_SDVO_DIV_4 (2 << 22)
# define DPLLB_TEST_SDVO_DIV_MASK (3 << 22)
# define DPLLB_TEST_N_BYPASS (1 << 19)
# define DPLLB_TEST_M_BYPASS (1 << 18)
# define DPLLB_INPUT_BUFFER_ENABLE (1 << 16)
# define DPLLA_TEST_N_BYPASS (1 << 3)
# define DPLLA_TEST_M_BYPASS (1 << 2)
# define DPLLA_INPUT_BUFFER_ENABLE (1 << 0)
#define ADPA 0x61100
#define ADPA_DAC_ENABLE (1<<31)
#define ADPA_DAC_DISABLE 0
#define ADPA_PIPE_SELECT_MASK (1<<30)
#define ADPA_PIPE_A_SELECT 0
#define ADPA_PIPE_B_SELECT (1<<30)
#define ADPA_USE_VGA_HVPOLARITY (1<<15)
#define ADPA_SETS_HVPOLARITY 0
#define ADPA_VSYNC_CNTL_DISABLE (1<<11)
#define ADPA_VSYNC_CNTL_ENABLE 0
#define ADPA_HSYNC_CNTL_DISABLE (1<<10)
#define ADPA_HSYNC_CNTL_ENABLE 0
#define ADPA_VSYNC_ACTIVE_HIGH (1<<4)
#define ADPA_VSYNC_ACTIVE_LOW 0
#define ADPA_HSYNC_ACTIVE_HIGH (1<<3)
#define ADPA_HSYNC_ACTIVE_LOW 0
#define FPA0 0x06040
#define FPA1 0x06044
#define FPB0 0x06048
#define FPB1 0x0604c
# define FP_N_DIV_MASK 0x003f0000
# define FP_N_DIV_SHIFT 16
# define FP_M1_DIV_MASK 0x00003f00
# define FP_M1_DIV_SHIFT 8
# define FP_M2_DIV_MASK 0x0000003f
# define FP_M2_DIV_SHIFT 0
#define PORT_HOTPLUG_EN 0x61110
# define SDVOB_HOTPLUG_INT_EN (1 << 26)
# define SDVOC_HOTPLUG_INT_EN (1 << 25)
# define TV_HOTPLUG_INT_EN (1 << 18)
# define CRT_HOTPLUG_INT_EN (1 << 9)
# define CRT_HOTPLUG_FORCE_DETECT (1 << 3)
#define PORT_HOTPLUG_STAT 0x61114
# define CRT_HOTPLUG_INT_STATUS (1 << 11)
# define TV_HOTPLUG_INT_STATUS (1 << 10)
# define CRT_HOTPLUG_MONITOR_MASK (3 << 8)
# define CRT_HOTPLUG_MONITOR_COLOR (3 << 8)
# define CRT_HOTPLUG_MONITOR_MONO (2 << 8)
# define CRT_HOTPLUG_MONITOR_NONE (0 << 8)
# define SDVOC_HOTPLUG_INT_STATUS (1 << 7)
# define SDVOB_HOTPLUG_INT_STATUS (1 << 6)
#define SDVOB 0x61140
#define SDVOC 0x61160
#define SDVO_ENABLE (1 << 31)
#define SDVO_PIPE_B_SELECT (1 << 30)
#define SDVO_STALL_SELECT (1 << 29)
#define SDVO_INTERRUPT_ENABLE (1 << 26)
/**
* 915G/GM SDVO pixel multiplier.
*
* Programmed value is multiplier - 1, up to 5x.
*
* \sa DPLL_MD_UDI_MULTIPLIER_MASK
*/
#define SDVO_PORT_MULTIPLY_MASK (7 << 23)
#define SDVO_PORT_MULTIPLY_SHIFT 23
#define SDVO_PHASE_SELECT_MASK (15 << 19)
#define SDVO_PHASE_SELECT_DEFAULT (6 << 19)
#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18)
#define SDVOC_GANG_MODE (1 << 16)
#define SDVO_BORDER_ENABLE (1 << 7)
#define SDVOB_PCIE_CONCURRENCY (1 << 3)
#define SDVO_DETECTED (1 << 2)
/* Bits to be preserved when writing */
#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14))
#define SDVOC_PRESERVE_MASK (1 << 17)
/** @defgroup LVDS
* @{
*/
/**
* This register controls the LVDS output enable, pipe selection, and data
* format selection.
*
* All of the clock/data pairs are force powered down by power sequencing.
*/
#define LVDS 0x61180
/**
* Enables the LVDS port. This bit must be set before DPLLs are enabled, as
* the DPLL semantics change when the LVDS is assigned to that pipe.
*/
# define LVDS_PORT_EN (1 << 31)
/** Selects pipe B for LVDS data. Must be set on pre-965. */
# define LVDS_PIPEB_SELECT (1 << 30)
/**
* Enables the A0-A2 data pairs and CLKA, containing 18 bits of color data per
* pixel.
*/
# define LVDS_A0A2_CLKA_POWER_MASK (3 << 8)
# define LVDS_A0A2_CLKA_POWER_DOWN (0 << 8)
# define LVDS_A0A2_CLKA_POWER_UP (3 << 8)
/**
* Controls the A3 data pair, which contains the additional LSBs for 24 bit
* mode. Only enabled if LVDS_A0A2_CLKA_POWER_UP also indicates it should be
* on.
*/
# define LVDS_A3_POWER_MASK (3 << 6)
# define LVDS_A3_POWER_DOWN (0 << 6)
# define LVDS_A3_POWER_UP (3 << 6)
/**
* Controls the CLKB pair. This should only be set when LVDS_B0B3_POWER_UP
* is set.
*/
# define LVDS_CLKB_POWER_MASK (3 << 4)
# define LVDS_CLKB_POWER_DOWN (0 << 4)
# define LVDS_CLKB_POWER_UP (3 << 4)
/**
* Controls the B0-B3 data pairs. This must be set to match the DPLL p2
* setting for whether we are in dual-channel mode. The B3 pair will
* additionally only be powered up when LVDS_A3_POWER_UP is set.
*/
# define LVDS_B0B3_POWER_MASK (3 << 2)
# define LVDS_B0B3_POWER_DOWN (0 << 2)
# define LVDS_B0B3_POWER_UP (3 << 2)
#define PIPEACONF 0x70008
#define PIPEACONF_ENABLE (1<<31)
#define PIPEACONF_DISABLE 0
#define PIPEACONF_DOUBLE_WIDE (1<<30)
#define I965_PIPECONF_ACTIVE (1<<30)
#define PIPEACONF_SINGLE_WIDE 0
#define PIPEACONF_PIPE_UNLOCKED 0
#define PIPEACONF_PIPE_LOCKED (1<<25)
#define PIPEACONF_PALETTE 0
#define PIPEACONF_GAMMA (1<<24)
#define PIPECONF_FORCE_BORDER (1<<25)
#define PIPECONF_PROGRESSIVE (0 << 21)
#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21)
#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21)
#define PIPEBCONF 0x71008
#define PIPEBCONF_ENABLE (1<<31)
#define PIPEBCONF_DISABLE 0
#define PIPEBCONF_DOUBLE_WIDE (1<<30)
#define PIPEBCONF_DISABLE 0
#define PIPEBCONF_GAMMA (1<<24)
#define PIPEBCONF_PALETTE 0
#define PIPEBGCMAXRED 0x71010
#define PIPEBGCMAXGREEN 0x71014
#define PIPEBGCMAXBLUE 0x71018
#define PIPEBSTAT 0x71024
#define PIPEBFRAMEHIGH 0x71040
#define PIPEBFRAMEPIXEL 0x71044
#define DSPACNTR 0x70180
#define DSPBCNTR 0x71180
#define DISPLAY_PLANE_ENABLE (1<<31)
#define DISPLAY_PLANE_DISABLE 0
#define DISPPLANE_GAMMA_ENABLE (1<<30)
#define DISPPLANE_GAMMA_DISABLE 0
#define DISPPLANE_PIXFORMAT_MASK (0xf<<26)
#define DISPPLANE_8BPP (0x2<<26)
#define DISPPLANE_15_16BPP (0x4<<26)
#define DISPPLANE_16BPP (0x5<<26)
#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26)
#define DISPPLANE_32BPP (0x7<<26)
#define DISPPLANE_STEREO_ENABLE (1<<25)
#define DISPPLANE_STEREO_DISABLE 0
#define DISPPLANE_SEL_PIPE_MASK (1<<24)
#define DISPPLANE_SEL_PIPE_A 0
#define DISPPLANE_SEL_PIPE_B (1<<24)
#define DISPPLANE_SRC_KEY_ENABLE (1<<22)
#define DISPPLANE_SRC_KEY_DISABLE 0
#define DISPPLANE_LINE_DOUBLE (1<<20)
#define DISPPLANE_NO_LINE_DOUBLE 0
#define DISPPLANE_STEREO_POLARITY_FIRST 0
#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18)
/* plane B only */
#define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15)
#define DISPPLANE_ALPHA_TRANS_DISABLE 0
#define DISPPLANE_SPRITE_ABOVE_DISPLAYA 0
#define DISPPLANE_SPRITE_ABOVE_OVERLAY (1)
#define DSPABASE 0x70184
#define DSPASTRIDE 0x70188
#define DSPBBASE 0x71184
#define DSPBADDR DSPBBASE
#define DSPBSTRIDE 0x71188
#define DSPAKEYVAL 0x70194
#define DSPAKEYMASK 0x70198
#define DSPAPOS 0x7018C /* reserved */
#define DSPASIZE 0x70190
#define DSPBPOS 0x7118C
#define DSPBSIZE 0x71190
#define DSPASURF 0x7019C
#define DSPATILEOFF 0x701A4
#define DSPBSURF 0x7119C
#define DSPBTILEOFF 0x711A4
#define VGACNTRL 0x71400
# define VGA_DISP_DISABLE (1 << 31)
# define VGA_2X_MODE (1 << 30)
# define VGA_PIPE_B_SELECT (1 << 29)
/*
* Palette registers
*/
#define PALETTE_A 0x0a000
#define PALETTE_B 0x0a800
#define IS_I830(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82830_CGC)
#define IS_845G(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82845G_IG)
#define IS_I85X(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82855GM_IG)
#define IS_I855(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82855GM_IG)
#define IS_I865G(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82865_IG)
#define IS_I915G(pI810) (dev->pci_device == PCI_DEVICE_ID_INTEL_82915G_IG)/* || dev->pci_device == PCI_DEVICE_ID_INTELPCI_CHIP_E7221_G)*/
#define IS_I915GM(pI810) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82915GM_IG)
#define IS_I945G(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82945G_IG)
#define IS_I945GM(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82945GM_IG)
#define IS_I965G(dev) ((dev)->pci_device == 0x2972 || \
(dev)->pci_device == 0x2982 || \
(dev)->pci_device == 0x2992 || \
(dev)->pci_device == 0x29A2)
#define IS_I9XX(pI810) (IS_I915G(pI810) || IS_I915GM(pI810) || IS_I945G(pI810) || IS_I945GM(pI810) || IS_I965G(pI810))
#define IS_MOBILE(pI810) (IS_I830(pI810) || IS_I85X(pI810) || IS_I915GM(pI810) || IS_I945GM(pI810))
#endif

304
shared-core/i915_init.c Normal file
View file

@ -0,0 +1,304 @@
/*
* 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_HB:
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(drm_device_t *dev, unsigned long flags)
{
drm_i915_private_t *dev_priv;
drm_i915_init_t init;
drm_buffer_object_t *entry;
struct drm_framebuffer *fb;
unsigned long agp_size, prealloc_size;
int hsize, vsize, bytes_per_pixel, size, ret;
dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER);
if (dev_priv == NULL)
return DRM_ERR(ENOMEM);
memset(dev_priv, 0, sizeof(drm_i915_private_t));
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)) {
dev_priv->mmiobase = drm_get_resource_start(dev, 0);
dev_priv->mmiolen = drm_get_resource_len(dev, 0);
dev->mode_config.fb_base = dev_priv->baseaddr =
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 = dev_priv->baseaddr =
drm_get_resource_start(dev, 0) & 0xff000000;
} else {
DRM_ERROR("Unable to find MMIO registers\n");
return -ENODEV;
}
ret = drm_addmap(dev, dev_priv->mmiobase, dev_priv->mmiolen,
_DRM_REGISTERS, _DRM_READ_ONLY, &dev_priv->mmio_map);
if (ret != 0) {
DRM_ERROR("Cannot add mapping for MMIO registers\n");
return ret;
}
ret = drm_setup(dev);
if (ret) {
DRM_ERROR("drm_setup failed\n");
return ret;
}
DRM_GETSAREA();
if (!dev_priv->sarea) {
DRM_ERROR("can not find sarea!\n");
dev->dev_private = (void *)dev_priv;
i915_dma_cleanup(dev);
return DRM_ERR(EINVAL);
}
/* FIXME: assume sarea_priv is right after SAREA */
dev_priv->sarea_priv = dev_priv->sarea->handle + sizeof(drm_sarea_t);
/*
* Initialize the memory manager for local and AGP space
*/
drm_bo_driver_init(dev);
i915_probe_agp(dev->pdev, &agp_size, &prealloc_size);
drm_bo_init_mm(dev, DRM_BO_MEM_PRIV0, dev_priv->baseaddr,
prealloc_size);
/* Allocate scanout buffer and command ring */
/* FIXME: types and other args correct? */
hsize = 1280;
vsize = 800;
bytes_per_pixel = 4;
size = hsize * vsize * bytes_per_pixel;
drm_buffer_object_create(dev, size, drm_bo_type_kernel,
DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE |
DRM_BO_FLAG_MEM_PRIV0 | DRM_BO_FLAG_NO_MOVE,
0, PAGE_SIZE, 0,
&entry);
DRM_DEBUG("allocated bo, start: 0x%lx, offset: 0x%lx\n",
entry->buffer_start, entry->offset);
intel_modeset_init(dev);
fb = drm_framebuffer_create(dev);
if (!fb) {
DRM_ERROR("failed to allocate fb\n");
return -EINVAL;
}
fb->width = hsize;
fb->height = vsize;
fb->pitch = hsize;
fb->bits_per_pixel = bytes_per_pixel * 8;
fb->depth = bytes_per_pixel * 8;
fb->offset = entry->offset;
fb->bo = entry;
drm_initial_config(dev, fb, false);
drmfb_probe(dev, fb);
#if 0
/* FIXME: command ring needs AGP space, do we own it at this point? */
dev_priv->ring.Start = dev_priv->baseaddr;
dev_priv->ring.End = 128*1024;
dev_priv->ring.Size = 128*1024;
dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
dev_priv->ring.map.offset = dev_priv->ring.Start;
dev_priv->ring.map.size = dev_priv->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) {
dev->dev_private = (void *)dev_priv;
i915_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
return DRM_ERR(ENOMEM);
}
dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
dev_priv->cpp = 4;
dev_priv->sarea_priv->pf_current_page = 0;
/* 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 */
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 DRM_ERR(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);
DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
I915_WRITE(0x02080, dev_priv->dma_status_page);
DRM_DEBUG("Enabled hardware status page\n");
#endif
return 0;
}
int i915_driver_unload(drm_device_t *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_framebuffer *fb;
/* FIXME: remove framebuffer */
intel_modeset_cleanup(dev);
drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
dev->dev_private = NULL;
return 0;
}
void i915_driver_lastclose(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
i915_mem_takedown(&(dev_priv->agp_heap));
i915_dma_cleanup(dev);
dev_priv->mmio_map = NULL;
}
void i915_driver_preclose(drm_device_t * dev, DRMFILE filp)
{
drm_i915_private_t *dev_priv = dev->dev_private;
i915_mem_release(dev, filp, dev_priv->agp_heap);
}