From 8e8e37515eafbd75b971f57f767ef01344361256 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 1 May 2007 13:15:41 +1000 Subject: fix unusued variable --- linux-core/drm_modes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 3293f91d..97f7607d 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -533,7 +533,7 @@ void drm_mode_sort(struct list_head *mode_list) */ void drm_mode_output_list_update(struct drm_output *output) { - struct drm_display_mode *mode, *t; + struct drm_display_mode *mode; struct drm_display_mode *pmode, *pt; int found_it; list_for_each_entry_safe(pmode, pt, &output->probed_modes, -- cgit v1.2.3 From 89231953d108e74ee7b0eb99494ead1dd795d640 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 1 May 2007 13:16:29 +1000 Subject: Add support for user defined modes This allows userspace to specify modes and add them to the modesetting system and attach modes to outputs --- libdrm/xf86drmMode.c | 33 +++---- libdrm/xf86drmMode.h | 16 ++-- linux-core/drm_crtc.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++++- linux-core/drm_crtc.h | 19 +++- linux-core/drm_drv.c | 4 + shared-core/drm.h | 12 ++- 6 files changed, 312 insertions(+), 29 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index b695467b..93b0af76 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -376,37 +376,38 @@ err_allocs: return 0; } -#if 0 -uint32_t drmModeNewMode(int fd, struct drm_mode_modeinfo *modeInfo) +uint32_t drmModeAddMode(int fd, struct drm_mode_modeinfo *mode_info) { - /* TODO impl */ + if (ioctl(fd, DRM_IOCTL_MODE_ADDMODE, mode_info)) + return 0; + + return mode_info->id; } -int drmModeDesMode(int fd, uint32_t modeId) +int drmModeRmMode(int fd, uint32_t mode_id) { - // return ioctl(fd, DRM_IOCTL_MODE_DESMODE, modeId); + return ioctl(fd, DRM_IOCTL_MODE_RMMODE, mode_id); } -int drmModeAddMode(int fd, uint32_t outputId, uint32_t modeId) +int drmModeAttachMode(int fd, uint32_t output_id, uint32_t mode_id) { - drm_mode_outputmode_t res; + struct drm_mode_mode_cmd res; - res.outputId = outputId; - res.modeId = modeId; + res.output_id = output_id; + res.mode_id = mode_id; - // return ioctl(fd, DRM_IOCTL_MODE_ADDMODE, &res); + return ioctl(fd, DRM_IOCTL_MODE_ATTACHMODE, &res); } -int drmModeDelMode(int fd, uint32_t outputId, uint32_t modeId) +int drmModeDetachMode(int fd, uint32_t output_id, uint32_t mode_id) { - drm_mode_outputmode_t res; + struct drm_mode_mode_cmd res; - res.outputId = outputId; - res.modeId = modeId; + res.output_id = output_id; + res.mode_id = mode_id; - // return ioctl(fd, DRM_IOCTL_MODE_DELMODE, &res); + return ioctl(fd, DRM_IOCTL_MODE_DETACHMODE, &res); } -#endif diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 6aa104a9..60e919ae 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -261,24 +261,24 @@ extern drmModeOutputPtr drmModeGetOutput(int fd, uint32_t outputId); /** - * Creates a new mode from the given mode info. + * Adds a new mode from the given mode info. * Name must be unique. */ -extern uint32_t drmModeNewMode(int fd, struct drm_mode_modeinfo *modeInfo); +extern uint32_t drmModeAddMode(int fd, struct drm_mode_modeinfo *modeInfo); /** - * Destroys a mode created with CreateMode, must be unused. + * Removes a mode created with AddMode, must be unused. */ -extern int drmModeDesMode(int fd, uint32_t modeId); +extern int drmModeRmMode(int fd, uint32_t modeId); /** - * Adds the given mode to an output. + * Attaches the given mode to an output. */ -extern int drmModeAddMode(int fd, uint32_t outputId, uint32_t modeId); +extern int drmModeAttachMode(int fd, uint32_t outputId, uint32_t modeId); /** - * Deletes a mode Added with AddOutputMode from the output, + * Detaches a mode from the output * must be unused, by the given mode. */ -extern int drmModeDelMode(int fd, uint32_t outputId, uint32_t modeId); +extern int drmModeDetachMode(int fd, uint32_t outputId, uint32_t modeId); diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 16cf62a7..201137db 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -749,6 +749,7 @@ void drm_mode_config_init(drm_device_t *dev) INIT_LIST_HEAD(&dev->mode_config.fb_list); INIT_LIST_HEAD(&dev->mode_config.crtc_list); INIT_LIST_HEAD(&dev->mode_config.output_list); + INIT_LIST_HEAD(&dev->mode_config.usermode_list); idr_init(&dev->mode_config.crtc_idr); } EXPORT_SYMBOL(drm_mode_config_init); @@ -1090,6 +1091,35 @@ void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, struct drm_display out->name[DRM_DISPLAY_MODE_LEN-1] = 0; } +/** + * drm_crtc_convert_to_umode - convert a modeinfo into a drm_display_mode + * @out: drm_display_mode to return to the user + * @in: drm_mode_modeinfo to use + * + * LOCKING: + * None. + * + * Convert a drmo_mode_modeinfo into a drm_display_mode structure to return to + * the caller. + */ +void drm_crtc_convert_umode(struct drm_display_mode *out, struct drm_mode_modeinfo *in) +{ + out->clock = in->clock; + out->hdisplay = in->hdisplay; + out->hsync_start = in->hsync_start; + out->hsync_end = in->hsync_end; + out->htotal = in->htotal; + out->hskew = in->hskew; + out->vdisplay = in->vdisplay; + out->vsync_start = in->vsync_start; + out->vsync_end = in->vsync_end; + out->vtotal = in->vtotal; + out->vscan = in->vscan; + out->vrefresh = in->vrefresh; + out->flags = in->flags; + strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); + out->name[DRM_DISPLAY_MODE_LEN-1] = 0; +} /** * drm_mode_getresources - get graphics configuration @@ -1143,6 +1173,8 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, list_for_each(lh, &output->modes) mode_count++; } + list_for_each(lh, &dev->mode_config.usermode_list) + mode_count++; if (copy_from_user(&card_res, argp, sizeof(card_res))) return -EFAULT; @@ -1155,6 +1187,8 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, list_for_each(lh, &output->modes) mode_count++; } + list_for_each(lh, &dev->mode_config.usermode_list) + mode_count++; } /* handle this in 4 parts */ @@ -1211,6 +1245,14 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, } } } + /* add in user modes */ + list_for_each_entry(mode, &dev->mode_config.usermode_list, head) { + drm_crtc_convert_to_umode(&u_mode, mode); + if (copy_to_user(&card_res.modes[copied++], &u_mode, sizeof(struct drm_mode_modeinfo))) { + retcode = -EFAULT; + goto done; + } + } } card_res.count_modes = mode_count; @@ -1312,6 +1354,7 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, int mode_count = 0; int retcode = 0; int copied = 0; + int i; if (copy_from_user(&out_resp, argp, sizeof(out_resp))) return -EFAULT; @@ -1323,6 +1366,10 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, list_for_each_entry(mode, &output->modes, head) mode_count++; + + for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) + if (output->user_mode_ids[i] != 0) + mode_count++; strncpy(out_resp.name, output->name, DRM_OUTPUT_NAME_LEN); out_resp.name[DRM_OUTPUT_NAME_LEN-1] = 0; @@ -1344,6 +1391,14 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, goto done; } } + for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { + if (output->user_mode_ids[i] != 0) + if (put_user(output->user_mode_ids[i], &out_resp.modes[copied++])) { + retcode = -EFAULT; + goto done; + } + } + } out_resp.count_modes = mode_count; @@ -1408,9 +1463,13 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, if (!mode || (mode->mode_id != crtc_req.mode)) { struct drm_output *output; - list_for_each_entry(output, &dev->mode_config.output_list, head) { - list_for_each_entry(mode, &output->modes, head) { - drm_mode_debug_printmodeline(dev, mode); + list_for_each_entry(output, + &dev->mode_config.output_list, + head) { + list_for_each_entry(mode, &output->modes, + head) { + drm_mode_debug_printmodeline(dev, + mode); } } @@ -1650,3 +1709,195 @@ void drm_fb_release(struct file *filp) } } + +/** + * drm_fb_newmode - adds a user defined mode + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * Adds a user specified mode to the kernel. + * + * Called by the user via ioctl. + * + * RETURNS: + * writes new mode id into arg. + * Zero on success, errno on failure. + */ +int drm_mode_addmode(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + struct drm_mode_modeinfo __user *argp = (void __user *)arg; + struct drm_mode_modeinfo new_mode; + struct drm_display_mode *user_mode; + + if (copy_from_user(&new_mode, argp, sizeof(new_mode))) + return -EFAULT; + + user_mode = drm_mode_create(dev); + if (!user_mode) + return -ENOMEM; + + drm_crtc_convert_umode(user_mode, &new_mode); + user_mode->type |= DRM_MODE_TYPE_USERDEF; + + user_mode->output_count = 0; + + spin_lock(&dev->mode_config.config_lock); + list_add(&user_mode->head, &dev->mode_config.usermode_list); + spin_unlock(&dev->mode_config.config_lock); + + new_mode.id = user_mode->mode_id; + if (copy_to_user(argp, &new_mode, sizeof(new_mode))) + return -EFAULT; + + return 0; +} + +/** + * drm_fb_rmmode - removes a user defined mode + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * Remove the user defined mode specified by the user. + * + * Called by the user via ioctl + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_mode_rmmode(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + uint32_t id = arg; + struct drm_display_mode *mode, *t; + int retcode = -EINVAL; + + mode = idr_find(&dev->mode_config.crtc_idr, id); + if (!mode || (id != mode->mode_id)) + return -EINVAL; + + if (!(mode->type & DRM_MODE_TYPE_USERDEF)) + return -EINVAL; + + if (mode->output_count) + return -EINVAL; + + spin_lock(&dev->mode_config.config_lock); + list_for_each_entry(t, &dev->mode_config.usermode_list, head) { + if (t == mode) { + list_del(&mode->head); + drm_mode_destroy(dev, mode); + retcode = 0; + break; + } + } + spin_unlock(&dev->mode_config.config_lock); + return retcode; +} + +/** + * drm_fb_attachmode - Attach a user mode to an output + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * This attaches a user specified mode to an output. + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_mode_attachmode(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + struct drm_mode_mode_cmd __user *argp = (void __user *)arg; + struct drm_mode_mode_cmd mode_cmd; + struct drm_output *output; + struct drm_display_mode *mode; + int i; + + if (copy_from_user(&mode_cmd, argp, sizeof(mode_cmd))) + return -EFAULT; + + mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd.mode_id); + if (!mode || (mode->mode_id != mode_cmd.mode_id)) + return -EINVAL; + + output = idr_find(&dev->mode_config.crtc_idr, mode_cmd.output_id); + if (!output || (output->id != mode_cmd.output_id)) + return -EINVAL; + + for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { + if (output->user_mode_ids[i] == 0) { + output->user_mode_ids[i] = mode->mode_id; + mode->output_count++; + break; + } + } + + if (i == DRM_OUTPUT_MAX_UMODES) + return -ENOSPC; + + return 0; +} + + +/** + * drm_fb_detachmode - Detach a user specified mode from an output + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_mode_detachmode(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + struct drm_mode_mode_cmd __user *argp = (void __user *)arg; + struct drm_mode_mode_cmd mode_cmd; + struct drm_output *output; + struct drm_display_mode *mode; + int i, found = 0; + + if (copy_from_user(&mode_cmd, argp, sizeof(mode_cmd))) + return -EFAULT; + + mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd.mode_id); + if (!mode || (mode->mode_id != mode_cmd.mode_id)) + return -EINVAL; + + output = idr_find(&dev->mode_config.crtc_idr, mode_cmd.output_id); + if (!output || (output->id != mode_cmd.output_id)) + return -EINVAL; + + + for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { + if (output->user_mode_ids[i] == mode->mode_id) { + output->user_mode_ids[i] = 0; + mode->output_count--; + found = 1; + } + } + + if (!found) + return -EINVAL; + + return 0; +} diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index a15ce0cf..12c7eef1 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -87,6 +87,7 @@ struct drm_display_mode { struct list_head head; char name[DRM_DISPLAY_MODE_LEN]; int mode_id; + int output_count; enum drm_mode_status status; int type; @@ -382,6 +383,7 @@ struct drm_output_funcs { void (*cleanup)(struct drm_output *output); }; +#define DRM_OUTPUT_MAX_UMODES 16 #define DRM_OUTPUT_LEN 32 /** * drm_output - central DRM output control structure @@ -417,6 +419,7 @@ struct drm_output { bool doublescan_allowed; spinlock_t modes_lock; /* protects modes and probed_modes lists */ struct list_head modes; /* list of modes on this output */ + /* OptionInfoPtr options; XF86ConfMonitorPtr conf_monitor; @@ -434,7 +437,8 @@ struct drm_output { char name[DRM_OUTPUT_LEN]; const struct drm_output_funcs *funcs; void *driver_private; - /* RROutputPtr randr_output? */ + + u32 user_mode_ids[DRM_OUTPUT_MAX_UMODES]; }; /** @@ -467,6 +471,7 @@ struct drm_mode_config { int num_crtc; struct list_head crtc_list; + struct list_head usermode_list; int min_width, min_height; int max_width, max_height; /* DamagePtr rotationDamage? */ @@ -480,6 +485,7 @@ struct drm_output *drm_output_create(struct drm_device *dev, 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 void drm_fb_release(struct file *filp); extern int drm_add_edid_modes(struct drm_output *output, struct i2c_adapter *adapter); @@ -507,6 +513,8 @@ extern void drm_mode_sort(struct list_head *mode_list); extern int drm_mode_vrefresh(struct drm_display_mode *mode); extern void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags); +extern void drm_mode_output_list_update(struct drm_output *output); + extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); extern bool drm_initial_config(struct drm_device *dev, bool cangrow); extern void drm_framebuffer_set_object(struct drm_device *dev, @@ -531,5 +539,14 @@ 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); +extern int drm_mode_addmode(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_mode_rmmode(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_mode_attachmode(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_mode_detachmode(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + #endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 5aa7137b..dc52f302 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -130,6 +130,10 @@ static drm_ioctl_desc_t drm_ioctls[] = { [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}, + [DRM_IOCTL_NR(DRM_IOCTL_MODE_ADDMODE)] = {drm_mode_addmode, DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MODE_RMMODE)] = {drm_mode_rmmode, DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MODE_ATTACHMODE)] = {drm_mode_attachmode, DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MODE_DETACHMODE)] = {drm_mode_detachmode, DRM_MASTER|DRM_ROOT_ONLY}, }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/shared-core/drm.h b/shared-core/drm.h index d42bf73a..890dcf88 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -978,6 +978,11 @@ struct drm_mode_fb_cmd { unsigned int depth; }; +struct drm_mode_mode_cmd { + unsigned int output_id; + unsigned int mode_id; +}; + /** * \name Ioctls Definitions */ @@ -1055,7 +1060,12 @@ struct drm_mode_fb_cmd { #define DRM_IOCTL_MODE_SETCRTC DRM_IOWR(0xA3, struct drm_mode_crtc) #define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xA4, struct drm_mode_fb_cmd) #define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xA5, unsigned int) -#define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xA6, struct drm_mode_fb_cmd) +#define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xA6, struct drm_mode_fb_cmd) + +#define DRM_IOCTL_MODE_ADDMODE DRM_IOWR(0xA7, struct drm_mode_modeinfo) +#define DRM_IOCTL_MODE_RMMODE DRM_IOWR(0xA8, unsigned int) +#define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) +#define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xAA, struct drm_mode_mode_cmd) /*@}*/ /** -- cgit v1.2.3 From 3a69e2484a4a392c8fc8542fc44f9c6552589c46 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 1 May 2007 14:20:22 +1000 Subject: cleanup usermodes on drm mode setting shutdown --- linux-core/drm_crtc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 201137db..a8f14e17 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -956,6 +956,7 @@ void drm_mode_config_cleanup(drm_device_t *dev) struct drm_output *output, *ot; struct drm_crtc *crtc, *ct; struct drm_framebuffer *fb, *fbt; + struct drm_display_mode *mode, *mt; list_for_each_entry_safe(output, ot, &dev->mode_config.output_list, head) { drm_output_destroy(output); } @@ -964,6 +965,10 @@ void drm_mode_config_cleanup(drm_device_t *dev) drm_crtc_destroy(crtc); } + list_for_each_entry_safe(mode, mt, &dev->mode_config.usermode_list, head) { + drm_mode_destroy(dev, mode); + } + list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { drmfb_remove(dev, fb); /* If this FB was the kernel one, free it */ -- cgit v1.2.3 From 45e09ea3cf85b76c18fb92a593ca7c40681052a7 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 5 May 2007 16:08:27 +0200 Subject: Cleaned up userspace interface for modesetting. --- libdrm/xf86drmMode.c | 30 ++++-------------- libdrm/xf86drmMode.h | 88 ++++------------------------------------------------ 2 files changed, 12 insertions(+), 106 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 93b0af76..a7241ffd 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -238,15 +238,10 @@ drmModeFBPtr drmModeGetFB(int fd, uint32_t buf) return r; } -#if 0 -int drmModeForceProbe(int fd, uint32_t outputId) -{ - /* TODO impl/keep? */ -} -#endif + /* - * Crtc function. + * Crtc functions */ drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) @@ -274,9 +269,7 @@ drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) 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->buffer_id = crtc.fb_id; r->gamma_size = crtc.gamma_size; r->count_outputs = crtc.count_outputs; r->count_possibles = crtc.count_possibles; @@ -305,8 +298,8 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, crtc.x = x; crtc.y = y; - crtc.crtc_id = crtcId; - crtc.fb_id = bufferId; + crtc.crtc_id = crtcId; + crtc.fb_id = bufferId; crtc.set_outputs = outputs; crtc.count_outputs = count; crtc.mode = modeId; @@ -314,22 +307,11 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, 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; diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 60e919ae..b25a6610 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -40,25 +40,17 @@ * In order to use this interface you must include either or another * header defining uint32_t, int32_t and uint16_t. * - * It aims to provide a randr compatible interface for modesettings in the + * It aims to provide a randr1.2 compatible interface for modesettings in the * kernel, the interface is also ment to be used by libraries like EGL. * * More information can be found in randrproto.txt which can be found here: * http://gitweb.freedesktop.org/?p=xorg/proto/randrproto.git * - * 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. - * + * There are some major diffrences to be noted. Unlike the randr1.2 proto you + * need to create the memory object of the framebuffer yourself with the ttm + * buffer object interface. This object needs to be pinned. */ -typedef struct _drmModeGammaTriple { - uint16_t r, g, b; -} drmModeGammaTriple, *drmModeGammaTriplePtr; typedef struct _drmModeRes { @@ -130,53 +122,7 @@ typedef struct _drmModeOutput { } 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 ); @@ -189,11 +135,6 @@ extern void drmModeFreeOutput( drmModeOutputPtr ptr ); */ 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. @@ -215,13 +156,9 @@ extern int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, */ 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. + * Crtc functions */ /** @@ -236,19 +173,6 @@ 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 -- cgit v1.2.3 From eba00df1203040905d38bf0ef449d25d6dbdb72c Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 10 May 2007 13:16:05 +0100 Subject: Just some minor cleanups. --- linux-core/drm_fb.c | 5 ++--- linux-core/intel_sdvo.c | 3 --- shared-core/i915_drv.h | 1 + shared-core/i915_init.c | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index ef05341a..c0453258 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -106,8 +106,7 @@ 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; + unsigned long size = (8*1024*1024); /* FIXME */ int ret; info = framebuffer_alloc(sizeof(struct drmfb_par), device); @@ -126,7 +125,7 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) 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.smem_len = size; info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_DIRECTCOLOR; info->fix.accel = FB_ACCEL_NONE; diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 98c4034d..58aa432c 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -525,7 +525,6 @@ static bool intel_sdvo_get_preferred_input_timing(struct drm_output *output, static int intel_sdvo_get_clock_rate_mult(struct drm_output *output) { - struct intel_output *intel_output = output->driver_private; u8 response, status; intel_sdvo_write_cmd(output, SDVO_CMD_GET_CLOCK_RATE_MULT, NULL, 0); @@ -895,8 +894,6 @@ static enum drm_output_status intel_sdvo_detect(struct drm_output *output) static int intel_sdvo_get_modes(struct drm_output *output) { - struct drm_display_mode *modes; - /* set the bus switch and get the modes */ intel_sdvo_set_control_bus_switch(output, SDVO_CONTROL_BUS_DDC2); intel_ddc_get_modes(output); diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 946e464f..0513eed8 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -221,6 +221,7 @@ extern void i915_emit_breadcrumb(drm_device_t *dev); extern void i915_dispatch_flip(drm_device_t * dev, int pipes, int sync); extern int i915_emit_mi_flush(drm_device_t *dev, uint32_t flush); extern int i915_driver_firstopen(struct drm_device *dev); +extern int i915_dma_cleanup(drm_device_t * dev); /* i915_irq.c */ extern int i915_irq_emit(DRM_IOCTL_ARGS); diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 0c9ef4d4..43040e6e 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -202,7 +202,7 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) /* FIXME: need wrapper with PCI mem checks */ ret = drm_mem_reg_ioremap(dev, &dev_priv->ring_buffer->mem, - &dev_priv->ring.virtual_start); + (void **) &dev_priv->ring.virtual_start); if (ret) DRM_ERROR("error mapping ring buffer: %d\n", ret); -- cgit v1.2.3 From 5ce8aaae7251e60c078eda0a21894aae0e1d7a45 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 17 May 2007 12:46:36 +0100 Subject: Large changes for fbdev support. Change from DIRECTCOLOR to TRUECOLOR, and enable support for PSEUDOCOLOR. DIRECTCOLOR support needs more work. Add the ability to change the mode on the fbdev device. Support depth 8, 15, 16 and 24 (and 32). Add a /dev/fbX device per CRTC, but there's some code which doesn't allocate the fbX device unless the output is actually enabled. Read the code on this as it impacts the fbcon map flags. Pick CRTC's based on the available outputs. More work could be done here to match modes, so cloning could be achieved on outputs. This fits more inline with what the X code does. --- linux-core/drm_crtc.c | 234 +++++++++++++++++---------------------- linux-core/drm_crtc.h | 11 +- linux-core/drm_fb.c | 267 +++++++++++++++++++++++++++++++++++++++++---- linux-core/intel_display.c | 23 ++-- linux-core/intel_drv.h | 2 +- linux-core/intel_lvds.c | 12 +- linux-core/intel_sdvo.c | 14 +-- 7 files changed, 375 insertions(+), 188 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index a8f14e17..d710a4e7 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -466,51 +466,6 @@ done: return ret; } -/** - * drm_set_desired_modes - set a good mode on every CRTC & output - * @dev: DRM device - * - * LOCKING: - * Caller? (FIXME) - * - * Each CRTC may have a desired mode associated with it. This routine simply - * walks @dev's mode_config and sets the desired mode on every CRTC. Intended - * for use at startup time. - * - * RETURNS: - * True if modes were set, false otherwise. - */ -bool drm_set_desired_modes(struct drm_device *dev) -{ - struct drm_crtc *crtc; - struct drm_output *output, *list_output; - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - output = NULL; - - list_for_each_entry(list_output, &dev->mode_config.output_list, - head) { - if (list_output->crtc == crtc) { - output = list_output; - break; - } - } - /* Skip disabled crtcs */ - if (!output) { - DRM_DEBUG("skipping disabled crtc\n"); - continue; - } - - if (!drm_crtc_set_mode(crtc, crtc->desired_mode, - crtc->desired_x, crtc->desired_y)) - return false; - } - - drm_disable_unused_functions(dev); - return true; -} -EXPORT_SYMBOL(drm_set_desired_modes); - /** * drm_disable_unused_functions - disable unused objects * @dev: DRM device @@ -799,26 +754,82 @@ out_err: } /** - * drm_setup_output - setup an output structure - * @output: output to setup - * @crtc: CRTC this output belongs to - * @mode: desired mode for this output + * drm_pick_crtcs - pick crtcs for output devices + * @dev: DRM device * * LOCKING: * None. - * - * Setup @output with the parameters given, with its initial coordinates set - * at the origin. */ -static void drm_setup_output(struct drm_output *output, struct drm_crtc *crtc, - struct drm_display_mode *mode) +static void drm_pick_crtcs (drm_device_t *dev) { - output->crtc = crtc; - output->crtc->desired_mode = mode; - output->initial_x = 0; - output->initial_y = 0; + int c, o; + struct drm_output *output, *output_equal; + struct drm_crtc *crtc; + struct drm_display_mode *des_mode = NULL, *modes, *modes_equal; + + list_for_each_entry(output, &dev->mode_config.output_list, head) { + output->crtc = NULL; + + /* Don't hook up outputs that are disconnected ?? + * + * This is debateable. Do we want fixed /dev/fbX or + * dynamic on hotplug (need mode code for that though) ? + * + * If we don't hook up outputs now, then we only create + * /dev/fbX for the output that's enabled, that's good as + * the users console will be on that output. + * + * If we do hook up outputs that are disconnected now, then + * the user may end up having to muck about with the fbcon + * map flags to assign his console to the enabled output. Ugh. + */ + if (output->status != output_status_connected) + continue; + + des_mode = NULL; + list_for_each_entry(des_mode, &output->modes, head) { + if (des_mode->flags & DRM_MODE_TYPE_PREFERRED) + break; + } + + c = -1; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + c++; + if ((output->possible_crtcs & (1 << c)) == 0) + continue; + +#if 0 /* should we try and clone ?? - code not tested - FIXME */ + o = -1; + list_for_each_entry(output_equal, &dev->mode_config.output_list, head) { + o++; + if (output->id == output_equal->id) + continue; + + list_for_each_entry(modes, &output->modes, head) { + list_for_each_entry(modes_equal, &output_equal->modes, head) { + if (drm_mode_equal (modes, modes_equal)) { + if ((output->possible_clones & (1 << o))) { + goto clone; + } + } + } + } + } + +clone: +#endif + /* Found a CRTC to attach to, do it ! */ + output->crtc = crtc; + output->crtc->desired_mode = des_mode; + output->initial_x = 0; + output->initial_y = 0; + DRM_DEBUG("Desired mode for CRTC %d is %dx%x\n",c,des_mode->hdisplay,des_mode->vdisplay); + break; + } + } } + /** * drm_initial_config - setup a sane initial output configuration * @dev: DRM device @@ -831,109 +842,61 @@ static void drm_setup_output(struct drm_output *output, struct drm_crtc *crtc, * At the moment, this is a cloned configuration across all heads with * a new framebuffer object as the backing store. * - * FIXME: return value and better initial config. - * * RETURNS: * Zero if everything went ok, nonzero otherwise. */ bool drm_initial_config(drm_device_t *dev, bool can_grow) { /* do a hardcoded initial configuration here */ - struct drm_crtc *crtc, *vga_crtc = NULL, *tmds_crtc = NULL, - *lvds_crtc = NULL; + struct drm_display_mode *des_mode = NULL; struct drm_output *output; struct drm_framebuffer *fb; drm_buffer_object_t *fbo; unsigned long size, bytes_per_pixel; - fb = drm_framebuffer_create(dev); - if (!fb) { - DRM_ERROR("failed to allocate fb.\n"); - return true; - } - - /* bind both CRTCs to this fb */ - /* only initialise one crtc to enabled state */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - crtc->fb = fb; - if (!vga_crtc) { - vga_crtc = crtc; - crtc->enabled = 1; - crtc->desired_x = 0; - crtc->desired_y = 0; - } else { - if (!lvds_crtc) { - lvds_crtc = crtc; - crtc->enabled = 1; - crtc->desired_x = 0; - crtc->desired_y = 0; - } - if (!tmds_crtc) { - tmds_crtc = crtc; - crtc->enabled = 1; - crtc->desired_x = 0; - crtc->desired_y = 0; - } - } - } - drm_crtc_probe_output_modes(dev, 2048, 2048); - /* hard bind the CRTCS */ + drm_pick_crtcs(dev); - /* bind analog output to one crtc */ list_for_each_entry(output, &dev->mode_config.output_list, head) { - struct drm_display_mode *des_mode = NULL; - if (list_empty(&output->modes)) + /* can't setup the output if there's no assigned crtc or mode */ + if (!output->crtc || !output->crtc->desired_mode) continue; - /* Get the first preferred moded */ - list_for_each_entry(des_mode, &output->modes, head) { - if (des_mode->flags & DRM_MODE_TYPE_PREFERRED) - break; + fb = drm_framebuffer_create(dev); + if (!fb) { + DRM_ERROR("failed to allocate fb.\n"); + return true; } + output->crtc->fb = fb; + des_mode = output->crtc->desired_mode; - if (!des_mode) - continue; - - if (!strncmp(output->name, "VGA", 3)) { - DRM_DEBUG("VGA preferred mode: %s\n", des_mode->name); - drm_setup_output(output, vga_crtc, des_mode); - } else if (!strncmp(output->name, "TMDS", 4)) { - DRM_DEBUG("TMDS preferred mode: %s\n", des_mode->name); - drm_setup_output(output, tmds_crtc, des_mode); - } else if (!strncmp(output->name, "LVDS", 3)) { - DRM_DEBUG("LVDS preferred mode: %s\n", des_mode->name); - drm_setup_output(output, lvds_crtc, des_mode); - } else - output->crtc = NULL; - - /* FB config is max of above desired resolutions */ - /* FIXME: per-output FBs/CRTCs */ if (des_mode->hdisplay > fb->width) { fb->width = des_mode->hdisplay; fb->pitch = fb->width; } if (des_mode->vdisplay > fb->height) fb->height = des_mode->vdisplay; - } - /* FIXME: multiple depths */ - bytes_per_pixel = 4; - fb->bits_per_pixel = bytes_per_pixel * 8; - fb->depth = bytes_per_pixel * 8; - size = fb->width * fb->height * bytes_per_pixel; - drm_buffer_object_create(dev, size, drm_bo_type_kernel, + /* FIXME: multiple depths */ + bytes_per_pixel = 4; + fb->bits_per_pixel = 32; + fb->depth = 24; + size = fb->pitch * fb->height * bytes_per_pixel; + /* FIXME - what about resizeable objects ??? */ + 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, 0, 0, &fbo); - DRM_DEBUG("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width, - fb->height, fbo->offset, fbo); - fb->offset = fbo->offset; - fb->bo = fbo; - drmfb_probe(dev, fb); + printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width, + fb->height, fbo->offset, fbo); + fb->offset = fbo->offset; + fb->bo = fbo; + drmfb_probe(dev, output->crtc); + } + drm_disable_unused_functions(dev); return false; } @@ -1582,17 +1545,20 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, r.buffer_id = fb->id; list_add(&fb->filp_head, &priv->fbs); + + if (copy_to_user(argp, &r, sizeof(r))) + return -EFAULT; + /* bind the fb to the crtc for now */ { struct drm_crtc *crtc; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { crtc->fb = fb; + + drmfb_probe(dev, crtc); } } - if (copy_to_user(argp, &r, sizeof(r))) - return -EFAULT; - drmfb_probe(dev, fb); return 0; } @@ -1629,6 +1595,7 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp, } drmfb_remove(dev, fb); + /* TODO check if we own the buffer */ /* TODO release all crtc connected to the framebuffer */ /* bind the fb to the crtc for now */ @@ -1711,7 +1678,6 @@ void drm_fb_release(struct file *filp) list_del(&fb->filp_head); drmfb_remove(dev, fb); drm_framebuffer_destroy(fb); - } } diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 12c7eef1..fa143e6e 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -294,8 +294,8 @@ struct drm_crtc_funcs { 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); + void (*gamma_set)(struct drm_crtc *crtc, u16 r, u16 g, u16 b, + int regno); /* Driver cleanup routine */ void (*cleanup)(struct drm_crtc *crtc); }; @@ -320,7 +320,7 @@ struct drm_crtc { int id; /* idr assigned */ - /* framebuffer the CRTC is currently bound to */ + /* framebuffer the output is currently bound to */ struct drm_framebuffer *fb; bool enabled; @@ -439,6 +439,7 @@ struct drm_output { void *driver_private; u32 user_mode_ids[DRM_OUTPUT_MAX_UMODES]; + }; /** @@ -498,6 +499,7 @@ extern void drm_mode_debug_printmodeline(struct drm_device *dev, extern void drm_mode_config_init(struct drm_device *dev); extern void drm_mode_config_cleanup(struct drm_device *dev); extern void drm_mode_set_name(struct drm_display_mode *mode); +extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2); extern void drm_disable_unused_functions(struct drm_device *dev); extern struct drm_display_mode *drm_mode_create(struct drm_device *dev); @@ -519,8 +521,7 @@ extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); extern bool drm_initial_config(struct drm_device *dev, bool cangrow); extern void drm_framebuffer_set_object(struct drm_device *dev, unsigned long handle); -extern bool drm_set_desired_modes(struct drm_device *dev); -extern int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb); +extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); /* IOCTLs */ diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index c0453258..8fd0f620 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -39,9 +39,11 @@ #include #include "drmP.h" +#include "drm_crtc.h" + struct drmfb_par { struct drm_device *dev; - struct drm_framebuffer *fb; + struct drm_crtc *crtc; }; static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green, @@ -49,11 +51,20 @@ static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green, struct fb_info *info) { struct drmfb_par *par = info->par; - struct drm_framebuffer *fb = par->fb; - if (regno > 17) + struct drm_framebuffer *fb = par->crtc->fb; + struct drm_crtc *crtc = par->crtc; + + if (regno > 255) return 1; - if (regno < 16) { + if (fb->depth == 8) { + if (crtc->funcs->gamma_set) { + crtc->funcs->gamma_set(crtc, red, green, blue, regno); + } + return 0; + } + + if (regno < 16) { switch (fb->depth) { case 15: fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | @@ -72,8 +83,118 @@ static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green, ((blue & 0xff00) >> 8); break; } + } + + return 0; +} + +static int drmfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct drmfb_par *par = info->par; + struct drm_device *dev = par->dev; + struct drm_display_mode *drm_mode; + struct drm_output *output; + int depth; + + if (!var->pixclock) + return -EINVAL; + + /* Need to resize the fb object !!! */ + if (var->xres > fb->width || var->yres > fb->height) { + DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height); + DRM_ERROR("Need resizing code.\n"); + return -EINVAL; + } + + switch (var->bits_per_pixel) { + case 16: + depth = (var->green.length == 6) ? 16 : 15; + break; + case 32: + depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + depth = var->bits_per_pixel; + break; + } + + switch (depth) { + case 8: + var->red.offset = 0; + var->green.offset = 0; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 15: + var->red.offset = 10; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 5; + var->blue.length = 5; + var->transp.length = 1; + var->transp.offset = 15; + break; + case 16: + var->red.offset = 11; + var->green.offset = 6; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 24: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 32: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 8; + var->transp.offset = 24; + break; + default: + return -EINVAL; + } + +#if 0 + /* Here we walk the output mode list and look for modes. If we haven't + * got it, then bail. Not very nice, so this is disabled. + * In the set_par code, we create our mode based on the incoming + * parameters. Nicer, but may not be desired by some. + */ + list_for_each_entry(output, &dev->mode_config.output_list, head) { + if (output->crtc == par->crtc) + break; + } + + list_for_each_entry(drm_mode, &output->modes, head) { + if (drm_mode->hdisplay == var->xres && + drm_mode->vdisplay == var->yres && + drm_mode->clock != 0) + break; } + if (!drm_mode) + return -EINVAL; +#endif + return 0; } @@ -81,9 +202,74 @@ static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green, static int drmfb_set_par(struct fb_info *info) { struct drmfb_par *par = info->par; + struct drm_framebuffer *fb = par->crtc->fb; struct drm_device *dev = par->dev; + struct drm_display_mode *drm_mode; + struct fb_var_screeninfo *var = &info->var; + struct drm_output *output; + + switch (var->bits_per_pixel) { + case 16: + fb->depth = (var->green.length == 6) ? 16 : 15; + break; + case 32: + fb->depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + fb->depth = var->bits_per_pixel; + break; + } + + fb->bits_per_pixel = var->bits_per_pixel; + + info->fix.line_length = fb->pitch * ((fb->bits_per_pixel + 1) / 8); + info->fix.smem_len = info->fix.line_length * fb->height; + info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + + info->screen_size = info->fix.smem_len; /* ??? */ + + /* Should we walk the output's modelist or just create our own ??? + * For now, we create and destroy a mode based on the incoming + * parameters. But there's commented out code below which scans + * the output list too. + */ +#if 0 + list_for_each_entry(output, &dev->mode_config.output_list, head) { + if (output->crtc == par->crtc) + break; + } + + list_for_each_entry(drm_mode, &output->modes, head) { + if (drm_mode->hdisplay == var->xres && + drm_mode->vdisplay == var->yres && + drm_mode->clock != 0) + break; + } +#else + drm_mode = drm_mode_create(dev); + drm_mode->hdisplay = var->xres; + drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin; + drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len; + drm_mode->htotal = drm_mode->hsync_end + var->left_margin; + drm_mode->vdisplay = var->yres; + drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin; + drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len; + drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin; + drm_mode->clock = PICOS2KHZ(var->pixclock); + drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); + drm_mode_set_name(drm_mode); +#endif + + if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) + return -EINVAL; + + /* Have to destroy our created mode if we're not searching the mode + * list for it. + */ +#if 1 + drm_mode_destroy(dev, drm_mode); +#endif - drm_set_desired_modes(dev); return 0; } @@ -94,6 +280,7 @@ static struct fb_ops drmfb_ops = { // .fb_write = drmfb_write, // .fb_release = drmfb_release, // .fb_ioctl = drmfb_ioctl, + .fb_check_var = drmfb_check_var, .fb_set_par = drmfb_set_par, .fb_setcolreg = drmfb_setcolreg, .fb_fillrect = cfb_fillrect, @@ -101,12 +288,13 @@ static struct fb_ops drmfb_ops = { .fb_imageblit = cfb_imageblit, }; -int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) +int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc) { struct fb_info *info; + struct drm_framebuffer *fb = crtc->fb; struct drmfb_par *par; struct device *device = &dev->pdev->dev; - unsigned long size = (8*1024*1024); /* FIXME */ + struct drm_display_mode *mode = crtc->desired_mode; int ret; info = framebuffer_alloc(sizeof(struct drmfb_par), device); @@ -119,20 +307,20 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) par = info->par; par->dev = dev; - par->fb = fb; + par->crtc = crtc; info->fbops = &drmfb_ops; strcpy(info->fix.id, "drmfb"); - info->fix.smem_start = fb->offset + dev->mode_config.fb_base; - info->fix.smem_len = size; info->fix.type = FB_TYPE_PACKED_PIXELS; - info->fix.visual = FB_VISUAL_DIRECTCOLOR; + info->fix.visual = FB_VISUAL_TRUECOLOR; info->fix.accel = FB_ACCEL_NONE; info->fix.type_aux = 0; info->fix.mmio_start = 0; info->fix.mmio_len = 0; info->fix.line_length = fb->pitch * ((fb->bits_per_pixel + 1) / 8); + info->fix.smem_start = fb->offset + dev->mode_config.fb_base; + info->fix.smem_len = info->fix.line_length * fb->height; info->flags = FBINFO_DEFAULT; @@ -141,11 +329,9 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) DRM_ERROR("error mapping fb: %d\n", ret); info->screen_base = fb->virtual_base; - info->screen_size = size; + info->screen_size = info->fix.smem_len; /* ??? */ 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; @@ -155,24 +341,67 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) info->var.width = -1; info->var.vmode = FB_VMODE_NONINTERLACED; + info->var.xres = mode->hdisplay; + info->var.right_margin = mode->hsync_start - mode->hdisplay; + info->var.hsync_len = mode->hsync_end - mode->hsync_start; + info->var.left_margin = mode->htotal - mode->hsync_end; + info->var.yres = mode->vdisplay; + info->var.lower_margin = mode->vsync_start - mode->vdisplay; + info->var.vsync_len = mode->vsync_end - mode->vsync_start; + info->var.upper_margin = mode->vtotal - mode->vsync_end; + info->var.pixclock = 10000000 / mode->htotal * 1000 / + mode->vtotal * 100000 / mode->vrefresh; + DRM_DEBUG("fb depth is %d\n", fb->depth); switch(fb->depth) { case 8: + info->var.red.offset = 0; + info->var.green.offset = 0; + info->var.blue.offset = 0; + info->var.red.length = 8; /* 8bit DAC */ + info->var.green.length = 8; + info->var.blue.length = 8; + info->var.transp.offset = 0; + info->var.transp.length = 0; + break; case 15: + info->var.red.offset = 10; + info->var.green.offset = 5; + info->var.blue.offset = 0; + info->var.red.length = info->var.green.length = + info->var.blue.length = 5; + info->var.transp.offset = 15; + info->var.transp.length = 1; + break; case 16: + info->var.red.offset = 11; + info->var.green.offset = 5; + info->var.blue.offset = 0; + info->var.red.length = 5; + info->var.green.length = 6; + info->var.blue.length = 5; + info->var.transp.offset = 0; + info->var.transp.length = 0; break; - default: case 24: + info->var.red.offset = 16; + info->var.green.offset = 8; + info->var.blue.offset = 0; + info->var.red.length = info->var.green.length = + info->var.blue.length = 8; + info->var.transp.offset = 0; + info->var.transp.length = 0; + break; case 32: info->var.red.offset = 16; info->var.green.offset = 8; info->var.blue.offset = 0; info->var.red.length = info->var.green.length = info->var.blue.length = 8; - if (fb->depth == 32) { - info->var.transp.offset = 24; - info->var.transp.length = 8; - } + info->var.transp.offset = 24; + info->var.transp.length = 8; + break; + default: break; } diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 7d581175..7879965e 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -787,6 +787,9 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, else dpll |= PLL_REF_INPUT_DREFCLK; + /* setup pipeconf */ + pipeconf = I915_READ(pipeconf_reg); + /* Set up the display plane register */ dspcntr = DISPPLANE_GAMMA_ENABLE; @@ -814,7 +817,6 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, else dspcntr |= DISPPLANE_SEL_PIPE_B; - pipeconf = I915_READ(pipeconf_reg); if (pipe == 0 && !IS_I965G(dev)) { /* Enable pixel doubling when the dot clock is > 90% of the (display) * core speed. @@ -955,19 +957,14 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) } /** Sets the color ramps on behalf of RandR */ -static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, int size) +static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, + u16 blue, int regno) { struct intel_crtc *intel_crtc = crtc->driver_private; - int i; - for (i = 0; i < 256; i++) { - intel_crtc->lut_r[i] = red[i] >> 8; - intel_crtc->lut_g[i] = green[i] >> 8; - intel_crtc->lut_b[i] = blue[i] >> 8; - } - - intel_crtc_load_lut(crtc); + intel_crtc->lut_r[regno] = red >> 8; + intel_crtc->lut_g[regno] = green >> 8; + intel_crtc->lut_b[regno] = blue >> 8; } /* Returns the clock of the currently programmed mode of the given pipe. */ @@ -1176,7 +1173,8 @@ static void intel_setup_outputs(drm_device_t *dev) (1 << INTEL_OUTPUT_SDVO)); break; case INTEL_OUTPUT_ANALOG: - crtc_mask = ((1 << 0)); + crtc_mask = ((1 << 0)| + (1 << 1)); clone_mask = ((1 << INTEL_OUTPUT_ANALOG) | (1 << INTEL_OUTPUT_DVO) | (1 << INTEL_OUTPUT_SDVO)); @@ -1223,7 +1221,6 @@ void intel_modeset_init(drm_device_t *dev) intel_setup_outputs(dev); //drm_initial_config(dev, false); - //drm_set_desired_modes(dev); } void intel_modeset_cleanup(drm_device_t *dev) diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index aa33437d..fdf260e9 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -72,7 +72,7 @@ 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); + struct drm_crtc *crtc); extern void intel_wait_for_vblank(drm_device_t *dev); extern struct drm_crtc *intel_get_crtc_from_pipe(drm_device_t *dev, int pipe); diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 74b040ba..942eb2ab 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -164,6 +164,13 @@ static bool intel_lvds_mode_fixup(struct drm_output *output, struct intel_crtc *intel_crtc = output->crtc->driver_private; struct drm_output *tmp_output; + /* Should never happen!! */ + if (!IS_I965G(dev) && intel_crtc->pipe == 0) { + printk(KERN_ERR "Can't support LVDS on pipe A\n"); + return false; + } + + /* Should never happen!! */ list_for_each_entry(tmp_output, &dev->mode_config.output_list, head) { if (tmp_output != output && tmp_output->crtc == output->crtc) { printk(KERN_ERR "Can't enable LVDS and another " @@ -172,11 +179,6 @@ static bool intel_lvds_mode_fixup(struct drm_output *output, } } - 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, diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 58aa432c..c02fd958 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -1010,26 +1010,18 @@ void intel_sdvo_init(drm_device_t *dev, int output_device) memset(&sdvo_priv->active_outputs, 0, sizeof(sdvo_priv->active_outputs)); - /* TODO, CVBS, SVID, YPRPB & SCART outputs. - * drm_initial_config probably wants tweaking too to support the - * above. But has fixed VGA, TMDS and LVDS checking code. That should - * be dealt with. - */ + /* TODO, CVBS, SVID, YPRPB & SCART outputs. */ if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0) { sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0; output->subpixel_order = SubPixelHorizontalRGB; - /* drm_initial_config wants this name, but should be RGB */ - /* Use this for now.... */ - name_prefix="VGA"; + name_prefix="RGB"; } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1) { sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1; output->subpixel_order = SubPixelHorizontalRGB; - /* drm_initial_config wants this name, but should be RGB */ - /* Use this for now.... */ - name_prefix="VGA"; + name_prefix="RGB"; } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) { -- cgit v1.2.3 From 2222bd767f9fc02d05ebd0f35a8ceeff2f032c94 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 17 May 2007 13:19:56 +0100 Subject: Fix build problem --- linux-core/drm_fb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index 8fd0f620..27d80d7a 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -92,6 +92,7 @@ static int drmfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct drmfb_par *par = info->par; struct drm_device *dev = par->dev; + struct drm_framebuffer *fb = par->crtc->fb; struct drm_display_mode *drm_mode; struct drm_output *output; int depth; -- cgit v1.2.3 From fd63ea971322246734fca5977a800c3ef51cc3fe Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 17 May 2007 17:00:11 +0100 Subject: Grab the default mode if the preferred mode isn't available. Fix an overflow problem. --- linux-core/drm_crtc.c | 16 ++++++++++++++-- linux-core/drm_fb.c | 4 +++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index d710a4e7..13a01fee 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -252,7 +252,7 @@ EXPORT_SYMBOL(drm_crtc_in_use); * Detailed mode info for a standard 640x480@60Hz monitor */ static struct drm_display_mode std_mode[] = { - { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656, + { DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 25200, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */ }; @@ -792,6 +792,18 @@ static void drm_pick_crtcs (drm_device_t *dev) break; } + + /* No preferred mode, let's select another which should pick + * the default 640x480 if nothing else is here. + * + */ + if (!des_mode || !(des_mode->flags & DRM_MODE_TYPE_PREFERRED)) { + list_for_each_entry(des_mode, &output->modes, head) { + if (des_mode->flags & DRM_MODE_TYPE_DEFAULT) + break; + } + } + c = -1; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { c++; @@ -823,7 +835,7 @@ clone: output->crtc->desired_mode = des_mode; output->initial_x = 0; output->initial_y = 0; - DRM_DEBUG("Desired mode for CRTC %d is %dx%x\n",c,des_mode->hdisplay,des_mode->vdisplay); + DRM_DEBUG("Desired mode for CRTC %d is %s\n",c,des_mode->name); break; } } diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index 27d80d7a..118967bf 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -351,7 +351,9 @@ int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->var.vsync_len = mode->vsync_end - mode->vsync_start; info->var.upper_margin = mode->vtotal - mode->vsync_end; info->var.pixclock = 10000000 / mode->htotal * 1000 / - mode->vtotal * 100000 / mode->vrefresh; + mode->vtotal * 100; + /* avoid overflow */ + info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; DRM_DEBUG("fb depth is %d\n", fb->depth); switch(fb->depth) { -- cgit v1.2.3