diff options
89 files changed, 1391 insertions, 1166 deletions
diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 528429252f0f..02e52d543e4b 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -241,6 +241,8 @@ struct ast_fbdev { void *sysram; int size; struct ttm_bo_kmap_obj mapping; + int x1, y1, x2, y2; /* dirty rect */ + spinlock_t dirty_lock; }; #define to_ast_crtc(x) container_of(x, struct ast_crtc, base) diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c index 34931fe7d2c5..fbc0823cfa18 100644 --- a/drivers/gpu/drm/ast/ast_fb.c +++ b/drivers/gpu/drm/ast/ast_fb.c @@ -53,16 +53,52 @@ static void ast_dirty_update(struct ast_fbdev *afbdev, int bpp = (afbdev->afb.base.bits_per_pixel + 7)/8; int ret; bool unmap = false; + bool store_for_later = false; + int x2, y2; + unsigned long flags; obj = afbdev->afb.obj; bo = gem_to_ast_bo(obj); + /* + * try and reserve the BO, if we fail with busy + * then the BO is being moved and we should + * store up the damage until later. + */ ret = ast_bo_reserve(bo, true); if (ret) { - DRM_ERROR("failed to reserve fb bo\n"); + if (ret != -EBUSY) + return; + + store_for_later = true; + } + + x2 = x + width - 1; + y2 = y + height - 1; + spin_lock_irqsave(&afbdev->dirty_lock, flags); + + if (afbdev->y1 < y) + y = afbdev->y1; + if (afbdev->y2 > y2) + y2 = afbdev->y2; + if (afbdev->x1 < x) + x = afbdev->x1; + if (afbdev->x2 > x2) + x2 = afbdev->x2; + + if (store_for_later) { + afbdev->x1 = x; + afbdev->x2 = x2; + afbdev->y1 = y; + afbdev->y2 = y2; + spin_unlock_irqrestore(&afbdev->dirty_lock, flags); return; } + afbdev->x1 = afbdev->y1 = INT_MAX; + afbdev->x2 = afbdev->y2 = 0; + spin_unlock_irqrestore(&afbdev->dirty_lock, flags); + if (!bo->kmap.virtual) { ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); if (ret) { @@ -72,10 +108,10 @@ static void ast_dirty_update(struct ast_fbdev *afbdev, } unmap = true; } - for (i = y; i < y + height; i++) { + for (i = y; i <= y2; i++) { /* assume equal stride for now */ src_offset = dst_offset = i * afbdev->afb.base.pitches[0] + (x * bpp); - memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, width * bpp); + memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, (x2 - x + 1) * bpp); } if (unmap) @@ -292,6 +328,7 @@ int ast_fbdev_init(struct drm_device *dev) ast->fbdev = afbdev; afbdev->helper.funcs = &ast_fb_helper_funcs; + spin_lock_init(&afbdev->dirty_lock); ret = drm_fb_helper_init(dev, &afbdev->helper, 1, 1); if (ret) { diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c index 3602731a6112..09da3393c527 100644 --- a/drivers/gpu/drm/ast/ast_ttm.c +++ b/drivers/gpu/drm/ast/ast_ttm.c @@ -316,7 +316,7 @@ int ast_bo_reserve(struct ast_bo *bo, bool no_wait) ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0); if (ret) { - if (ret != -ERESTARTSYS) + if (ret != -ERESTARTSYS && ret != -EBUSY) DRM_ERROR("reserve failed %p\n", bo); return ret; } diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h index 6e0cc724e5a2..7ca059596887 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.h +++ b/drivers/gpu/drm/cirrus/cirrus_drv.h @@ -154,6 +154,8 @@ struct cirrus_fbdev { struct list_head fbdev_list; void *sysram; int size; + int x1, y1, x2, y2; /* dirty rect */ + spinlock_t dirty_lock; }; struct cirrus_bo { diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c index e25afccaf85b..3541b567bbd8 100644 --- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c +++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c @@ -27,16 +27,51 @@ static void cirrus_dirty_update(struct cirrus_fbdev *afbdev, int bpp = (afbdev->gfb.base.bits_per_pixel + 7)/8; int ret; bool unmap = false; + bool store_for_later = false; + int x2, y2; + unsigned long flags; obj = afbdev->gfb.obj; bo = gem_to_cirrus_bo(obj); + /* + * try and reserve the BO, if we fail with busy + * then the BO is being moved and we should + * store up the damage until later. + */ ret = cirrus_bo_reserve(bo, true); if (ret) { - DRM_ERROR("failed to reserve fb bo\n"); + if (ret != -EBUSY) + return; + store_for_later = true; + } + + x2 = x + width - 1; + y2 = y + height - 1; + spin_lock_irqsave(&afbdev->dirty_lock, flags); + + if (afbdev->y1 < y) + y = afbdev->y1; + if (afbdev->y2 > y2) + y2 = afbdev->y2; + if (afbdev->x1 < x) + x = afbdev->x1; + if (afbdev->x2 > x2) + x2 = afbdev->x2; + + if (store_for_later) { + afbdev->x1 = x; + afbdev->x2 = x2; + afbdev->y1 = y; + afbdev->y2 = y2; + spin_unlock_irqrestore(&afbdev->dirty_lock, flags); return; } + afbdev->x1 = afbdev->y1 = INT_MAX; + afbdev->x2 = afbdev->y2 = 0; + spin_unlock_irqrestore(&afbdev->dirty_lock, flags); + if (!bo->kmap.virtual) { ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); if (ret) { @@ -268,6 +303,7 @@ int cirrus_fbdev_init(struct cirrus_device *cdev) cdev->mode_info.gfbdev = gfbdev; gfbdev->helper.funcs = &cirrus_fb_helper_funcs; + spin_lock_init(&gfbdev->dirty_lock); ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper, cdev->num_crtc, CIRRUSFB_CONN_LIMIT); diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c index 1413a26e4905..2ed8cfc740c9 100644 --- a/drivers/gpu/drm/cirrus/cirrus_ttm.c +++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c @@ -321,7 +321,7 @@ int cirrus_bo_reserve(struct cirrus_bo *bo, bool no_wait) ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0); if (ret) { - if (ret != -ERESTARTSYS) + if (ret != -ERESTARTSYS && ret != -EBUSY) DRM_ERROR("reserve failed %p\n", bo); return ret; } diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index c577baec416f..e7e92429d10f 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -78,6 +78,10 @@ void drm_warn_on_modeset_not_all_locked(struct drm_device *dev) { struct drm_crtc *crtc; + /* Locking is currently fubar in the panic handler. */ + if (oops_in_progress) + return; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) WARN_ON(!mutex_is_locked(&crtc->mutex)); @@ -178,9 +182,6 @@ static struct drm_prop_enum_list drm_dirty_info_enum_list[] = { { DRM_MODE_DIRTY_ANNOTATE, "Annotate" }, }; -DRM_ENUM_NAME_FN(drm_get_dirty_info_name, - drm_dirty_info_enum_list) - struct drm_conn_prop_enum_list { int type; char *name; @@ -249,6 +250,7 @@ char *drm_get_connector_status_name(enum drm_connector_status status) else return "unknown"; } +EXPORT_SYMBOL(drm_get_connector_status_name); /** * drm_mode_object_get - allocate a new modeset identifier @@ -706,7 +708,6 @@ int drm_connector_init(struct drm_device *dev, connector->connector_type = connector_type; connector->connector_type_id = ++drm_connector_enum_list[connector_type].count; /* TODO */ - INIT_LIST_HEAD(&connector->user_modes); INIT_LIST_HEAD(&connector->probed_modes); INIT_LIST_HEAD(&connector->modes); connector->edid_blob_ptr = NULL; @@ -747,9 +748,6 @@ void drm_connector_cleanup(struct drm_connector *connector) list_for_each_entry_safe(mode, t, &connector->modes, head) drm_mode_remove(connector, mode); - list_for_each_entry_safe(mode, t, &connector->user_modes, head) - drm_mode_remove(connector, mode); - drm_mode_object_put(dev, &connector->base); list_del(&connector->head); dev->mode_config.num_connector--; @@ -1120,7 +1118,7 @@ int drm_mode_create_dirty_info_property(struct drm_device *dev) } EXPORT_SYMBOL(drm_mode_create_dirty_info_property); -int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) +static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) { uint32_t total_objects = 0; @@ -2616,192 +2614,6 @@ void drm_fb_release(struct drm_file *priv) mutex_unlock(&priv->fbs_lock); } -/** - * drm_mode_attachmode - add a mode to the user mode list - * @dev: DRM device - * @connector: connector to add the mode to - * @mode: mode to add - * - * Add @mode to @connector's user mode list. - */ -static void drm_mode_attachmode(struct drm_device *dev, - struct drm_connector *connector, - struct drm_display_mode *mode) -{ - list_add_tail(&mode->head, &connector->user_modes); -} - -int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc, - const struct drm_display_mode *mode) -{ - struct drm_connector *connector; - int ret = 0; - struct drm_display_mode *dup_mode, *next; - LIST_HEAD(list); - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (!connector->encoder) - continue; - if (connector->encoder->crtc == crtc) { - dup_mode = drm_mode_duplicate(dev, mode); - if (!dup_mode) { - ret = -ENOMEM; - goto out; - } - list_add_tail(&dup_mode->head, &list); - } - } - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (!connector->encoder) - continue; - if (connector->encoder->crtc == crtc) - list_move_tail(list.next, &connector->user_modes); - } - - WARN_ON(!list_empty(&list)); - - out: - list_for_each_entry_safe(dup_mode, next, &list, head) - drm_mode_destroy(dev, dup_mode); - - return ret; -} -EXPORT_SYMBOL(drm_mode_attachmode_crtc); - -static int drm_mode_detachmode(struct drm_device *dev, - struct drm_connector *connector, - struct drm_display_mode *mode) -{ - int found = 0; - int ret = 0; - struct drm_display_mode *match_mode, *t; - - list_for_each_entry_safe(match_mode, t, &connector->user_modes, head) { - if (drm_mode_equal(match_mode, mode)) { - list_del(&match_mode->head); - drm_mode_destroy(dev, match_mode); - found = 1; - break; - } - } - - if (!found) - ret = -EINVAL; - - return ret; -} - -int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode) -{ - struct drm_connector *connector; - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - drm_mode_detachmode(dev, connector, mode); - } - return 0; -} -EXPORT_SYMBOL(drm_mode_detachmode_crtc); - -/** - * drm_fb_attachmode - Attach a user mode to an connector - * @dev: drm device for the ioctl - * @data: data pointer for the ioctl - * @file_priv: drm file for the ioctl call - * - * This attaches a user specified mode to an connector. - * Called by the user via ioctl. - * - * RETURNS: - * Zero on success, errno on failure. - */ -int drm_mode_attachmode_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_mode_cmd *mode_cmd = data; - struct drm_connector *connector; - struct drm_display_mode *mode; - struct drm_mode_object *obj; - struct drm_mode_modeinfo *umode = &mode_cmd->mode; - int ret; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - drm_modeset_lock_all(dev); - - obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); - if (!obj) { - ret = -EINVAL; - goto out; - } - connector = obj_to_connector(obj); - - mode = drm_mode_create(dev); - if (!mode) { - ret = -ENOMEM; - goto out; - } - - ret = drm_crtc_convert_umode(mode, umode); - if (ret) { - DRM_DEBUG_KMS("Invalid mode\n"); - drm_mode_destroy(dev, mode); - goto out; - } - - drm_mode_attachmode(dev, connector, mode); -out: - drm_modeset_unlock_all(dev); - return ret; -} - - -/** - * drm_fb_detachmode - Detach a user specified mode from an connector - * @dev: drm device for the ioctl - * @data: data pointer for the ioctl - * @file_priv: drm file for the ioctl call - * - * Called by the user via ioctl. - * - * RETURNS: - * Zero on success, errno on failure. - */ -int drm_mode_detachmode_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_object *obj; - struct drm_mode_mode_cmd *mode_cmd = data; - struct drm_connector *connector; - struct drm_display_mode mode; - struct drm_mode_modeinfo *umode = &mode_cmd->mode; - int ret; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - drm_modeset_lock_all(dev); - - obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); - if (!obj) { - ret = -EINVAL; - goto out; - } - connector = obj_to_connector(obj); - - ret = drm_crtc_convert_umode(&mode, umode); - if (ret) { - DRM_DEBUG_KMS("Invalid mode\n"); - goto out; - } - - ret = drm_mode_detachmode(dev, connector, &mode); -out: - drm_modeset_unlock_all(dev); - return ret; -} - struct drm_property *drm_property_create(struct drm_device *dev, int flags, const char *name, int num_values) { diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index e974f9309b72..ed1334e27c33 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -121,6 +121,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, connector->helper_private; int count = 0; int mode_flags = 0; + bool verbose_prune = true; DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, drm_get_connector_name(connector)); @@ -149,6 +150,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n", connector->base.id, drm_get_connector_name(connector)); drm_mode_connector_update_edid_property(connector, NULL); + verbose_prune = false; goto prune; } @@ -182,7 +184,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, } prune: - drm_mode_prune_invalid(dev, &connector->modes, true); + drm_mode_prune_invalid(dev, &connector->modes, verbose_prune); if (list_empty(&connector->modes)) return 0; @@ -1005,12 +1007,20 @@ static void output_poll_execute(struct work_struct *work) continue; connector->status = connector->funcs->detect(connector, false); - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n", - connector->base.id, - drm_get_connector_name(connector), - old_status, connector->status); - if (old_status != connector->status) + if (old_status != connector->status) { + const char *old, *new; + + old = drm_get_connector_status_name(old_status); + new = drm_get_connector_status_name(connector->status); + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] " + "status updated from %s to %s\n", + connector->base.id, + drm_get_connector_name(connector), + old, new); + changed = true; + } } mutex_unlock(&dev->mode_config.mutex); @@ -1083,10 +1093,11 @@ void drm_helper_hpd_irq_event(struct drm_device *dev) old_status = connector->status; connector->status = connector->funcs->detect(connector, false); - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n", + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", connector->base.id, drm_get_connector_name(connector), - old_status, connector->status); + drm_get_connector_status_name(old_status), + drm_get_connector_status_name(connector->status)); if (old_status != connector->status) changed = true; } diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 0ac1991a470a..9cc247f55502 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -57,10 +57,10 @@ static int drm_version(struct drm_device *dev, void *data, struct drm_file *file_priv); #define DRM_IOCTL_DEF(ioctl, _func, _flags) \ - [DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0} + [DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0, .name = #ioctl} /** Ioctl table */ -static struct drm_ioctl_desc drm_ioctls[] = { +static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0), DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0), @@ -150,8 +150,8 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), @@ -375,7 +375,7 @@ long drm_ioctl(struct file *filp, { struct drm_file *file_priv = filp->private_data; struct drm_device *dev; - struct drm_ioctl_desc *ioctl; + const struct drm_ioctl_desc *ioctl = NULL; drm_ioctl_t *func; unsigned int nr = DRM_IOCTL_NR(cmd); int retcode = -EINVAL; @@ -392,11 +392,6 @@ long drm_ioctl(struct file *filp, atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]); ++file_priv->ioctl_count; - DRM_DEBUG("pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%lx, auth=%d\n", - task_pid_nr(current), cmd, nr, - (long)old_encode_dev(file_priv->minor->device), - file_priv->authenticated); - if ((nr >= DRM_CORE_IOCTL_COUNT) && ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END))) goto err_i1; @@ -417,6 +412,11 @@ long drm_ioctl(struct file *filp, } else goto err_i1; + DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n", + task_pid_nr(current), + (long)old_encode_dev(file_priv->minor->device), + file_priv->authenticated, ioctl->name); + /* Do not trust userspace, use our own definition */ func = ioctl->func; /* is there a local override? */ @@ -471,6 +471,12 @@ long drm_ioctl(struct file *filp, } err_i1: + if (!ioctl) + DRM_DEBUG("invalid iotcl: pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n", + task_pid_nr(current), + (long)old_encode_dev(file_priv->minor->device), + file_priv->authenticated, cmd, nr); + if (kdata != stack_kdata) kfree(kdata); atomic_dec(&dev->ioctl_count); diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index b6807e881a60..9e62bbedb5ad 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -587,284 +587,348 @@ static const struct drm_display_mode edid_cea_modes[] = { /* 1 - 640x480@60Hz */ { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 60, }, /* 2 - 720x480@60Hz */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 60, }, /* 3 - 720x480@60Hz */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 60, }, /* 4 - 1280x720@60Hz */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 60, }, /* 5 - 1920x1080i@60Hz */ { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | - DRM_MODE_FLAG_INTERLACE) }, + DRM_MODE_FLAG_INTERLACE), + .vrefresh = 60, }, /* 6 - 1440x480i@60Hz */ { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + .vrefresh = 60, }, /* 7 - 1440x480i@60Hz */ { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + .vrefresh = 60, }, /* 8 - 1440x240@60Hz */ { DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, 1602, 1716, 0, 240, 244, 247, 262, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_DBLCLK) }, + DRM_MODE_FLAG_DBLCLK), + .vrefresh = 60, }, /* 9 - 1440x240@60Hz */ { DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, 1602, 1716, 0, 240, 244, 247, 262, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_DBLCLK) }, + DRM_MODE_FLAG_DBLCLK), + .vrefresh = 60, }, /* 10 - 2880x480i@60Hz */ { DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE) }, + DRM_MODE_FLAG_INTERLACE), + .vrefresh = 60, }, /* 11 - 2880x480i@60Hz */ { DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE) }, + DRM_MODE_FLAG_INTERLACE), + .vrefresh = 60, }, /* 12 - 2880x240@60Hz */ { DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, 3204, 3432, 0, 240, 244, 247, 262, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 60, }, /* 13 - 2880x240@60Hz */ { DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, 3204, 3432, 0, 240, 244, 247, 262, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 60, }, /* 14 - 1440x480@60Hz */ { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472, 1596, 1716, 0, 480, 489, 495, 525, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 60, }, /* 15 - 1440x480@60Hz */ { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472, 1596, 1716, 0, 480, 489, 495, 525, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 60, }, /* 16 - 1920x1080@60Hz */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 60, }, /* 17 - 720x576@50Hz */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 50, }, /* 18 - 720x576@50Hz */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 50, }, /* 19 - 1280x720@50Hz */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 50, }, /* 20 - 1920x1080i@50Hz */ { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | - DRM_MODE_FLAG_INTERLACE) }, + DRM_MODE_FLAG_INTERLACE), + .vrefresh = 50, }, /* 21 - 1440x576i@50Hz */ { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + .vrefresh = 50, }, /* 22 - 1440x576i@50Hz */ { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + .vrefresh = 50, }, /* 23 - 1440x288@50Hz */ { DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, 1590, 1728, 0, 288, 290, 293, 312, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_DBLCLK) }, + DRM_MODE_FLAG_DBLCLK), + .vrefresh = 50, }, /* 24 - 1440x288@50Hz */ { DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, 1590, 1728, 0, 288, 290, 293, 312, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_DBLCLK) }, + DRM_MODE_FLAG_DBLCLK), + .vrefresh = 50, }, /* 25 - 2880x576i@50Hz */ { DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE) }, + DRM_MODE_FLAG_INTERLACE), + .vrefresh = 50, }, /* 26 - 2880x576i@50Hz */ { DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE) }, + DRM_MODE_FLAG_INTERLACE), + .vrefresh = 50, }, /* 27 - 2880x288@50Hz */ { DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, 3180, 3456, 0, 288, 290, 293, 312, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 50, }, /* 28 - 2880x288@50Hz */ { DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, 3180, 3456, 0, 288, 290, 293, 312, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 50, }, /* 29 - 1440x576@50Hz */ { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, 1592, 1728, 0, 576, 581, 586, 625, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 50, }, /* 30 - 1440x576@50Hz */ { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, 1592, 1728, 0, 576, 581, 586, 625, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 50, }, /* 31 - 1920x1080@50Hz */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 50, }, /* 32 - 1920x1080@24Hz */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558, 2602, 2750, 0, 1080, 1084, 1089, 1125, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 24, }, /* 33 - 1920x1080@25Hz */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 25, }, /* 34 - 1920x1080@30Hz */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 30, }, /* 35 - 2880x480@60Hz */ { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944, 3192, 3432, 0, 480, 489, 495, 525, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 60, }, /* 36 - 2880x480@60Hz */ { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944, 3192, 3432, 0, 480, 489, 495, 525, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 60, }, /* 37 - 2880x576@50Hz */ { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928, 3184, 3456, 0, 576, 581, 586, 625, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 50, }, /* 38 - 2880x576@50Hz */ { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928, 3184, 3456, 0, 576, 581, 586, 625, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 50, }, /* 39 - 1920x1080i@50Hz */ { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952, 2120, 2304, 0, 1080, 1126, 1136, 1250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE) }, + DRM_MODE_FLAG_INTERLACE), + .vrefresh = 50, }, /* 40 - 1920x1080i@100Hz */ { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | - DRM_MODE_FLAG_INTERLACE) }, + DRM_MODE_FLAG_INTERLACE), + .vrefresh = 100, }, /* 41 - 1280x720@100Hz */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 100, }, /* 42 - 720x576@100Hz */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 100, }, /* 43 - 720x576@100Hz */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 100, }, /* 44 - 1440x576i@100Hz */ { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_DBLCLK) }, + DRM_MODE_FLAG_DBLCLK), + .vrefresh = 100, }, /* 45 - 1440x576i@100Hz */ { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_DBLCLK) }, + DRM_MODE_FLAG_DBLCLK), + .vrefresh = 100, }, /* 46 - 1920x1080i@120Hz */ { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | - DRM_MODE_FLAG_INTERLACE) }, + DRM_MODE_FLAG_INTERLACE), + .vrefresh = 120, }, /* 47 - 1280x720@120Hz */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 120, }, /* 48 - 720x480@120Hz */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 120, }, /* 49 - 720x480@120Hz */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 120, }, /* 50 - 1440x480i@120Hz */ { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + .vrefresh = 120, }, /* 51 - 1440x480i@120Hz */ { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + .vrefresh = 120, }, /* 52 - 720x576@200Hz */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 200, }, /* 53 - 720x576@200Hz */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 200, }, /* 54 - 1440x576i@200Hz */ { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + .vrefresh = 200, }, /* 55 - 1440x576i@200Hz */ { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + .vrefresh = 200, }, /* 56 - 720x480@240Hz */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 240, }, /* 57 - 720x480@240Hz */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), + .vrefresh = 240, }, /* 58 - 1440x480i@240 */ { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + .vrefresh = 240, }, /* 59 - 1440x480i@240 */ { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + .vrefresh = 240, }, /* 60 - 1280x720@24Hz */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 59400, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 24, }, /* 61 - 1280x720@25Hz */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3700, 3740, 3960, 0, 720, 725, 730, 750, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 25, }, /* 62 - 1280x720@30Hz */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 30, }, /* 63 - 1920x1080@120Hz */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 120, }, /* 64 - 1920x1080@100Hz */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 100, }, }; /*** DDC fetch and block validation ***/ @@ -2266,13 +2330,34 @@ EXPORT_SYMBOL(drm_find_cea_extension); */ u8 drm_match_cea_mode(const struct drm_display_mode *to_match) { - struct drm_display_mode *cea_mode; u8 mode; + if (!to_match->clock) + return 0; + for (mode = 0; mode < ARRAY_SIZE(edid_cea_modes); mode++) { - cea_mode = (struct drm_display_mode *)&edid_cea_modes[mode]; + const struct drm_display_mode *cea_mode = &edid_cea_modes[mode]; + unsigned int clock1, clock2; + + clock1 = clock2 = cea_mode->clock; + + /* Check both 60Hz and 59.94Hz */ + if (cea_mode->vrefresh % 6 == 0) { + /* + * edid_cea_modes contains the 59.94Hz + * variant for 240 and 480 line modes, + * and the 60Hz variant otherwise. + */ + if (cea_mode->vdisplay == 240 || + cea_mode->vdisplay == 480) + clock1 = clock1 * 1001 / 1000; + else + clock2 = DIV_ROUND_UP(clock2 * 1000, 1001); + } - if (drm_mode_equal(to_match, cea_mode)) + if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) || + KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) && + drm_mode_equal_no_clocks(to_match, cea_mode)) return mode + 1; } return 0; @@ -2294,6 +2379,7 @@ do_cea_modes (struct drm_connector *connector, u8 *db, u8 len) newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]); if (newmode) { + newmode->vrefresh = 0; drm_mode_probed_add(connector, newmode); modes++; } diff --git a/drivers/gpu/drm/drm_encoder_slave.c b/drivers/gpu/drm/drm_encoder_slave.c index 48c52f7df4e6..0cfb60f54766 100644 --- a/drivers/gpu/drm/drm_encoder_slave.c +++ b/drivers/gpu/drm/drm_encoder_slave.c @@ -54,16 +54,12 @@ int drm_i2c_encoder_init(struct drm_device *dev, struct i2c_adapter *adap, const struct i2c_board_info *info) { - char modalias[sizeof(I2C_MODULE_PREFIX) - + I2C_NAME_SIZE]; struct module *module = NULL; struct i2c_client *client; struct drm_i2c_encoder_driver *encoder_drv; int err = 0; - snprintf(modalias, sizeof(modalias), - "%s%s", I2C_MODULE_PREFIX, info->type); - request_module(modalias); + request_module("%s%s", I2C_MODULE_PREFIX, info->type); client = i2c_new_device(adap, info); if (!client) { diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index af779ae19ebf..cf919e36e8ae 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -205,11 +205,11 @@ static void drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp) { if (obj->import_attach) { - drm_prime_remove_imported_buf_handle(&filp->prime, + drm_prime_remove_buf_handle(&filp->prime, obj->import_attach->dmabuf); } if (obj->export_dma_buf) { - drm_prime_remove_imported_buf_handle(&filp->prime, + drm_prime_remove_buf_handle(&filp->prime, obj->export_dma_buf); } } diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index db1e2d6f90d7..07cf99cc8862 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -755,33 +755,35 @@ void drm_mm_debug_table(struct drm_mm *mm, const char *prefix) EXPORT_SYMBOL(drm_mm_debug_table); #if defined(CONFIG_DEBUG_FS) -int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm) +static unsigned long drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *entry) { - struct drm_mm_node *entry; - unsigned long total_used = 0, total_free = 0, total = 0; unsigned long hole_start, hole_end, hole_size; - hole_start = drm_mm_hole_node_start(&mm->head_node); - hole_end = drm_mm_hole_node_end(&mm->head_node); - hole_size = hole_end - hole_start; - if (hole_size) + if (entry->hole_follows) { + hole_start = drm_mm_hole_node_start(entry); + hole_end = drm_mm_hole_node_end(entry); + hole_size = hole_end - hole_start; seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n", hole_start, hole_end, hole_size); - total_free += hole_size; + return hole_size; + } + + return 0; +} + +int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm) +{ + struct drm_mm_node *entry; + unsigned long total_used = 0, total_free = 0, total = 0; + + total_free += drm_mm_dump_hole(m, &mm->head_node); drm_mm_for_each_node(entry, mm) { seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: used\n", entry->start, entry->start + entry->size, entry->size); total_used += entry->size; - if (entry->hole_follows) { - hole_start = drm_mm_hole_node_start(entry); - hole_end = drm_mm_hole_node_end(entry); - hole_size = hole_end - hole_start; - seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n", - hole_start, hole_end, hole_size); - total_free += hole_size; - } + total_free += drm_mm_dump_hole(m, entry); } total = total_free + total_used; diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 04fa6f1808d1..7a83836879bc 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -848,6 +848,26 @@ bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_displ } else if (mode1->clock != mode2->clock) return false; + return drm_mode_equal_no_clocks(mode1, mode2); +} +EXPORT_SYMBOL(drm_mode_equal); + +/** + * drm_mode_equal_no_clocks - test modes for equality + * @mode1: first mode + * @mode2: second mode + * + * LOCKING: + * None. + * + * Check to see if @mode1 and @mode2 are equivalent, but + * don't check the pixel clocks. + * + * RETURNS: + * True if the modes are equal, false otherwise. + */ +bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2) +{ if (mode1->hdisplay == mode2->hdisplay && mode1->hsync_start == mode2->hsync_start && mode1->hsync_end == mode2->hsync_end && @@ -863,7 +883,7 @@ bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_displ return false; } -EXPORT_SYMBOL(drm_mode_equal); +EXPORT_SYMBOL(drm_mode_equal_no_clocks); /** * drm_mode_validate_size - make sure modes adhere to size constraints @@ -1123,6 +1143,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, was_digit = false; } else goto done; + break; case '0' ... '9': was_digit = true; break; diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index bd719e936e13..14194b6ef644 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -152,7 +152,7 @@ static const char *drm_pci_get_name(struct drm_device *dev) return pdriver->name; } -int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master) +static int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master) { int len, ret; struct pci_driver *pdriver = dev->driver->kdriver.pci; @@ -194,9 +194,9 @@ err: return ret; } -int drm_pci_set_unique(struct drm_device *dev, - struct drm_master *master, - struct drm_unique *u) +static int drm_pci_set_unique(struct drm_device *dev, + struct drm_master *master, + struct drm_unique *u) { int domain, bus, slot, func, ret; const char *bus_name; @@ -266,7 +266,7 @@ static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p) return 0; } -int drm_pci_agp_init(struct drm_device *dev) +static int drm_pci_agp_init(struct drm_device *dev) { if (drm_core_has_AGP(dev)) { if (drm_pci_device_is_agp(dev)) diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 25d02187067e..dcde35231e25 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -62,6 +62,7 @@ struct drm_prime_member { struct dma_buf *dma_buf; uint32_t handle; }; +static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle); static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach, enum dma_data_direction dir) @@ -200,7 +201,8 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev, { struct drm_gem_object *obj; void *buf; - int ret; + int ret = 0; + struct dma_buf *dmabuf; obj = drm_gem_object_lookup(dev, file_priv, handle); if (!obj) @@ -209,43 +211,44 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev, mutex_lock(&file_priv->prime.lock); /* re-export the original imported object */ if (obj->import_attach) { - get_dma_buf(obj->import_attach->dmabuf); - *prime_fd = dma_buf_fd(obj->import_attach->dmabuf, flags); - drm_gem_object_unreference_unlocked(obj); - mutex_unlock(&file_priv->prime.lock); - return 0; + dmabuf = obj->import_attach->dmabuf; + goto out_have_obj; } if (obj->export_dma_buf) { - get_dma_buf(obj->export_dma_buf); - *prime_fd = dma_buf_fd(obj->export_dma_buf, flags); - drm_gem_object_unreference_unlocked(obj); - } else { - buf = dev->driver->gem_prime_export(dev, obj, flags); - if (IS_ERR(buf)) { - /* normally the created dma-buf takes ownership of the ref, - * but if that fails then drop the ref - */ - drm_gem_object_unreference_unlocked(obj); - mutex_unlock(&file_priv->prime.lock); - return PTR_ERR(buf); - } - obj->export_dma_buf = buf; - *prime_fd = dma_buf_fd(buf, flags); + dmabuf = obj->export_dma_buf; + goto out_have_obj; + } + + buf = dev->driver->gem_prime_export(dev, obj, flags); + if (IS_ERR(buf)) { + /* normally the created dma-buf takes ownership of the ref, + * but if that fails then drop the ref + */ + ret = PTR_ERR(buf); + goto out; } + obj->export_dma_buf = buf; + /* if we've exported this buffer the cheat and add it to the import list * so we get the correct handle back */ - ret = drm_prime_add_imported_buf_handle(&file_priv->prime, - obj->export_dma_buf, handle); - if (ret) { - drm_gem_object_unreference_unlocked(obj); - mutex_unlock(&file_priv->prime.lock); - return ret; - } + ret = drm_prime_add_buf_handle(&file_priv->prime, + obj->export_dma_buf, handle); + if (ret) + goto out; + *prime_fd = dma_buf_fd(buf, flags); mutex_unlock(&file_priv->prime.lock); return 0; + +out_have_obj: + get_dma_buf(dmabuf); + *prime_fd = dma_buf_fd(dmabuf, flags); +out: + drm_gem_object_unreference_unlocked(obj); + mutex_unlock(&file_priv->prime.lock); + return ret; } EXPORT_SYMBOL(drm_gem_prime_handle_to_fd); @@ -268,7 +271,6 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, * refcount on gem itself instead of f_count of dmabuf. */ drm_gem_object_reference(obj); - dma_buf_put(dma_buf); return obj; } } @@ -277,6 +279,8 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, if (IS_ERR(attach)) return ERR_PTR(PTR_ERR(attach)); + get_dma_buf(dma_buf); + sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); if (IS_ERR_OR_NULL(sgt)) { ret = PTR_ERR(sgt); @@ -297,6 +301,8 @@ fail_unmap: dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); fail_detach: dma_buf_detach(dma_buf, attach); + dma_buf_put(dma_buf); + return ERR_PTR(ret); } EXPORT_SYMBOL(drm_gem_prime_import); @@ -314,7 +320,7 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev, mutex_lock(&file_priv->prime.lock); - ret = drm_prime_lookup_imported_buf_handle(&file_priv->prime, + ret = drm_prime_lookup_buf_handle(&file_priv->prime, dma_buf, handle); if (!ret) { ret = 0; @@ -333,12 +339,15 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev, if (ret) goto out_put; - ret = drm_prime_add_imported_buf_handle(&file_priv->prime, + ret = drm_prime_add_buf_handle(&file_priv->prime, dma_buf, *handle); if (ret) goto fail; mutex_unlock(&file_priv->prime.lock); + + dma_buf_put(dma_buf); + return 0; fail: @@ -479,15 +488,12 @@ EXPORT_SYMBOL(drm_prime_init_file_private); void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv) { - struct drm_prime_member *member, *safe; - list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) { - list_del(&member->entry); - kfree(member); - } + /* by now drm_gem_release should've made sure the list is empty */ + WARN_ON(!list_empty(&prime_fpriv->head)); } EXPORT_SYMBOL(drm_prime_destroy_file_private); -int drm_prime_add_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle) +static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle) { struct drm_prime_member *member; @@ -495,14 +501,14 @@ int drm_prime_add_imported_buf_handle(struct drm_prime_file_private *prime_fpriv if (!member) return -ENOMEM; + get_dma_buf(dma_buf); member->dma_buf = dma_buf; member->handle = handle; list_add(&member->entry, &prime_fpriv->head); return 0; } -EXPORT_SYMBOL(drm_prime_add_imported_buf_handle); -int drm_prime_lookup_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle) +int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle) { struct drm_prime_member *member; @@ -514,19 +520,20 @@ int drm_prime_lookup_imported_buf_handle(struct drm_prime_file_private *prime_fp } return -ENOENT; } -EXPORT_SYMBOL(drm_prime_lookup_imported_buf_handle); +EXPORT_SYMBOL(drm_prime_lookup_buf_handle); -void drm_prime_remove_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf) +void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf) { struct drm_prime_member *member, *safe; mutex_lock(&prime_fpriv->lock); list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) { if (member->dma_buf == dma_buf) { + dma_buf_put(dma_buf); list_del(&member->entry); kfree(member); } } mutex_unlock(&prime_fpriv->lock); } -EXPORT_SYMBOL(drm_prime_remove_imported_buf_handle); +EXPORT_SYMBOL(drm_prime_remove_buf_handle); diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 406f32af8266..772c62a6e2ac 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -25,8 +25,8 @@ config DRM_EXYNOS_DMABUF config DRM_EXYNOS_FIMD bool "Exynos DRM FIMD" depends on OF && DRM_EXYNOS && !FB_S3C && !ARCH_MULTIPLATFORM - select OF_VIDEOMODE select FB_MODE_HELPERS + select VIDEOMODE_HELPERS help Choose this option if you want to use Exynos FIMD for DRM. @@ -56,7 +56,7 @@ config DRM_EXYNOS_IPP config DRM_EXYNOS_FIMC bool "Exynos DRM FIMC" - depends on DRM_EXYNOS_IPP + depends on DRM_EXYNOS_IPP && MFD_SYSCON && OF help Choose this option if you want to use Exynos FIMC for DRM. diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c index ba0a3aa78547..ff7f2a886a34 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c @@ -235,7 +235,6 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev, * refcount on gem itself instead of f_count of dmabuf. */ drm_gem_object_reference(obj); - dma_buf_put(dma_buf); return obj; } } @@ -244,6 +243,7 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev, if (IS_ERR(attach)) return ERR_PTR(-EINVAL); + get_dma_buf(dma_buf); sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); if (IS_ERR_OR_NULL(sgt)) { @@ -298,6 +298,8 @@ err_unmap_attach: dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); err_buf_detach: dma_buf_detach(dma_buf, attach); + dma_buf_put(dma_buf); + return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 3da5c2d214d8..ba6d995e4375 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -380,6 +380,10 @@ static int __init exynos_drm_init(void) ret = platform_driver_register(&ipp_driver); if (ret < 0) goto out_ipp; + + ret = exynos_platform_device_ipp_register(); + if (ret < 0) + goto out_ipp_dev; #endif ret = platform_driver_register(&exynos_drm_platform_driver); @@ -388,7 +392,7 @@ static int __init exynos_drm_init(void) exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1, NULL, 0); - if (IS_ERR_OR_NULL(exynos_drm_pdev)) { + if (IS_ERR(exynos_drm_pdev)) { ret = PTR_ERR(exynos_drm_pdev); goto out; } @@ -400,6 +404,8 @@ out: out_drm: #ifdef CONFIG_DRM_EXYNOS_IPP + exynos_platform_device_ipp_unregister(); +out_ipp_dev: platform_driver_unregister(&ipp_driver); out_ipp: #endif @@ -456,6 +462,7 @@ static void __exit exynos_drm_exit(void) platform_driver_unregister(&exynos_drm_platform_driver); #ifdef CONFIG_DRM_EXYNOS_IPP + exynos_platform_device_ipp_unregister(); platform_driver_unregister(&ipp_driver); #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 4606fac7241a..680a7c1b9dea 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -322,13 +322,23 @@ void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file); * this function registers exynos drm hdmi platform device. It ensures only one * instance of the device is created. */ -extern int exynos_platform_device_hdmi_register(void); +int exynos_platform_device_hdmi_register(void); /* * this function unregisters exynos drm hdmi platform device if it exists. */ void exynos_platform_device_hdmi_unregister(void); +/* + * this function registers exynos drm ipp platform device. + */ +int exynos_platform_device_ipp_register(void); + +/* + * this function unregisters exynos drm ipp platform device if it exists. + */ +void exynos_platform_device_ipp_unregister(void); + extern struct platform_driver fimd_driver; extern struct platform_driver hdmi_driver; extern struct platform_driver mixer_driver; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c index 411f69b76e84..773f583fa964 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c @@ -12,11 +12,12 @@ * */ #include <linux/kernel.h> +#include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/regmap.h> #include <linux/clk.h> #include <linux/pm_runtime.h> -#include <plat/map-base.h> #include <drm/drmP.h> #include <drm/exynos_drm.h> @@ -76,6 +77,27 @@ enum fimc_wb { FIMC_WB_B, }; +enum { + FIMC_CLK_LCLK, + FIMC_CLK_GATE, + FIMC_CLK_WB_A, + FIMC_CLK_WB_B, + FIMC_CLK_MUX, + FIMC_CLK_PARENT, + FIMC_CLKS_MAX +}; + +static const char * const fimc_clock_names[] = { + [FIMC_CLK_LCLK] = "sclk_fimc", + [FIMC_CLK_GATE] = "fimc", + [FIMC_CLK_WB_A] = "pxl_async0", + [FIMC_CLK_WB_B] = "pxl_async1", + [FIMC_CLK_MUX] = "mux", + [FIMC_CLK_PARENT] = "parent", +}; + +#define FIMC_DEFAULT_LCLK_FREQUENCY 133000000UL + /* * A structure of scaler. * @@ -119,28 +141,16 @@ struct fimc_capability { }; /* - * A structure of fimc driver data. - * - * @parent_clk: name of parent clock. - */ -struct fimc_driverdata { - char *parent_clk; -}; - -/* * A structure of fimc context. * * @ippdrv: prepare initialization using ippdrv. * @regs_res: register resources. * @regs: memory mapped io registers. * @lock: locking of operations. - * @sclk_fimc_clk: fimc source clock. - * @fimc_clk: fimc clock. - * @wb_clk: writeback a clock. - * @wb_b_clk: writeback b clock. + * @clocks: fimc clocks. + * @clk_frequency: LCLK clock frequency. + * @sysreg: handle to SYSREG block regmap. * @sc: scaler infomations. - * @odr: ordering of YUV. - * @ver: fimc version. * @pol: porarity of writeback. * @id: fimc id. * @irq: irq number. @@ -151,12 +161,10 @@ struct fimc_context { struct resource *regs_res; void __iomem *regs; struct mutex lock; - struct clk *sclk_fimc_clk; - struct clk *fimc_clk; - struct clk *wb_clk; - struct clk *wb_b_clk; + struct clk *clocks[FIMC_CLKS_MAX]; + u32 clk_frequency; + struct regmap *sysreg; struct fimc_scaler sc; - struct fimc_driverdata *ddata; struct exynos_drm_ipp_pol pol; int id; int irq; @@ -200,17 +208,13 @@ static void fimc_sw_reset(struct fimc_context *ctx) fimc_write(0x0, EXYNOS_CIFCNTSEQ); } -static void fimc_set_camblk_fimd0_wb(struct fimc_context *ctx) +static int fimc_set_camblk_fimd0_wb(struct fimc_context *ctx) { - u32 camblk_cfg; - DRM_DEBUG_KMS("%s\n", __func__); - camblk_cfg = readl(SYSREG_CAMERA_BLK); - camblk_cfg &= ~(SYSREG_FIMD0WB_DEST_MASK); - camblk_cfg |= ctx->id << (SYSREG_FIMD0WB_DEST_SHIFT); - - writel(camblk_cfg, SYSREG_CAMERA_BLK); + return regmap_update_bits(ctx->sysreg, SYSREG_CAMERA_BLK, + SYSREG_FIMD0WB_DEST_MASK, + ctx->id << SYSREG_FIMD0WB_DEST_SHIFT); } static void fimc_set_type_ctrl(struct fimc_context *ctx, enum fimc_wb wb) @@ -1301,14 +1305,12 @@ static int fimc_clk_ctrl(struct fimc_context *ctx, bool enable) DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable); if (enable) { - clk_enable(ctx->sclk_fimc_clk); - clk_enable(ctx->fimc_clk); - clk_enable(ctx->wb_clk); + clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]); + clk_prepare_enable(ctx->clocks[FIMC_CLK_WB_A]); ctx->suspended = false; } else { - clk_disable(ctx->sclk_fimc_clk); - clk_disable(ctx->fimc_clk); - clk_disable(ctx->wb_clk); + clk_disable_unprepare(ctx->clocks[FIMC_CLK_GATE]); + clk_disable_unprepare(ctx->clocks[FIMC_CLK_WB_A]); ctx->suspended = true; } @@ -1613,7 +1615,11 @@ static int fimc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd) fimc_handle_lastend(ctx, true); /* setup FIMD */ - fimc_set_camblk_fimd0_wb(ctx); + ret = fimc_set_camblk_fimd0_wb(ctx); + if (ret < 0) { + dev_err(dev, "camblk setup failed.\n"); + return ret; + } set_wb.enable = 1; set_wb.refresh = property->refresh_rate; @@ -1713,76 +1719,118 @@ static void fimc_ippdrv_stop(struct device *dev, enum drm_exynos_ipp_cmd cmd) fimc_write(cfg, EXYNOS_CIGCTRL); } +static void fimc_put_clocks(struct fimc_context *ctx) +{ + int i; + + for (i = 0; i < FIMC_CLKS_MAX; i++) { + if (IS_ERR(ctx->clocks[i])) + continue; + clk_put(ctx->clocks[i]); + ctx->clocks[i] = ERR_PTR(-EINVAL); + } +} + +static int fimc_setup_clocks(struct fimc_context *ctx) +{ + struct device *fimc_dev = ctx->ippdrv.dev; + struct device *dev; + int ret, i; + + for (i = 0; i < FIMC_CLKS_MAX; i++) + ctx->clocks[i] = ERR_PTR(-EINVAL); + + for (i = 0; i < FIMC_CLKS_MAX; i++) { + if (i == FIMC_CLK_WB_A || i == FIMC_CLK_WB_B) + dev = fimc_dev->parent; + else + dev = fimc_dev; + + ctx->clocks[i] = clk_get(dev, fimc_clock_names[i]); + if (IS_ERR(ctx->clocks[i])) { + if (i >= FIMC_CLK_MUX) + break; + ret = PTR_ERR(ctx->clocks[i]); + dev_err(fimc_dev, "failed to get clock: %s\n", + fimc_clock_names[i]); + goto e_clk_free; + } + } + + /* Optional FIMC LCLK parent clock setting */ + if (!IS_ERR(ctx->clocks[FIMC_CLK_PARENT])) { + ret = clk_set_parent(ctx->clocks[FIMC_CLK_MUX], + ctx->clocks[FIMC_CLK_PARENT]); + if (ret < 0) { + dev_err(fimc_dev, "failed to set parent.\n"); + goto e_clk_free; + } + } + + ret = clk_set_rate(ctx->clocks[FIMC_CLK_LCLK], ctx->clk_frequency); + if (ret < 0) + goto e_clk_free; + + ret = clk_prepare_enable(ctx->clocks[FIMC_CLK_LCLK]); + if (!ret) + return ret; +e_clk_free: + fimc_put_clocks(ctx); + return ret; +} + +static int fimc_parse_dt(struct fimc_context *ctx) +{ + struct device_node *node = ctx->ippdrv.dev->of_node; + + /* Handle only devices that support the LCD Writeback data path */ + if (!of_property_read_bool(node, "samsung,lcd-wb")) + return -ENODEV; + + if (of_property_read_u32(node, "clock-frequency", + &ctx->clk_frequency)) + ctx->clk_frequency = FIMC_DEFAULT_LCLK_FREQUENCY; + + ctx->id = of_alias_get_id(node, "fimc"); + + if (ctx->id < 0) { + dev_err(ctx->ippdrv.dev, "failed to get node alias id.\n"); + return -EINVAL; + } + + return 0; +} + static int fimc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct fimc_context *ctx; - struct clk *parent_clk; struct resource *res; struct exynos_drm_ippdrv *ippdrv; - struct exynos_drm_fimc_pdata *pdata; - struct fimc_driverdata *ddata; int ret; - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(dev, "no platform data specified.\n"); - return -EINVAL; + if (!dev->of_node) { + dev_err(dev, "device tree node not found.\n"); + return -ENODEV; } ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; - ddata = (struct fimc_driverdata *) - platform_get_device_id(pdev)->driver_data; - - /* clock control */ - ctx->sclk_fimc_clk = devm_clk_get(dev, "sclk_fimc"); - if (IS_ERR(ctx->sclk_fimc_clk)) { - dev_err(dev, "failed to get src fimc clock.\n"); - return PTR_ERR(ctx->sclk_fimc_clk); - } - clk_enable(ctx->sclk_fimc_clk); - - ctx->fimc_clk = devm_clk_get(dev, "fimc"); - if (IS_ERR(ctx->fimc_clk)) { - dev_err(dev, "failed to get fimc clock.\n"); - clk_disable(ctx->sclk_fimc_clk); - return PTR_ERR(ctx->fimc_clk); - } - - ctx->wb_clk = devm_clk_get(dev, "pxl_async0"); - if (IS_ERR(ctx->wb_clk)) { - dev_err(dev, "failed to get writeback a clock.\n"); - clk_disable(ctx->sclk_fimc_clk); - return PTR_ERR(ctx->wb_clk); - } - - ctx->wb_b_clk = devm_clk_get(dev, "pxl_async1"); - if (IS_ERR(ctx->wb_b_clk)) { - dev_err(dev, "failed to get writeback b clock.\n"); - clk_disable(ctx->sclk_fimc_clk); - return PTR_ERR(ctx->wb_b_clk); - } + ctx->ippdrv.dev = dev; - parent_clk = devm_clk_get(dev, ddata->parent_clk); - - if (IS_ERR(parent_clk)) { - dev_err(dev, "failed to get parent clock.\n"); - clk_disable(ctx->sclk_fimc_clk); - return PTR_ERR(parent_clk); - } + ret = fimc_parse_dt(ctx); + if (ret < 0) + return ret; - if (clk_set_parent(ctx->sclk_fimc_clk, parent_clk)) { - dev_err(dev, "failed to set parent.\n"); - clk_disable(ctx->sclk_fimc_clk); - return -EINVAL; + ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node, + "samsung,sysreg"); + if (IS_ERR(ctx->sysreg)) { + dev_err(dev, "syscon regmap lookup failed.\n"); + return PTR_ERR(ctx->sysreg); } - devm_clk_put(dev, parent_clk); - clk_set_rate(ctx->sclk_fimc_clk, pdata->clk_rate); - /* resource memory */ ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ctx->regs = devm_ioremap_resource(dev, ctx->regs_res); @@ -1804,13 +1852,11 @@ static int fimc_probe(struct platform_device *pdev) return ret; } - /* context initailization */ - ctx->id = pdev->id; - ctx->pol = pdata->pol; - ctx->ddata = ddata; + ret = fimc_setup_clocks(ctx); + if (ret < 0) + goto err_free_irq; ippdrv = &ctx->ippdrv; - ippdrv->dev = dev; ippdrv->ops[EXYNOS_DRM_OPS_SRC] = &fimc_src_ops; ippdrv->ops[EXYNOS_DRM_OPS_DST] = &fimc_dst_ops; ippdrv->check_property = fimc_ippdrv_check_property; @@ -1820,7 +1866,7 @@ static int fimc_probe(struct platform_device *pdev) ret = fimc_init_prop_list(ippdrv); if (ret < 0) { dev_err(dev, "failed to init property list.\n"); - goto err_get_irq; + goto err_put_clk; } DRM_DEBUG_KMS("%s:id[%d]ippdrv[0x%x]\n", __func__, ctx->id, @@ -1835,17 +1881,18 @@ static int fimc_probe(struct platform_device *pdev) ret = exynos_drm_ippdrv_register(ippdrv); if (ret < 0) { dev_err(dev, "failed to register drm fimc device.\n"); - goto err_ippdrv_register; + goto err_pm_dis; } dev_info(&pdev->dev, "drm fimc registered successfully.\n"); return 0; -err_ippdrv_register: - devm_kfree(dev, ippdrv->prop_list); +err_pm_dis: pm_runtime_disable(dev); -err_get_irq: +err_put_clk: + fimc_put_clocks(ctx); +err_free_irq: free_irq(ctx->irq, ctx); return ret; @@ -1857,10 +1904,10 @@ static int fimc_remove(struct platform_device *pdev) struct fimc_context *ctx = get_fimc_context(dev); struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; - devm_kfree(dev, ippdrv->prop_list); exynos_drm_ippdrv_unregister(ippdrv); mutex_destroy(&ctx->lock); + fimc_put_clocks(ctx); pm_runtime_set_suspended(dev); pm_runtime_disable(dev); @@ -1915,36 +1962,22 @@ static int fimc_runtime_resume(struct device *dev) } #endif -static struct fimc_driverdata exynos4210_fimc_data = { - .parent_clk = "mout_mpll", -}; - -static struct fimc_driverdata exynos4410_fimc_data = { - .parent_clk = "mout_mpll_user", -}; - -static struct platform_device_id fimc_driver_ids[] = { - { - .name = "exynos4210-fimc", - .driver_data = (unsigned long)&exynos4210_fimc_data, - }, { - .name = "exynos4412-fimc", - .driver_data = (unsigned long)&exynos4410_fimc_data, - }, - {}, -}; -MODULE_DEVICE_TABLE(platform, fimc_driver_ids); - static const struct dev_pm_ops fimc_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume) SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL) }; +static const struct of_device_id fimc_of_match[] = { + { .compatible = "samsung,exynos4210-fimc" }, + { .compatible = "samsung,exynos4212-fimc" }, + { }, +}; + struct platform_driver fimc_driver = { .probe = fimc_probe, .remove = fimc_remove, - .id_table = fimc_driver_ids, .driver = { + .of_match_table = fimc_of_match, .name = "exynos-drm-fimc", .owner = THIS_MODULE, .pm = &fimc_pm_ops, diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 15e58f5abe02..746b282b343a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -801,18 +801,18 @@ static int fimd_clock(struct fimd_context *ctx, bool enable) if (enable) { int ret; - ret = clk_enable(ctx->bus_clk); + ret = clk_prepare_enable(ctx->bus_clk); if (ret < 0) return ret; - ret = clk_enable(ctx->lcd_clk); + ret = clk_prepare_enable(ctx->lcd_clk); if (ret < 0) { - clk_disable(ctx->bus_clk); + clk_disable_unprepare(ctx->bus_clk); return ret; } } else { - clk_disable(ctx->lcd_clk); - clk_disable(ctx->bus_clk); + clk_disable_unprepare(ctx->lcd_clk); + clk_disable_unprepare(ctx->bus_clk); } return 0; @@ -949,16 +949,6 @@ static int fimd_probe(struct platform_device *pdev) return ret; } - ret = clk_prepare(ctx->bus_clk); - if (ret < 0) - return ret; - - ret = clk_prepare(ctx->lcd_clk); - if (ret < 0) { - clk_unprepare(ctx->bus_clk); - return ret; - } - ctx->vidcon0 = pdata->vidcon0; ctx->vidcon1 = pdata->vidcon1; ctx->default_win = pdata->default_win; @@ -1006,9 +996,6 @@ static int fimd_remove(struct platform_device *pdev) if (ctx->suspended) goto out; - clk_unprepare(ctx->lcd_clk); - clk_unprepare(ctx->bus_clk); - pm_runtime_set_suspended(dev); pm_runtime_put_sync(dev); diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 0e6fe000578c..cf4543ffa079 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -682,7 +682,8 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv, args->pitch = args->width * ((args->bpp + 7) / 8); args->size = args->pitch * args->height; - exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size); + exynos_gem_obj = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG | + EXYNOS_BO_WC, args->size); if (IS_ERR(exynos_gem_obj)) return PTR_ERR(exynos_gem_obj); diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c index 5285509e4b34..ba2f0f1aa05f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c @@ -51,21 +51,27 @@ struct drm_hdmi_context { int exynos_platform_device_hdmi_register(void) { + struct platform_device *pdev; + if (exynos_drm_hdmi_pdev) return -EEXIST; - exynos_drm_hdmi_pdev = platform_device_register_simple( + pdev = platform_device_register_simple( "exynos-drm-hdmi", -1, NULL, 0); - if (IS_ERR_OR_NULL(exynos_drm_hdmi_pdev)) - return PTR_ERR(exynos_drm_hdmi_pdev); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + exynos_drm_hdmi_pdev = pdev; return 0; } void exynos_platform_device_hdmi_unregister(void) { - if (exynos_drm_hdmi_pdev) + if (exynos_drm_hdmi_pdev) { platform_device_unregister(exynos_drm_hdmi_pdev); + exynos_drm_hdmi_pdev = NULL; + } } void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx) diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index 1adce07ecb5b..29d2ad314490 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -47,6 +47,9 @@ #define get_ipp_context(dev) platform_get_drvdata(to_platform_device(dev)) #define ipp_is_m2m_cmd(c) (c == IPP_CMD_M2M) +/* platform device pointer for ipp device. */ +static struct platform_device *exynos_drm_ipp_pdev; + /* * A structure of event. * @@ -102,6 +105,30 @@ static LIST_HEAD(exynos_drm_ippdrv_list); static DEFINE_MUTEX(exynos_drm_ippdrv_lock); static BLOCKING_NOTIFIER_HEAD(exynos_drm_ippnb_list); +int exynos_platform_device_ipp_register(void) +{ + struct platform_device *pdev; + + if (exynos_drm_ipp_pdev) + return -EEXIST; + + pdev = platform_device_register_simple("exynos-drm-ipp", -1, NULL, 0); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + exynos_drm_ipp_pdev = pdev; + + return 0; +} + +void exynos_platform_device_ipp_unregister(void) +{ + if (exynos_drm_ipp_pdev) { + platform_device_unregister(exynos_drm_ipp_pdev); + exynos_drm_ipp_pdev = NULL; + } +} + int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv) { DRM_DEBUG_KMS("%s\n", __func__); diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 93b70e9f6e99..bbfc3840080c 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1373,11 +1373,10 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata) return; } - if (hdata->type == HDMI_TYPE13) { + if (hdata->type == HDMI_TYPE13) hdmiphy_data = hdmiphy_v13_configs[i].conf; - } else { + else hdmiphy_data = hdmiphy_v14_configs[i].conf; - } memcpy(buffer, hdmiphy_data, 32); ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32); @@ -1653,11 +1652,10 @@ static void hdmi_mode_set(void *ctx, void *mode) m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ? "INTERLACED" : "PROGERESSIVE"); - if (hdata->type == HDMI_TYPE13) { + if (hdata->type == HDMI_TYPE13) hdmi_v13_mode_set(hdata, mode); - } else { + else hdmi_v14_mode_set(hdata, mode); - } } static void hdmi_get_max_resol(void *ctx, unsigned int *width, diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index f08e2512c931..ec3e376b7e01 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -643,12 +643,14 @@ static void mixer_win_reset(struct mixer_context *ctx) /* setting graphical layers */ val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */ val |= MXR_GRP_CFG_WIN_BLEND_EN; - val |= MXR_GRP_CFG_BLEND_PRE_MUL; - val |= MXR_GRP_CFG_PIXEL_BLEND_EN; val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */ - /* the same configuration for both layers */ + /* Don't blend layer 0 onto the mixer background */ mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val); + + /* Blend layer 1 into layer 0 */ + val |= MXR_GRP_CFG_BLEND_PRE_MUL; + val |= MXR_GRP_CFG_PIXEL_BLEND_EN; mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val); /* setting video layers */ diff --git a/drivers/gpu/drm/exynos/regs-fimc.h b/drivers/gpu/drm/exynos/regs-fimc.h index b4f9ca1fd851..30496134a3d0 100644 --- a/drivers/gpu/drm/exynos/regs-fimc.h +++ b/drivers/gpu/drm/exynos/regs-fimc.h @@ -661,9 +661,8 @@ #define EXYNOS_CLKSRC_SCLK (1 << 1) /* SYSREG for FIMC writeback */ -#define SYSREG_CAMERA_BLK (S3C_VA_SYS + 0x0218) -#define SYSREG_ISP_BLK (S3C_VA_SYS + 0x020c) -#define SYSREG_FIMD0WB_DEST_MASK (0x3 << 23) -#define SYSREG_FIMD0WB_DEST_SHIFT 23 +#define SYSREG_CAMERA_BLK (0x0218) +#define SYSREG_FIMD0WB_DEST_MASK (0x3 << 23) +#define SYSREG_FIMD0WB_DEST_SHIFT 23 #endif /* EXYNOS_REGS_FIMC_H */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 6be940effefd..6165535d15f0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1045,6 +1045,8 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, if (timeout) { struct timespec sleep_time = timespec_sub(now, before); *timeout = timespec_sub(*timeout, sleep_time); + if (!timespec_valid(timeout)) /* i.e. negative time remains */ + set_normalized_timespec(timeout, 0, 0); } switch (end) { @@ -1053,8 +1055,6 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, case -ERESTARTSYS: /* Signal */ return (int)end; case 0: /* Timeout */ - if (timeout) - set_normalized_timespec(timeout, 0, 0); return -ETIME; default: /* Completed */ WARN_ON(end < 0); /* We're not aware of other errors */ @@ -2377,10 +2377,8 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) mutex_unlock(&dev->struct_mutex); ret = __wait_seqno(ring, seqno, reset_counter, true, timeout); - if (timeout) { - WARN_ON(!timespec_valid(timeout)); + if (timeout) args->timeout_ns = timespec_to_ns(timeout); - } return ret; out: diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c index c6dfc1466e3a..dc53a527126b 100644 --- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c @@ -129,7 +129,7 @@ static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf) goto error; i = 0; - for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0); + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) pages[i++] = sg_page_iter_page(&sg_iter); obj->dma_buf_vmapping = vmap(pages, i, 0, PAGE_KERNEL); @@ -272,7 +272,6 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev, * refcount on gem itself instead of f_count of dmabuf. */ drm_gem_object_reference(&obj->base); - dma_buf_put(dma_buf); return &obj->base; } } @@ -282,6 +281,8 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev, if (IS_ERR(attach)) return ERR_CAST(attach); + get_dma_buf(dma_buf); + obj = i915_gem_object_alloc(dev); if (obj == NULL) { ret = -ENOMEM; @@ -301,5 +302,7 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev, fail_detach: dma_buf_detach(dma_buf, attach); + dma_buf_put(dma_buf); + return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 50df194914a6..bdb0d7717bc7 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -233,8 +233,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) /* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024 * entries. For aliasing ppgtt support we just steal them at the end for * now. */ - first_pd_entry_in_global_pt = - gtt_total_entries(dev_priv->gtt) - I915_PPGTT_PD_ENTRIES; + first_pd_entry_in_global_pt = gtt_total_entries(dev_priv->gtt); ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES; ppgtt->enable = gen6_ppgtt_enable; @@ -710,15 +709,6 @@ static inline size_t gen6_get_stolen_size(u16 snb_gmch_ctl) return snb_gmch_ctl << 25; /* 32 MB units */ } -static inline size_t gen7_get_stolen_size(u16 snb_gmch_ctl) -{ - static const int stolen_decoder[] = { - 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352}; - snb_gmch_ctl >>= IVB_GMCH_GMS_SHIFT; - snb_gmch_ctl &= IVB_GMCH_GMS_MASK; - return stolen_decoder[snb_gmch_ctl] << 20; -} - static int gen6_gmch_probe(struct drm_device *dev, size_t *gtt_total, size_t *stolen, @@ -748,11 +738,7 @@ static int gen6_gmch_probe(struct drm_device *dev, pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl); gtt_size = gen6_get_total_gtt_size(snb_gmch_ctl); - if (IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) - *stolen = gen7_get_stolen_size(snb_gmch_ctl); - else - *stolen = gen6_get_stolen_size(snb_gmch_ctl); - + *stolen = gen6_get_stolen_size(snb_gmch_ctl); *gtt_total = (gtt_size / sizeof(gen6_gtt_pte_t)) << PAGE_SHIFT; /* For Modern GENs the PTEs and register space are split in the BAR */ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 31de7e4b1f3e..2d6b62e42daf 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -46,8 +46,6 @@ #define SNB_GMCH_GGMS_MASK 0x3 #define SNB_GMCH_GMS_SHIFT 3 /* Graphics Mode Select */ #define SNB_GMCH_GMS_MASK 0x1f -#define IVB_GMCH_GMS_SHIFT 4 -#define IVB_GMCH_GMS_MASK 0xf /* PCI config space */ @@ -2652,14 +2650,14 @@ #define _PIPEB_GMCH_DATA_M 0x71050 /* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */ -#define PIPE_GMCH_DATA_M_TU_SIZE_MASK (0x3f << 25) -#define PIPE_GMCH_DATA_M_TU_SIZE_SHIFT 25 +#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */ +#define TU_SIZE_MASK (0x3f << 25) -#define PIPE_GMCH_DATA_M_MASK (0xffffff) +#define DATA_LINK_M_N_MASK (0xffffff) +#define DATA_LINK_N_MAX (0x800000) #define _PIPEA_GMCH_DATA_N 0x70054 #define _PIPEB_GMCH_DATA_N 0x71054 -#define PIPE_GMCH_DATA_N_MASK (0xffffff) /* * Computing Link M and N values for the Display Port link @@ -2674,11 +2672,9 @@ #define _PIPEA_DP_LINK_M 0x70060 #define _PIPEB_DP_LINK_M 0x71060 -#define PIPEA_DP_LINK_M_MASK (0xffffff) #define _PIPEA_DP_LINK_N 0x70064 #define _PIPEB_DP_LINK_N 0x71064 -#define PIPEA_DP_LINK_N_MASK (0xffffff) #define PIPE_GMCH_DATA_M(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_M, _PIPEB_GMCH_DATA_M) #define PIPE_GMCH_DATA_N(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_N, _PIPEB_GMCH_DATA_N) @@ -3404,8 +3400,6 @@ #define _PIPEA_DATA_M1 (dev_priv->info->display_mmio_offset + 0x60030) -#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */ -#define TU_SIZE_MASK 0x7e000000 #define PIPE_DATA_M1_OFFSET 0 #define _PIPEA_DATA_N1 (dev_priv->info->display_mmio_offset + 0x60034) #define PIPE_DATA_N1_OFFSET 0 diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 26a0a570f92e..fb961bb81903 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1265,6 +1265,8 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); intel_dp_start_link_train(intel_dp); intel_dp_complete_link_train(intel_dp); + if (port != PORT_A) + intel_dp_stop_link_train(intel_dp); } } @@ -1326,6 +1328,9 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder) } else if (type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + if (port == PORT_A) + intel_dp_stop_link_train(intel_dp); + ironlake_edp_backlight_on(intel_dp); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6e423e04c35e..efe829919755 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4084,26 +4084,36 @@ static int i830_get_display_clock_speed(struct drm_device *dev) } static void -intel_reduce_ratio(uint32_t *num, uint32_t *den) +intel_reduce_m_n_ratio(uint32_t *num, uint32_t *den) { - while (*num > 0xffffff || *den > 0xffffff) { + while (*num > DATA_LINK_M_N_MASK || + *den > DATA_LINK_M_N_MASK) { *num >>= 1; *den >>= 1; } } +static void compute_m_n(unsigned int m, unsigned int n, + uint32_t *ret_m, uint32_t *ret_n) +{ + *ret_n = min_t(unsigned int, roundup_pow_of_two(n), DATA_LINK_N_MAX); + *ret_m = div_u64((uint64_t) m * *ret_n, n); + intel_reduce_m_n_ratio(ret_m, ret_n); +} + void intel_link_compute_m_n(int bits_per_pixel, int nlanes, int pixel_clock, int link_clock, struct intel_link_m_n *m_n) { m_n->tu = 64; - m_n->gmch_m = bits_per_pixel * pixel_clock; - m_n->gmch_n = link_clock * nlanes * 8; - intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n); - m_n->link_m = pixel_clock; - m_n->link_n = link_clock; - intel_reduce_ratio(&m_n->link_m, &m_n->link_n); + + compute_m_n(bits_per_pixel * pixel_clock, + link_clock * nlanes * 8, + &m_n->gmch_m, &m_n->gmch_n); + + compute_m_n(pixel_clock, link_clock, + &m_n->link_m, &m_n->link_n); } static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index a3288376ac71..b14bec93fb69 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -702,6 +702,9 @@ intel_dp_compute_config(struct intel_encoder *encoder, /* Walk through all bpp values. Luckily they're all nicely spaced with 2 * bpc in between. */ bpp = min_t(int, 8*3, pipe_config->pipe_bpp); + if (is_edp(intel_dp) && dev_priv->edp.bpp) + bpp = min_t(int, bpp, dev_priv->edp.bpp); + for (; bpp >= 6*3; bpp -= 2*3) { mode_rate = intel_dp_link_required(target_clock, bpp); @@ -739,6 +742,7 @@ found: intel_dp->link_bw = bws[clock]; intel_dp->lane_count = lane_count; adjusted_mode->clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw); + pipe_config->pipe_bpp = bpp; pipe_config->pixel_target_clock = target_clock; DRM_DEBUG_KMS("DP link bw %02x lane count %d clock %d bpp %d\n", @@ -751,20 +755,6 @@ found: target_clock, adjusted_mode->clock, &pipe_config->dp_m_n); - /* - * XXX: We have a strange regression where using the vbt edp bpp value - * for the link bw computation results in black screens, the panel only - * works when we do the computation at the usual 24bpp (but still - * requires us to use 18bpp). Until that's fully debugged, stay - * bug-for-bug compatible with the old code. - */ - if (is_edp(intel_dp) && dev_priv->edp.bpp) { - DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", - bpp, dev_priv->edp.bpp); - bpp = min_t(int, bpp, dev_priv->edp.bpp); - } - pipe_config->pipe_bpp = bpp; - return true; } @@ -1389,6 +1379,7 @@ static void intel_enable_dp(struct intel_encoder *encoder) ironlake_edp_panel_on(intel_dp); ironlake_edp_panel_vdd_off(intel_dp, true); intel_dp_complete_link_train(intel_dp); + intel_dp_stop_link_train(intel_dp); ironlake_edp_backlight_on(intel_dp); } @@ -1711,10 +1702,9 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, struct drm_i915_private *dev_priv = dev->dev_private; enum port port = intel_dig_port->port; int ret; - uint32_t temp; if (HAS_DDI(dev)) { - temp = I915_READ(DP_TP_CTL(port)); + uint32_t temp = I915_READ(DP_TP_CTL(port)); if (dp_train_pat & DP_LINK_SCRAMBLING_DISABLE) temp |= DP_TP_CTL_SCRAMBLE_DISABLE; @@ -1724,18 +1714,6 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, temp &= ~DP_TP_CTL_LINK_TRAIN_MASK; switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) { case DP_TRAINING_PATTERN_DISABLE: - - if (port != PORT_A) { - temp |= DP_TP_CTL_LINK_TRAIN_IDLE; - I915_WRITE(DP_TP_CTL(port), temp); - - if (wait_for((I915_READ(DP_TP_STATUS(port)) & - DP_TP_STATUS_IDLE_DONE), 1)) - DRM_ERROR("Timed out waiting for DP idle patterns\n"); - - temp &= ~DP_TP_CTL_LINK_TRAIN_MASK; - } - temp |= DP_TP_CTL_LINK_TRAIN_NORMAL; break; @@ -1811,6 +1789,37 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, return true; } +static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum port port = intel_dig_port->port; + uint32_t val; + + if (!HAS_DDI(dev)) + return; + + val = I915_READ(DP_TP_CTL(port)); + val &= ~DP_TP_CTL_LINK_TRAIN_MASK; + val |= DP_TP_CTL_LINK_TRAIN_IDLE; + I915_WRITE(DP_TP_CTL(port), val); + + /* + * On PORT_A we can have only eDP in SST mode. There the only reason + * we need to set idle transmission mode is to work around a HW issue + * where we enable the pipe while not in idle link-training mode. + * In this case there is requirement to wait for a minimum number of + * idle patterns to be sent. + */ + if (port == PORT_A) + return; + + if (wait_for((I915_READ(DP_TP_STATUS(port)) & DP_TP_STATUS_IDLE_DONE), + 1)) + DRM_ERROR("Timed out waiting for DP idle patterns\n"); +} + /* Enable corresponding port and start training pattern 1 */ void intel_dp_start_link_train(struct intel_dp *intel_dp) @@ -1953,10 +1962,19 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) ++tries; } + intel_dp_set_idle_link_train(intel_dp); + + intel_dp->DP = DP; + if (channel_eq) DRM_DEBUG_KMS("Channel EQ done. DP Training successfull\n"); - intel_dp_set_link_train(intel_dp, DP, DP_TRAINING_PATTERN_DISABLE); +} + +void intel_dp_stop_link_train(struct intel_dp *intel_dp) +{ + intel_dp_set_link_train(intel_dp, intel_dp->DP, + DP_TRAINING_PATTERN_DISABLE); } static void @@ -2164,6 +2182,7 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) drm_get_encoder_name(&intel_encoder->base)); intel_dp_start_link_train(intel_dp); intel_dp_complete_link_train(intel_dp); + intel_dp_stop_link_train(intel_dp); } } @@ -2428,6 +2447,9 @@ intel_dp_set_property(struct drm_connector *connector, } if (property == dev_priv->broadcast_rgb_property) { + bool old_auto = intel_dp->color_range_auto; + uint32_t old_range = intel_dp->color_range; + switch (val) { case INTEL_BROADCAST_RGB_AUTO: intel_dp->color_range_auto = true; @@ -2443,6 +2465,11 @@ intel_dp_set_property(struct drm_connector *connector, default: return -EINVAL; } + + if (old_auto == intel_dp->color_range_auto && + old_range == intel_dp->color_range) + return 0; + goto done; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b5b6d19e6dd3..624a9e6b8d71 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -499,6 +499,7 @@ extern void intel_dp_init_connector(struct intel_digital_port *intel_dig_port, extern void intel_dp_init_link_config(struct intel_dp *intel_dp); extern void intel_dp_start_link_train(struct intel_dp *intel_dp); extern void intel_dp_complete_link_train(struct intel_dp *intel_dp); +extern void intel_dp_stop_link_train(struct intel_dp *intel_dp); extern void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode); extern void intel_dp_encoder_destroy(struct drm_encoder *encoder); extern void intel_dp_check_link_status(struct intel_dp *intel_dp); diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 00e70dbe82da..cc70b16d5d42 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -448,6 +448,7 @@ void intel_dvo_init(struct drm_device *dev) const struct intel_dvo_device *dvo = &intel_dvo_devices[i]; struct i2c_adapter *i2c; int gpio; + bool dvoinit; /* Allow the I2C driver info to specify the GPIO to be used in * special cases, but otherwise default to what's defined @@ -467,7 +468,17 @@ void intel_dvo_init(struct drm_device *dev) i2c = intel_gmbus_get_adapter(dev_priv, gpio); intel_dvo->dev = *dvo; - if (!dvo->dev_ops->init(&intel_dvo->dev, i2c)) + + /* GMBUS NAK handling seems to be unstable, hence let the + * transmitter detection run in bit banging mode for now. + */ + intel_gmbus_force_bit(i2c, true); + + dvoinit = dvo->dev_ops->init(&intel_dvo->dev, i2c); + + intel_gmbus_force_bit(i2c, false); + + if (!dvoinit) continue; intel_encoder->type = INTEL_OUTPUT_DVO; diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 0e19e575a1b4..6b7c3ca2c035 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -262,10 +262,22 @@ void intel_fbdev_fini(struct drm_device *dev) void intel_fbdev_set_suspend(struct drm_device *dev, int state) { drm_i915_private_t *dev_priv = dev->dev_private; - if (!dev_priv->fbdev) + struct intel_fbdev *ifbdev = dev_priv->fbdev; + struct fb_info *info; + + if (!ifbdev) return; - fb_set_suspend(dev_priv->fbdev->helper.fbdev, state); + info = ifbdev->helper.fbdev; + + /* On resume from hibernation: If the object is shmemfs backed, it has + * been restored from swap. If the object is stolen however, it will be + * full of whatever garbage was left in there. + */ + if (!state && ifbdev->ifb.obj->stolen) + memset_io(info->screen_base, 0, info->screen_size); + + fb_set_suspend(info, state); } MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 3e6a3ef10d5c..a9057930f2b2 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -920,6 +920,9 @@ intel_hdmi_set_property(struct drm_connector *connector, } if (property == dev_priv->broadcast_rgb_property) { + bool old_auto = intel_hdmi->color_range_auto; + uint32_t old_range = intel_hdmi->color_range; + switch (val) { case INTEL_BROADCAST_RGB_AUTO: intel_hdmi->color_range_auto = true; @@ -935,6 +938,11 @@ intel_hdmi_set_property(struct drm_connector *connector, default: return -EINVAL; } + + if (old_auto == intel_hdmi->color_range_auto && + old_range == intel_hdmi->color_range) + return 0; + goto done; } diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index e34ad9642519..aa01128ff192 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1301,17 +1301,17 @@ static void valleyview_update_wm(struct drm_device *dev) vlv_update_drain_latency(dev); - if (g4x_compute_wm0(dev, 0, + if (g4x_compute_wm0(dev, PIPE_A, &valleyview_wm_info, latency_ns, &valleyview_cursor_wm_info, latency_ns, &planea_wm, &cursora_wm)) - enabled |= 1; + enabled |= 1 << PIPE_A; - if (g4x_compute_wm0(dev, 1, + if (g4x_compute_wm0(dev, PIPE_B, &valleyview_wm_info, latency_ns, &valleyview_cursor_wm_info, latency_ns, &planeb_wm, &cursorb_wm)) - enabled |= 2; + enabled |= 1 << PIPE_B; if (single_plane_enabled(enabled) && g4x_compute_srwm(dev, ffs(enabled) - 1, @@ -1357,17 +1357,17 @@ static void g4x_update_wm(struct drm_device *dev) int plane_sr, cursor_sr; unsigned int enabled = 0; - if (g4x_compute_wm0(dev, 0, + if (g4x_compute_wm0(dev, PIPE_A, &g4x_wm_info, latency_ns, &g4x_cursor_wm_info, latency_ns, &planea_wm, &cursora_wm)) - enabled |= 1; + enabled |= 1 << PIPE_A; - if (g4x_compute_wm0(dev, 1, + if (g4x_compute_wm0(dev, PIPE_B, &g4x_wm_info, latency_ns, &g4x_cursor_wm_info, latency_ns, &planeb_wm, &cursorb_wm)) - enabled |= 2; + enabled |= 1 << PIPE_B; if (single_plane_enabled(enabled) && g4x_compute_srwm(dev, ffs(enabled) - 1, @@ -1716,7 +1716,7 @@ static void ironlake_update_wm(struct drm_device *dev) unsigned int enabled; enabled = 0; - if (g4x_compute_wm0(dev, 0, + if (g4x_compute_wm0(dev, PIPE_A, &ironlake_display_wm_info, ILK_LP0_PLANE_LATENCY, &ironlake_cursor_wm_info, @@ -1727,10 +1727,10 @@ static void ironlake_update_wm(struct drm_device *dev) DRM_DEBUG_KMS("FIFO watermarks For pipe A -" " plane %d, " "cursor: %d\n", plane_wm, cursor_wm); - enabled |= 1; + enabled |= 1 << PIPE_A; } - if (g4x_compute_wm0(dev, 1, + if (g4x_compute_wm0(dev, PIPE_B, &ironlake_display_wm_info, ILK_LP0_PLANE_LATENCY, &ironlake_cursor_wm_info, @@ -1741,7 +1741,7 @@ static void ironlake_update_wm(struct drm_device *dev) DRM_DEBUG_KMS("FIFO watermarks For pipe B -" " plane %d, cursor: %d\n", plane_wm, cursor_wm); - enabled |= 2; + enabled |= 1 << PIPE_B; } /* @@ -1801,7 +1801,7 @@ static void sandybridge_update_wm(struct drm_device *dev) unsigned int enabled; enabled = 0; - if (g4x_compute_wm0(dev, 0, + if (g4x_compute_wm0(dev, PIPE_A, &sandybridge_display_wm_info, latency, &sandybridge_cursor_wm_info, latency, &plane_wm, &cursor_wm)) { @@ -1812,10 +1812,10 @@ static void sandybridge_update_wm(struct drm_device *dev) DRM_DEBUG_KMS("FIFO watermarks For pipe A -" " plane %d, " "cursor: %d\n", plane_wm, cursor_wm); - enabled |= 1; + enabled |= 1 << PIPE_A; } - if (g4x_compute_wm0(dev, 1, + if (g4x_compute_wm0(dev, PIPE_B, &sandybridge_display_wm_info, latency, &sandybridge_cursor_wm_info, latency, &plane_wm, &cursor_wm)) { @@ -1826,7 +1826,7 @@ static void sandybridge_update_wm(struct drm_device *dev) DRM_DEBUG_KMS("FIFO watermarks For pipe B -" " plane %d, cursor: %d\n", plane_wm, cursor_wm); - enabled |= 2; + enabled |= 1 << PIPE_B; } /* @@ -1904,7 +1904,7 @@ static void ivybridge_update_wm(struct drm_device *dev) unsigned int enabled; enabled = 0; - if (g4x_compute_wm0(dev, 0, + if (g4x_compute_wm0(dev, PIPE_A, &sandybridge_display_wm_info, latency, &sandybridge_cursor_wm_info, latency, &plane_wm, &cursor_wm)) { @@ -1915,10 +1915,10 @@ static void ivybridge_update_wm(struct drm_device *dev) DRM_DEBUG_KMS("FIFO watermarks For pipe A -" " plane %d, " "cursor: %d\n", plane_wm, cursor_wm); - enabled |= 1; + enabled |= 1 << PIPE_A; } - if (g4x_compute_wm0(dev, 1, + if (g4x_compute_wm0(dev, PIPE_B, &sandybridge_display_wm_info, latency, &sandybridge_cursor_wm_info, latency, &plane_wm, &cursor_wm)) { @@ -1929,10 +1929,10 @@ static void ivybridge_update_wm(struct drm_device *dev) DRM_DEBUG_KMS("FIFO watermarks For pipe B -" " plane %d, cursor: %d\n", plane_wm, cursor_wm); - enabled |= 2; + enabled |= 1 << PIPE_B; } - if (g4x_compute_wm0(dev, 2, + if (g4x_compute_wm0(dev, PIPE_C, &sandybridge_display_wm_info, latency, &sandybridge_cursor_wm_info, latency, &plane_wm, &cursor_wm)) { @@ -1943,7 +1943,7 @@ static void ivybridge_update_wm(struct drm_device *dev) DRM_DEBUG_KMS("FIFO watermarks For pipe C -" " plane %d, cursor: %d\n", plane_wm, cursor_wm); - enabled |= 3; + enabled |= 1 << PIPE_C; } /* @@ -2639,7 +2639,7 @@ static void gen6_enable_rps(struct drm_device *dev) (IS_HASWELL(dev) ? GEN7_RP_DOWN_IDLE_AVG : GEN6_RP_DOWN_IDLE_CONT)); ret = sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_MIN_FREQ_TABLE, 0); - if (!ret && (IS_GEN6(dev) || IS_IVYBRIDGE(dev))) { + if (!ret) { pcu_mbox = 0; ret = sandybridge_pcode_read(dev_priv, GEN6_READ_OC_PARAMS, &pcu_mbox); if (!ret && (pcu_mbox & (1<<31))) { /* OC supported */ diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index a618a6a45a77..d15428404b9a 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1930,6 +1930,9 @@ intel_sdvo_set_property(struct drm_connector *connector, } if (property == dev_priv->broadcast_rgb_property) { + bool old_auto = intel_sdvo->color_range_auto; + uint32_t old_range = intel_sdvo->color_range; + switch (val) { case INTEL_BROADCAST_RGB_AUTO: intel_sdvo->color_range_auto = true; @@ -1947,6 +1950,11 @@ intel_sdvo_set_property(struct drm_connector *connector, default: return -EINVAL; } + + if (old_auto == intel_sdvo->color_range_auto && + old_range == intel_sdvo->color_range) + return 0; + goto done; } diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index dcfc973e29f7..bf29b2f4d68d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -115,6 +115,8 @@ struct mga_fbdev { void *sysram; int size; struct ttm_bo_kmap_obj mapping; + int x1, y1, x2, y2; /* dirty rect */ + spinlock_t dirty_lock; }; struct mga_crtc { diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c index 2ebe0f635b26..5da824ce9ba1 100644 --- a/drivers/gpu/drm/mgag200/mgag200_fb.c +++ b/drivers/gpu/drm/mgag200/mgag200_fb.c @@ -29,16 +29,52 @@ static void mga_dirty_update(struct mga_fbdev *mfbdev, int bpp = (mfbdev->mfb.base.bits_per_pixel + 7)/8; int ret; bool unmap = false; + bool store_for_later = false; + int x2, y2; + unsigned long flags; obj = mfbdev->mfb.obj; bo = gem_to_mga_bo(obj); + /* + * try and reserve the BO, if we fail with busy + * then the BO is being moved and we should + * store up the damage until later. + */ ret = mgag200_bo_reserve(bo, true); if (ret) { - DRM_ERROR("failed to reserve fb bo\n"); + if (ret != -EBUSY) + return; + + store_for_later = true; + } + + x2 = x + width - 1; + y2 = y + height - 1; + spin_lock_irqsave(&mfbdev->dirty_lock, flags); + + if (mfbdev->y1 < y) + y = mfbdev->y1; + if (mfbdev->y2 > y2) + y2 = mfbdev->y2; + if (mfbdev->x1 < x) + x = mfbdev->x1; + if (mfbdev->x2 > x2) + x2 = mfbdev->x2; + + if (store_for_later) { + mfbdev->x1 = x; + mfbdev->x2 = x2; + mfbdev->y1 = y; + mfbdev->y2 = y2; + spin_unlock_irqrestore(&mfbdev->dirty_lock, flags); return; } + mfbdev->x1 = mfbdev->y1 = INT_MAX; + mfbdev->x2 = mfbdev->y2 = 0; + spin_unlock_irqrestore(&mfbdev->dirty_lock, flags); + if (!bo->kmap.virtual) { ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); if (ret) { @@ -48,10 +84,10 @@ static void mga_dirty_update(struct mga_fbdev *mfbdev, } unmap = true; } - for (i = y; i < y + height; i++) { + for (i = y; i <= y2; i++) { /* assume equal stride for now */ src_offset = dst_offset = i * mfbdev->mfb.base.pitches[0] + (x * bpp); - memcpy_toio(bo->kmap.virtual + src_offset, mfbdev->sysram + src_offset, width * bpp); + memcpy_toio(bo->kmap.virtual + src_offset, mfbdev->sysram + src_offset, (x2 - x + 1) * bpp); } if (unmap) @@ -105,12 +141,9 @@ static int mgag200fb_create_object(struct mga_fbdev *afbdev, struct drm_gem_object **gobj_p) { struct drm_device *dev = afbdev->helper.dev; - u32 bpp, depth; u32 size; struct drm_gem_object *gobj; - int ret = 0; - drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp); size = mode_cmd->pitches[0] * mode_cmd->height; ret = mgag200_gem_create(dev, size, true, &gobj); @@ -255,6 +288,7 @@ int mgag200_fbdev_init(struct mga_device *mdev) mdev->mfbdev = mfbdev; mfbdev->helper.funcs = &mga_fb_helper_funcs; + spin_lock_init(&mfbdev->dirty_lock); ret = drm_fb_helper_init(mdev->dev, &mfbdev->helper, mdev->num_crtc, MGAG200FB_CONN_LIMIT); diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c index 1f7ea057b2fc..99059237da38 100644 --- a/drivers/gpu/drm/mgag200/mgag200_main.c +++ b/drivers/gpu/drm/mgag200/mgag200_main.c @@ -217,8 +217,6 @@ int mgag200_driver_load(struct drm_device *dev, unsigned long flags) drm_mode_config_init(dev); dev->mode_config.funcs = (void *)&mga_mode_funcs; - dev->mode_config.min_width = 0; - dev->mode_config.min_height = 0; dev->mode_config.preferred_depth = 24; dev->mode_config.prefer_shadow = 1; diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index fe22bb780e1d..e8e20c653b1d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -46,29 +46,26 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc) static inline void mga_wait_vsync(struct mga_device *mdev) { - unsigned int count = 0; + unsigned long timeout = jiffies + HZ/10; unsigned int status = 0; do { status = RREG32(MGAREG_Status); - count++; - } while ((status & 0x08) && (count < 250000)); - count = 0; + } while ((status & 0x08) && time_before(jiffies, timeout)); + timeout = jiffies + HZ/10; status = 0; do { status = RREG32(MGAREG_Status); - count++; - } while (!(status & 0x08) && (count < 250000)); + } while (!(status & 0x08) && time_before(jiffies, timeout)); } static inline void mga_wait_busy(struct mga_device *mdev) { - unsigned int count = 0; + unsigned long timeout = jiffies + HZ; unsigned int status = 0; do { status = RREG8(MGAREG_Status + 2); - count++; - } while ((status & 0x01) && (count < 500000)); + } while ((status & 0x01) && time_before(jiffies, timeout)); } /* @@ -189,12 +186,12 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); tmp = RREG8(DAC_DATA); tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; - WREG_DAC(MGA1064_PIX_CLK_CTL_CLK_DIS, tmp); + WREG8(DAC_DATA, tmp); WREG8(DAC_INDEX, MGA1064_REMHEADCTL); tmp = RREG8(DAC_DATA); tmp |= MGA1064_REMHEADCTL_CLKDIS; - WREG_DAC(MGA1064_REMHEADCTL, tmp); + WREG8(DAC_DATA, tmp); /* select PLL Set C */ tmp = RREG8(MGAREG_MEM_MISC_READ); @@ -204,7 +201,7 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); tmp = RREG8(DAC_DATA); tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80; - WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); + WREG8(DAC_DATA, tmp); udelay(500); @@ -212,7 +209,7 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) WREG8(DAC_INDEX, MGA1064_VREF_CTL); tmp = RREG8(DAC_DATA); tmp &= ~0x04; - WREG_DAC(MGA1064_VREF_CTL, tmp); + WREG8(DAC_DATA, tmp); udelay(50); @@ -236,13 +233,13 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) tmp = RREG8(DAC_DATA); tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; - WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); + WREG8(DAC_DATA, tmp); WREG8(DAC_INDEX, MGA1064_REMHEADCTL); tmp = RREG8(DAC_DATA); tmp &= ~MGA1064_REMHEADCTL_CLKSL_MSK; tmp |= MGA1064_REMHEADCTL_CLKSL_PLL; - WREG_DAC(MGA1064_REMHEADCTL, tmp); + WREG8(DAC_DATA, tmp); /* reset dotclock rate bit */ WREG8(MGAREG_SEQ_INDEX, 1); @@ -253,7 +250,7 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); tmp = RREG8(DAC_DATA); tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; - WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); + WREG8(DAC_DATA, tmp); vcount = RREG8(MGAREG_VCOUNT); @@ -318,7 +315,7 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); tmp = RREG8(DAC_DATA); tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; - WREG_DAC(MGA1064_PIX_CLK_CTL_CLK_DIS, tmp); + WREG8(DAC_DATA, tmp); tmp = RREG8(MGAREG_MEM_MISC_READ); tmp |= 0x3 << 2; @@ -326,12 +323,12 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT); tmp = RREG8(DAC_DATA); - WREG_DAC(MGA1064_PIX_PLL_STAT, tmp & ~0x40); + WREG8(DAC_DATA, tmp & ~0x40); WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); tmp = RREG8(DAC_DATA); tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; - WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); + WREG8(DAC_DATA, tmp); WREG_DAC(MGA1064_EV_PIX_PLLC_M, m); WREG_DAC(MGA1064_EV_PIX_PLLC_N, n); @@ -342,7 +339,7 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); tmp = RREG8(DAC_DATA); tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; - WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); + WREG8(DAC_DATA, tmp); udelay(500); @@ -350,11 +347,11 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) tmp = RREG8(DAC_DATA); tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; - WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); + WREG8(DAC_DATA, tmp); WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT); tmp = RREG8(DAC_DATA); - WREG_DAC(MGA1064_PIX_PLL_STAT, tmp | 0x40); + WREG8(DAC_DATA, tmp | 0x40); tmp = RREG8(MGAREG_MEM_MISC_READ); tmp |= (0x3 << 2); @@ -363,7 +360,7 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); tmp = RREG8(DAC_DATA); tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; - WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); + WREG8(DAC_DATA, tmp); return 0; } @@ -416,7 +413,7 @@ static int mga_g200eh_set_plls(struct mga_device *mdev, long clock) WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); tmp = RREG8(DAC_DATA); tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; - WREG_DAC(MGA1064_PIX_CLK_CTL_CLK_DIS, tmp); + WREG8(DAC_DATA, tmp); tmp = RREG8(MGAREG_MEM_MISC_READ); tmp |= 0x3 << 2; @@ -425,7 +422,7 @@ static int mga_g200eh_set_plls(struct mga_device *mdev, long clock) WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); tmp = RREG8(DAC_DATA); tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; - WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); + WREG8(DAC_DATA, tmp); udelay(500); @@ -439,13 +436,13 @@ static int mga_g200eh_set_plls(struct mga_device *mdev, long clock) tmp = RREG8(DAC_DATA); tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; - WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); + WREG8(DAC_DATA, tmp); WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); tmp = RREG8(DAC_DATA); tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; - WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); + WREG8(DAC_DATA, tmp); vcount = RREG8(MGAREG_VCOUNT); @@ -515,12 +512,12 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock) WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); tmp = RREG8(DAC_DATA); tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; - WREG_DAC(MGA1064_PIX_CLK_CTL_CLK_DIS, tmp); + WREG8(DAC_DATA, tmp); WREG8(DAC_INDEX, MGA1064_REMHEADCTL); tmp = RREG8(DAC_DATA); tmp |= MGA1064_REMHEADCTL_CLKDIS; - WREG_DAC(MGA1064_REMHEADCTL, tmp); + WREG8(DAC_DATA, tmp); tmp = RREG8(MGAREG_MEM_MISC_READ); tmp |= (0x3<<2) | 0xc0; @@ -530,7 +527,7 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock) tmp = RREG8(DAC_DATA); tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; - WREG_DAC(MGA1064_PIX_CLK_CTL, tmp); + WREG8(DAC_DATA, tmp); udelay(500); @@ -657,12 +654,26 @@ static void mga_g200wb_commit(struct drm_crtc *crtc) WREG_DAC(MGA1064_GEN_IO_DATA, tmp); } - +/* + This is how the framebuffer base address is stored in g200 cards: + * Assume @offset is the gpu_addr variable of the framebuffer object + * Then addr is the number of _pixels_ (not bytes) from the start of + VRAM to the first pixel we want to display. (divided by 2 for 32bit + framebuffers) + * addr is stored in the CRTCEXT0, CRTCC and CRTCD registers + addr<20> -> CRTCEXT0<6> + addr<19-16> -> CRTCEXT0<3-0> + addr<15-8> -> CRTCC<7-0> + addr<7-0> -> CRTCD<7-0> + CRTCEXT0 has to be programmed last to trigger an update and make the + new addr variable take effect. + */ void mga_set_start_address(struct drm_crtc *crtc, unsigned offset) { struct mga_device *mdev = crtc->dev->dev_private; u32 addr; int count; + u8 crtcext0; while (RREG8(0x1fda) & 0x08); while (!(RREG8(0x1fda) & 0x08)); @@ -670,10 +681,17 @@ void mga_set_start_address(struct drm_crtc *crtc, unsigned offset) count = RREG8(MGAREG_VCOUNT) + 2; while (RREG8(MGAREG_VCOUNT) < count); - addr = offset >> 2; + WREG8(MGAREG_CRTCEXT_INDEX, 0); + crtcext0 = RREG8(MGAREG_CRTCEXT_DATA); + crtcext0 &= 0xB0; + addr = offset / 8; + /* Can't store addresses any higher than that... + but we also don't have more than 16MB of memory, so it should be fine. */ + WARN_ON(addr > 0x1fffff); + crtcext0 |= (!!(addr & (1<<20)))<<6; WREG_CRT(0x0d, (u8)(addr & 0xff)); WREG_CRT(0x0c, (u8)(addr >> 8) & 0xff); - WREG_CRT(0xaf, (u8)(addr >> 16) & 0xf); + WREG_ECRT(0x0, ((u8)(addr >> 16) & 0xf) | crtcext0); } @@ -832,11 +850,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, for (i = 0; i < sizeof(dacvalue); i++) { - if ((i <= 0x03) || - (i == 0x07) || - (i == 0x0b) || - (i == 0x0f) || - ((i >= 0x13) && (i <= 0x17)) || + if ((i <= 0x17) || (i == 0x1b) || (i == 0x1c) || ((i >= 0x1f) && (i <= 0x29)) || @@ -1261,9 +1275,8 @@ static const struct drm_crtc_helper_funcs mga_helper_funcs = { }; /* CRTC setup */ -static void mga_crtc_init(struct drm_device *dev) +static void mga_crtc_init(struct mga_device *mdev) { - struct mga_device *mdev = dev->dev_private; struct mga_crtc *mga_crtc; int i; @@ -1274,7 +1287,7 @@ static void mga_crtc_init(struct drm_device *dev) if (mga_crtc == NULL) return; - drm_crtc_init(dev, &mga_crtc->base, &mga_crtc_funcs); + drm_crtc_init(mdev->dev, &mga_crtc->base, &mga_crtc_funcs); drm_mode_crtc_set_gamma_size(&mga_crtc->base, MGAG200_LUT_SIZE); mdev->mode_info.crtc = mga_crtc; @@ -1529,7 +1542,7 @@ int mgag200_modeset_init(struct mga_device *mdev) mdev->dev->mode_config.fb_base = mdev->mc.vram_base; - mga_crtc_init(mdev->dev); + mga_crtc_init(mdev); encoder = mga_encoder_init(mdev->dev); if (!encoder) { diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c index 8fc9d9201945..401c9891d3a8 100644 --- a/drivers/gpu/drm/mgag200/mgag200_ttm.c +++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c @@ -315,8 +315,8 @@ int mgag200_bo_reserve(struct mgag200_bo *bo, bool no_wait) ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0); if (ret) { - if (ret != -ERESTARTSYS) - DRM_ERROR("reserve failed %p\n", bo); + if (ret != -ERESTARTSYS && ret != -EBUSY) + DRM_ERROR("reserve failed %p %d\n", bo, ret); return ret; } return 0; diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c index 0682cb5c0150..be7cd97a0db0 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c +++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c @@ -212,7 +212,6 @@ struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, * refcount on gem itself instead of f_count of dmabuf. */ drm_gem_object_reference(obj); - dma_buf_put(buffer); return obj; } } diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c index 736365e6ca80..f86771481317 100644 --- a/drivers/gpu/drm/qxl/qxl_cmd.c +++ b/drivers/gpu/drm/qxl/qxl_cmd.c @@ -277,7 +277,7 @@ out_unref: return 0; } -static int wait_for_io_cmd_user(struct qxl_device *qdev, uint8_t val, long port) +static int wait_for_io_cmd_user(struct qxl_device *qdev, uint8_t val, long port, bool intr) { int irq_num; long addr = qdev->io_base + port; @@ -285,20 +285,29 @@ static int wait_for_io_cmd_user(struct qxl_device *qdev, uint8_t val, long port) mutex_lock(&qdev->async_io_mutex); irq_num = atomic_read(&qdev->irq_received_io_cmd); - - if (qdev->last_sent_io_cmd > irq_num) { - ret = wait_event_interruptible(qdev->io_cmd_event, - atomic_read(&qdev->irq_received_io_cmd) > irq_num); - if (ret) + if (intr) + ret = wait_event_interruptible_timeout(qdev->io_cmd_event, + atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); + else + ret = wait_event_timeout(qdev->io_cmd_event, + atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); + /* 0 is timeout, just bail the "hw" has gone away */ + if (ret <= 0) goto out; irq_num = atomic_read(&qdev->irq_received_io_cmd); } outb(val, addr); qdev->last_sent_io_cmd = irq_num + 1; - ret = wait_event_interruptible(qdev->io_cmd_event, - atomic_read(&qdev->irq_received_io_cmd) > irq_num); + if (intr) + ret = wait_event_interruptible_timeout(qdev->io_cmd_event, + atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); + else + ret = wait_event_timeout(qdev->io_cmd_event, + atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); out: + if (ret > 0) + ret = 0; mutex_unlock(&qdev->async_io_mutex); return ret; } @@ -308,7 +317,7 @@ static void wait_for_io_cmd(struct qxl_device *qdev, uint8_t val, long port) int ret; restart: - ret = wait_for_io_cmd_user(qdev, val, port); + ret = wait_for_io_cmd_user(qdev, val, port, false); if (ret == -ERESTARTSYS) goto restart; } @@ -340,7 +349,7 @@ int qxl_io_update_area(struct qxl_device *qdev, struct qxl_bo *surf, mutex_lock(&qdev->update_area_mutex); qdev->ram_header->update_area = *area; qdev->ram_header->update_surface = surface_id; - ret = wait_for_io_cmd_user(qdev, 0, QXL_IO_UPDATE_AREA_ASYNC); + ret = wait_for_io_cmd_user(qdev, 0, QXL_IO_UPDATE_AREA_ASYNC, true); mutex_unlock(&qdev->update_area_mutex); return ret; } @@ -435,22 +444,18 @@ void qxl_io_monitors_config(struct qxl_device *qdev) int qxl_surface_id_alloc(struct qxl_device *qdev, struct qxl_bo *surf) { - uint32_t handle = -ENOMEM; + uint32_t handle; int idr_ret; int count = 0; again: - if (idr_pre_get(&qdev->surf_id_idr, GFP_ATOMIC) == 0) { - DRM_ERROR("Out of memory for surf idr\n"); - kfree(surf); - goto alloc_fail; - } - + idr_preload(GFP_ATOMIC); spin_lock(&qdev->surf_id_idr_lock); - idr_ret = idr_get_new_above(&qdev->surf_id_idr, NULL, 1, &handle); + idr_ret = idr_alloc(&qdev->surf_id_idr, NULL, 1, 0, GFP_NOWAIT); spin_unlock(&qdev->surf_id_idr_lock); - - if (idr_ret == -EAGAIN) - goto again; + idr_preload_end(); + if (idr_ret < 0) + return idr_ret; + handle = idr_ret; if (handle >= qdev->rom->n_surfaces) { count++; @@ -465,7 +470,6 @@ again: spin_lock(&qdev->surf_id_idr_lock); qdev->last_alloced_surf_id = handle; spin_unlock(&qdev->surf_id_idr_lock); - alloc_fail: return 0; } diff --git a/drivers/gpu/drm/qxl/qxl_debugfs.c b/drivers/gpu/drm/qxl/qxl_debugfs.c index c630152f2d2f..c3c2bbdc6674 100644 --- a/drivers/gpu/drm/qxl/qxl_debugfs.c +++ b/drivers/gpu/drm/qxl/qxl_debugfs.c @@ -35,6 +35,7 @@ #include "qxl_object.h" +#if defined(CONFIG_DEBUG_FS) static int qxl_debugfs_irq_received(struct seq_file *m, void *data) { @@ -69,20 +70,25 @@ static struct drm_info_list qxl_debugfs_list[] = { { "qxl_buffers", qxl_debugfs_buffers_info, 0, NULL }, }; #define QXL_DEBUGFS_ENTRIES ARRAY_SIZE(qxl_debugfs_list) +#endif int qxl_debugfs_init(struct drm_minor *minor) { +#if defined(CONFIG_DEBUG_FS) drm_debugfs_create_files(qxl_debugfs_list, QXL_DEBUGFS_ENTRIES, minor->debugfs_root, minor); +#endif return 0; } void qxl_debugfs_takedown(struct drm_minor *minor) { +#if defined(CONFIG_DEBUG_FS) drm_debugfs_remove_files(qxl_debugfs_list, QXL_DEBUGFS_ENTRIES, minor); +#endif } int qxl_debugfs_add_files(struct qxl_device *qdev, diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index fcfd4436ceed..823d29e926ec 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -428,10 +428,10 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb, int inc = 1; qobj = gem_to_qxl_bo(qxl_fb->obj); - if (qxl_fb != qdev->active_user_framebuffer) { - DRM_INFO("%s: qxl_fb 0x%p != qdev->active_user_framebuffer 0x%p\n", - __func__, qxl_fb, qdev->active_user_framebuffer); - } + /* if we aren't primary surface ignore this */ + if (!qobj->is_primary) + return 0; + if (!num_clips) { num_clips = 1; clips = &norect; @@ -604,7 +604,6 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc, mode->hdisplay, mode->vdisplay); } - qdev->mode_set = true; return 0; } @@ -893,7 +892,6 @@ qxl_user_framebuffer_create(struct drm_device *dev, { struct drm_gem_object *obj; struct qxl_framebuffer *qxl_fb; - struct qxl_device *qdev = dev->dev_private; int ret; obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]); @@ -909,13 +907,6 @@ qxl_user_framebuffer_create(struct drm_device *dev, return NULL; } - if (qdev->active_user_framebuffer) { - DRM_INFO("%s: active_user_framebuffer %p -> %p\n", - __func__, - qdev->active_user_framebuffer, qxl_fb); - } - qdev->active_user_framebuffer = qxl_fb; - return &qxl_fb->base; } diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 52b582c211da..43d06ab28a21 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -255,12 +255,6 @@ struct qxl_device { struct qxl_gem gem; struct qxl_mode_info mode_info; - /* - * last created framebuffer with fb_create - * only used by debugfs dumbppm - */ - struct qxl_framebuffer *active_user_framebuffer; - struct fb_info *fbdev_info; struct qxl_framebuffer *fbdev_qfb; void *ram_physical; @@ -270,7 +264,6 @@ struct qxl_device { struct qxl_ring *cursor_ring; struct qxl_ram_header *ram_header; - bool mode_set; bool primary_created; diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c index 04b64f9cbfdb..6db7370373ea 100644 --- a/drivers/gpu/drm/qxl/qxl_ioctl.c +++ b/drivers/gpu/drm/qxl/qxl_ioctl.c @@ -294,6 +294,7 @@ static int qxl_update_area_ioctl(struct drm_device *dev, void *data, goto out; if (!qobj->pin_count) { + qxl_ttm_placement_from_domain(qobj, qobj->type); ret = ttm_bo_validate(&qobj->tbo, &qobj->placement, true, false); if (unlikely(ret)) diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c index c4267c71dd2d..b443d6751d5f 100644 --- a/drivers/gpu/drm/qxl/qxl_release.c +++ b/drivers/gpu/drm/qxl/qxl_release.c @@ -43,7 +43,7 @@ qxl_release_alloc(struct qxl_device *qdev, int type, struct qxl_release **ret) { struct qxl_release *release; - int handle = 0; + int handle; size_t size = sizeof(*release); int idr_ret; @@ -56,19 +56,16 @@ qxl_release_alloc(struct qxl_device *qdev, int type, release->bo_count = 0; release->release_offset = 0; release->surface_release_id = 0; -again: - if (idr_pre_get(&qdev->release_idr, GFP_KERNEL) == 0) { - DRM_ERROR("Out of memory for release idr\n"); - kfree(release); - goto release_fail; - } + + idr_preload(GFP_KERNEL); spin_lock(&qdev->release_idr_lock); - idr_ret = idr_get_new_above(&qdev->release_idr, release, 1, &handle); + idr_ret = idr_alloc(&qdev->release_idr, release, 1, 0, GFP_NOWAIT); spin_unlock(&qdev->release_idr_lock); - if (idr_ret == -EAGAIN) - goto again; - if (ret) - *ret = release; + idr_preload_end(); + handle = idr_ret; + if (idr_ret < 0) + goto release_fail; + *ret = release; QXL_INFO(qdev, "allocated release %lld\n", handle); release->id = handle; release_fail: diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index 46a9c3772850..fb441a790f3d 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -1394,10 +1394,10 @@ int atom_allocate_fb_scratch(struct atom_context *ctx) firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset); DRM_DEBUG("atom firmware requested %08x %dkb\n", - firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware, - firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb); + le32_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware), + le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb)); - usage_bytes = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024; + usage_bytes = le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb) * 1024; } ctx->scratch_size_bytes = 0; if (usage_bytes == 0) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 1531f167d152..105bafb6c29d 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -989,62 +989,10 @@ done: return r; } -static int evergreen_uvd_calc_post_div(unsigned target_freq, - unsigned vco_freq, - unsigned *div) -{ - /* target larger than vco frequency ? */ - if (vco_freq < target_freq) - return -1; /* forget it */ - - /* Fclk = Fvco / PDIV */ - *div = vco_freq / target_freq; - - /* we alway need a frequency less than or equal the target */ - if ((vco_freq / *div) > target_freq) - *div += 1; - - /* dividers above 5 must be even */ - if (*div > 5 && *div % 2) - *div += 1; - - /* out of range ? */ - if (*div >= 128) - return -1; /* forget it */ - - return vco_freq / *div; -} - -static int evergreen_uvd_send_upll_ctlreq(struct radeon_device *rdev) -{ - unsigned i; - - /* assert UPLL_CTLREQ */ - WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_CTLREQ_MASK, ~UPLL_CTLREQ_MASK); - - /* wait for CTLACK and CTLACK2 to get asserted */ - for (i = 0; i < 100; ++i) { - uint32_t mask = UPLL_CTLACK_MASK | UPLL_CTLACK2_MASK; - if ((RREG32(CG_UPLL_FUNC_CNTL) & mask) == mask) - break; - mdelay(10); - } - if (i == 100) - return -ETIMEDOUT; - - /* deassert UPLL_CTLREQ */ - WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_CTLREQ_MASK); - - return 0; -} - int evergreen_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) { /* start off with something large */ - int optimal_diff_score = 0x7FFFFFF; - unsigned optimal_fb_div = 0, optimal_vclk_div = 0; - unsigned optimal_dclk_div = 0, optimal_vco_freq = 0; - unsigned vco_freq; + unsigned fb_div = 0, vclk_div = 0, dclk_div = 0; int r; /* bypass vclk and dclk with bclk */ @@ -1061,40 +1009,11 @@ int evergreen_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) return 0; } - /* loop through vco from low to high */ - for (vco_freq = 125000; vco_freq <= 250000; vco_freq += 100) { - unsigned fb_div = vco_freq / rdev->clock.spll.reference_freq * 16384; - int calc_clk, diff_score, diff_vclk, diff_dclk; - unsigned vclk_div, dclk_div; - - /* fb div out of range ? */ - if (fb_div > 0x03FFFFFF) - break; /* it can oly get worse */ - - /* calc vclk with current vco freq. */ - calc_clk = evergreen_uvd_calc_post_div(vclk, vco_freq, &vclk_div); - if (calc_clk == -1) - break; /* vco is too big, it has to stop. */ - diff_vclk = vclk - calc_clk; - - /* calc dclk with current vco freq. */ - calc_clk = evergreen_uvd_calc_post_div(dclk, vco_freq, &dclk_div); - if (calc_clk == -1) - break; /* vco is too big, it has to stop. */ - diff_dclk = dclk - calc_clk; - - /* determine if this vco setting is better than current optimal settings */ - diff_score = abs(diff_vclk) + abs(diff_dclk); - if (diff_score < optimal_diff_score) { - optimal_fb_div = fb_div; - optimal_vclk_div = vclk_div; - optimal_dclk_div = dclk_div; - optimal_vco_freq = vco_freq; - optimal_diff_score = diff_score; - if (optimal_diff_score == 0) - break; /* it can't get better than this */ - } - } + r = radeon_uvd_calc_upll_dividers(rdev, vclk, dclk, 125000, 250000, + 16384, 0x03FFFFFF, 0, 128, 5, + &fb_div, &vclk_div, &dclk_div); + if (r) + return r; /* set VCO_MODE to 1 */ WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_VCO_MODE_MASK, ~UPLL_VCO_MODE_MASK); @@ -1108,7 +1027,7 @@ int evergreen_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) mdelay(1); - r = evergreen_uvd_send_upll_ctlreq(rdev); + r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL); if (r) return r; @@ -1119,19 +1038,19 @@ int evergreen_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) WREG32_P(CG_UPLL_SPREAD_SPECTRUM, 0, ~SSEN_MASK); /* set feedback divider */ - WREG32_P(CG_UPLL_FUNC_CNTL_3, UPLL_FB_DIV(optimal_fb_div), ~UPLL_FB_DIV_MASK); + WREG32_P(CG_UPLL_FUNC_CNTL_3, UPLL_FB_DIV(fb_div), ~UPLL_FB_DIV_MASK); /* set ref divider to 0 */ WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_REF_DIV_MASK); - if (optimal_vco_freq < 187500) + if (fb_div < 307200) WREG32_P(CG_UPLL_FUNC_CNTL_4, 0, ~UPLL_SPARE_ISPARE9); else WREG32_P(CG_UPLL_FUNC_CNTL_4, UPLL_SPARE_ISPARE9, ~UPLL_SPARE_ISPARE9); /* set PDIV_A and PDIV_B */ WREG32_P(CG_UPLL_FUNC_CNTL_2, - UPLL_PDIV_A(optimal_vclk_div) | UPLL_PDIV_B(optimal_dclk_div), + UPLL_PDIV_A(vclk_div) | UPLL_PDIV_B(dclk_div), ~(UPLL_PDIV_A_MASK | UPLL_PDIV_B_MASK)); /* give the PLL some time to settle */ @@ -1145,7 +1064,7 @@ int evergreen_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) /* switch from bypass mode to normal mode */ WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_BYPASS_EN_MASK); - r = evergreen_uvd_send_upll_ctlreq(rdev); + r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL); if (r) return r; diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index d9a005431087..75c05631146d 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -59,7 +59,7 @@ # define UPLL_SLEEP_MASK 0x00000002 # define UPLL_BYPASS_EN_MASK 0x00000004 # define UPLL_CTLREQ_MASK 0x00000008 -# define UPLL_REF_DIV_MASK 0x001F0000 +# define UPLL_REF_DIV_MASK 0x003F0000 # define UPLL_VCO_MODE_MASK 0x00000200 # define UPLL_CTLACK_MASK 0x40000000 # define UPLL_CTLACK2_MASK 0x80000000 diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 7436b91699d0..7969c0c8ec20 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -749,7 +749,8 @@ static void cayman_gpu_init(struct radeon_device *rdev) (rdev->pdev->device == 0x990F) || (rdev->pdev->device == 0x9910) || (rdev->pdev->device == 0x9917) || - (rdev->pdev->device == 0x9999)) { + (rdev->pdev->device == 0x9999) || + (rdev->pdev->device == 0x999C)) { rdev->config.cayman.max_simds_per_se = 6; rdev->config.cayman.max_backends_per_se = 2; } else if ((rdev->pdev->device == 0x9903) || @@ -758,7 +759,8 @@ static void cayman_gpu_init(struct radeon_device *rdev) (rdev->pdev->device == 0x990D) || (rdev->pdev->device == 0x990E) || (rdev->pdev->device == 0x9913) || - (rdev->pdev->device == 0x9918)) { + (rdev->pdev->device == 0x9918) || + (rdev->pdev->device == 0x999D)) { rdev->config.cayman.max_simds_per_se = 4; rdev->config.cayman.max_backends_per_se = 2; } else if ((rdev->pdev->device == 0x9919) || diff --git a/drivers/gpu/drm/radeon/r300_cmdbuf.c b/drivers/gpu/drm/radeon/r300_cmdbuf.c index 865e2c9980db..60170ea5e3a2 100644 --- a/drivers/gpu/drm/radeon/r300_cmdbuf.c +++ b/drivers/gpu/drm/radeon/r300_cmdbuf.c @@ -75,7 +75,7 @@ static int r300_emit_cliprects(drm_radeon_private_t *dev_priv, OUT_RING(CP_PACKET0(R300_RE_CLIPRECT_TL_0, nr * 2 - 1)); for (i = 0; i < nr; ++i) { - if (DRM_COPY_FROM_USER_UNCHECKED + if (DRM_COPY_FROM_USER (&box, &cmdbuf->boxes[n + i], sizeof(box))) { DRM_ERROR("copy cliprect faulted\n"); return -EFAULT; diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 6105b25b18c3..acb146c06973 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -1208,6 +1208,10 @@ #define UVD_CONTEXT_ID 0xf6f4 +# define UPLL_CTLREQ_MASK 0x00000008 +# define UPLL_CTLACK_MASK 0x40000000 +# define UPLL_CTLACK2_MASK 0x80000000 + /* * PM4 */ diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index d6c8cbaa8693..1442ce765d48 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -358,7 +358,8 @@ struct radeon_bo { struct radeon_device *rdev; struct drm_gem_object gem_base; - struct ttm_bo_kmap_obj dma_buf_vmap; + struct ttm_bo_kmap_obj dma_buf_vmap; + pid_t pid; }; #define gem_to_radeon_bo(gobj) container_of((gobj), struct radeon_bo, gem_base) @@ -372,6 +373,8 @@ struct radeon_bo_list { u32 tiling_flags; }; +int radeon_gem_debugfs_init(struct radeon_device *rdev); + /* sub-allocation manager, it has to be protected by another lock. * By conception this is an helper for other part of the driver * like the indirect buffer or semaphore, which both have their @@ -1159,6 +1162,17 @@ void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp); int radeon_uvd_cs_parse(struct radeon_cs_parser *parser); void radeon_uvd_note_usage(struct radeon_device *rdev); +int radeon_uvd_calc_upll_dividers(struct radeon_device *rdev, + unsigned vclk, unsigned dclk, + unsigned vco_min, unsigned vco_max, + unsigned fb_factor, unsigned fb_mask, + unsigned pd_min, unsigned pd_max, + unsigned pd_even, + unsigned *optimal_fb_div, + unsigned *optimal_vclk_div, + unsigned *optimal_dclk_div); +int radeon_uvd_send_upll_ctlreq(struct radeon_device *rdev, + unsigned cg_upll_func_cntl); struct r600_audio { int channels; diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 0dd87c0e0fac..dea6f63c9724 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -2028,6 +2028,8 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) num_modes = power_info->info.ucNumOfPowerModeEntries; if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK) num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK; + if (num_modes == 0) + return state_index; rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * num_modes, GFP_KERNEL); if (!rdev->pm.power_state) return state_index; @@ -2307,7 +2309,7 @@ static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rde rdev->pm.default_power_state_index = state_index; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[mode_index - 1]; - if (ASIC_IS_DCE5(rdev) && !(rdev->flags & RADEON_IS_IGP)) { + if ((rdev->family >= CHIP_BARTS) && !(rdev->flags & RADEON_IS_IGP)) { /* NI chips post without MC ucode, so default clocks are strobe mode only */ rdev->pm.default_sclk = rdev->pm.power_state[state_index].clock_info[0].sclk; rdev->pm.default_mclk = rdev->pm.power_state[state_index].clock_info[0].mclk; @@ -2345,7 +2347,7 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev, sclk |= clock_info->rs780.ucLowEngineClockHigh << 16; rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; } - } else if (ASIC_IS_DCE6(rdev)) { + } else if (rdev->family >= CHIP_TAHITI) { sclk = le16_to_cpu(clock_info->si.usEngineClockLow); sclk |= clock_info->si.ucEngineClockHigh << 16; mclk = le16_to_cpu(clock_info->si.usMemoryClockLow); @@ -2358,7 +2360,7 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev, le16_to_cpu(clock_info->si.usVDDC); rdev->pm.power_state[state_index].clock_info[mode_index].voltage.vddci = le16_to_cpu(clock_info->si.usVDDCI); - } else if (ASIC_IS_DCE4(rdev)) { + } else if (rdev->family >= CHIP_CEDAR) { sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow); sclk |= clock_info->evergreen.ucEngineClockHigh << 16; mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow); @@ -2432,6 +2434,8 @@ static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev) power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController); + if (power_info->pplib.ucNumStates == 0) + return state_index; rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * power_info->pplib.ucNumStates, GFP_KERNEL); if (!rdev->pm.power_state) @@ -2514,6 +2518,7 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); u16 data_offset; u8 frev, crev; + u8 *power_state_offset; if (!atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset)) @@ -2530,15 +2535,17 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) non_clock_info_array = (struct _NonClockInfoArray *) (mode_info->atom_context->bios + data_offset + le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); + if (state_array->ucNumEntries == 0) + return state_index; rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * state_array->ucNumEntries, GFP_KERNEL); if (!rdev->pm.power_state) return state_index; + power_state_offset = (u8 *)state_array->states; for (i = 0; i < state_array->ucNumEntries; i++) { mode_index = 0; - power_state = (union pplib_power_state *)&state_array->states[i]; - /* XXX this might be an inagua bug... */ - non_clock_array_index = i; /* power_state->v2.nonClockInfoIndex */ + power_state = (union pplib_power_state *)power_state_offset; + non_clock_array_index = power_state->v2.nonClockInfoIndex; non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) &non_clock_info_array->nonClockInfo[non_clock_array_index]; rdev->pm.power_state[i].clock_info = kzalloc(sizeof(struct radeon_pm_clock_info) * @@ -2550,9 +2557,6 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) if (power_state->v2.ucNumDPMLevels) { for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { clock_array_index = power_state->v2.clockInfoIndex[j]; - /* XXX this might be an inagua bug... */ - if (clock_array_index >= clock_info_array->ucNumEntries) - continue; clock_info = (union pplib_clock_info *) &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize]; valid = radeon_atombios_parse_pplib_clock_info(rdev, @@ -2574,6 +2578,7 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) non_clock_info); state_index++; } + power_state_offset += 2 + power_state->v2.ucNumDPMLevels; } /* if multiple clock modes, mark the lowest as no display */ for (i = 0; i < state_index; i++) { @@ -2620,7 +2625,9 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) default: break; } - } else { + } + + if (state_index == 0) { rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state), GFP_KERNEL); if (rdev->pm.power_state) { rdev->pm.power_state[0].clock_info = diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 237b7a7549e6..a8f608903989 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1178,6 +1178,11 @@ int radeon_device_init(struct radeon_device *rdev, if (r) DRM_ERROR("ib ring test failed (%d).\n", r); + r = radeon_gem_debugfs_init(rdev); + if (r) { + DRM_ERROR("registering gem debugfs failed (%d).\n", r); + } + if (rdev->flags & RADEON_IS_AGP && !rdev->accel_working) { /* Acceleration not working on AGP card try again * with fallback to PCI or PCIE GART diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index d33f484ace48..094e7e5ea39e 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -147,7 +147,7 @@ static inline void radeon_unregister_atpx_handler(void) {} #endif int radeon_no_wb; -int radeon_modeset = 1; +int radeon_modeset = -1; int radeon_dynclks = -1; int radeon_r4xx_atom = 0; int radeon_agpmode = 0; @@ -456,6 +456,16 @@ static struct pci_driver radeon_kms_pci_driver = { static int __init radeon_init(void) { +#ifdef CONFIG_VGA_CONSOLE + if (vgacon_text_force() && radeon_modeset == -1) { + DRM_INFO("VGACON disable radeon kernel modesetting.\n"); + radeon_modeset = 0; + } +#endif + /* set to modesetting by default if not nomodeset */ + if (radeon_modeset == -1) + radeon_modeset = 1; + if (radeon_modeset == 1) { DRM_INFO("radeon kernel modesetting enabled.\n"); driver = &kms_driver; diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 1a699cefaac7..5b937dfe6f65 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -767,8 +767,8 @@ int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring) radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg); if (rdev->wb.use_event || !radeon_ring_supports_scratch_reg(rdev, &rdev->ring[ring])) { + rdev->fence_drv[ring].scratch_reg = 0; if (ring != R600_RING_TYPE_UVD_INDEX) { - rdev->fence_drv[ring].scratch_reg = 0; index = R600_WB_EVENT_OFFSET + ring * 4; rdev->fence_drv[ring].cpu_addr = &rdev->wb.wb[index/4]; rdev->fence_drv[ring].gpu_addr = rdev->wb.gpu_addr + diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index fe5c1f6b7957..aa796031ab65 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -84,6 +84,7 @@ retry: return r; } *obj = &robj->gem_base; + robj->pid = task_pid_nr(current); mutex_lock(&rdev->gem.mutex); list_add_tail(&robj->list, &rdev->gem.objects); @@ -575,3 +576,52 @@ int radeon_mode_dumb_destroy(struct drm_file *file_priv, { return drm_gem_handle_delete(file_priv, handle); } + +#if defined(CONFIG_DEBUG_FS) +static int radeon_debugfs_gem_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *)m->private; + struct drm_device *dev = node->minor->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_bo *rbo; + unsigned i = 0; + + mutex_lock(&rdev->gem.mutex); + list_for_each_entry(rbo, &rdev->gem.objects, list) { + unsigned domain; + const char *placement; + + domain = radeon_mem_type_to_domain(rbo->tbo.mem.mem_type); + switch (domain) { + case RADEON_GEM_DOMAIN_VRAM: + placement = "VRAM"; + break; + case RADEON_GEM_DOMAIN_GTT: + placement = " GTT"; + break; + case RADEON_GEM_DOMAIN_CPU: + default: + placement = " CPU"; + break; + } + seq_printf(m, "bo[0x%08x] %8ldkB %8ldMB %s pid %8ld\n", + i, radeon_bo_size(rbo) >> 10, radeon_bo_size(rbo) >> 20, + placement, (unsigned long)rbo->pid); + i++; + } + mutex_unlock(&rdev->gem.mutex); + return 0; +} + +static struct drm_info_list radeon_debugfs_gem_list[] = { + {"radeon_gem_info", &radeon_debugfs_gem_info, 0, NULL}, +}; +#endif + +int radeon_gem_debugfs_init(struct radeon_device *rdev) +{ +#if defined(CONFIG_DEBUG_FS) + return radeon_debugfs_add_files(rdev, radeon_debugfs_gem_list, 1); +#endif + return 0; +} diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index cb800995d4f9..0abe5a9431bb 100644 --- a/drivers/gpu/drm/radeon/radeon_sa.c +++ b/drivers/gpu/drm/radeon/radeon_sa.c @@ -64,7 +64,7 @@ int radeon_sa_bo_manager_init(struct radeon_device *rdev, } r = radeon_bo_create(rdev, size, RADEON_GPU_PAGE_SIZE, true, - RADEON_GEM_DOMAIN_CPU, NULL, &sa_manager->bo); + domain, NULL, &sa_manager->bo); if (r) { dev_err(rdev->dev, "(%d) failed to allocate bo for manager\n", r); return r; diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 0312a7f4d768..906e5c0ca3b9 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -692,3 +692,140 @@ void radeon_uvd_note_usage(struct radeon_device *rdev) if (set_clocks) radeon_set_uvd_clocks(rdev, 53300, 40000); } + +static unsigned radeon_uvd_calc_upll_post_div(unsigned vco_freq, + unsigned target_freq, + unsigned pd_min, + unsigned pd_even) +{ + unsigned post_div = vco_freq / target_freq; + + /* adjust to post divider minimum value */ + if (post_div < pd_min) + post_div = pd_min; + + /* we alway need a frequency less than or equal the target */ + if ((vco_freq / post_div) > target_freq) + post_div += 1; + + /* post dividers above a certain value must be even */ + if (post_div > pd_even && post_div % 2) + post_div += 1; + + return post_div; +} + +/** + * radeon_uvd_calc_upll_dividers - calc UPLL clock dividers + * + * @rdev: radeon_device pointer + * @vclk: wanted VCLK + * @dclk: wanted DCLK + * @vco_min: minimum VCO frequency + * @vco_max: maximum VCO frequency + * @fb_factor: factor to multiply vco freq with + * @fb_mask: limit and bitmask for feedback divider + * @pd_min: post divider minimum + * @pd_max: post divider maximum + * @pd_even: post divider must be even above this value + * @optimal_fb_div: resulting feedback divider + * @optimal_vclk_div: resulting vclk post divider + * @optimal_dclk_div: resulting dclk post divider + * + * Calculate dividers for UVDs UPLL (R6xx-SI, except APUs). + * Returns zero on success -EINVAL on error. + */ +int radeon_uvd_calc_upll_dividers(struct radeon_device *rdev, + unsigned vclk, unsigned dclk, + unsigned vco_min, unsigned vco_max, + unsigned fb_factor, unsigned fb_mask, + unsigned pd_min, unsigned pd_max, + unsigned pd_even, + unsigned *optimal_fb_div, + unsigned *optimal_vclk_div, + unsigned *optimal_dclk_div) +{ + unsigned vco_freq, ref_freq = rdev->clock.spll.reference_freq; + + /* start off with something large */ + unsigned optimal_score = ~0; + + /* loop through vco from low to high */ + vco_min = max(max(vco_min, vclk), dclk); + for (vco_freq = vco_min; vco_freq <= vco_max; vco_freq += 100) { + + uint64_t fb_div = (uint64_t)vco_freq * fb_factor; + unsigned vclk_div, dclk_div, score; + + do_div(fb_div, ref_freq); + + /* fb div out of range ? */ + if (fb_div > fb_mask) + break; /* it can oly get worse */ + + fb_div &= fb_mask; + + /* calc vclk divider with current vco freq */ + vclk_div = radeon_uvd_calc_upll_post_div(vco_freq, vclk, + pd_min, pd_even); + if (vclk_div > pd_max) + break; /* vco is too big, it has to stop */ + + /* calc dclk divider with current vco freq */ + dclk_div = radeon_uvd_calc_upll_post_div(vco_freq, dclk, + pd_min, pd_even); + if (vclk_div > pd_max) + break; /* vco is too big, it has to stop */ + + /* calc score with current vco freq */ + score = vclk - (vco_freq / vclk_div) + dclk - (vco_freq / dclk_div); + + /* determine if this vco setting is better than current optimal settings */ + if (score < optimal_score) { + *optimal_fb_div = fb_div; + *optimal_vclk_div = vclk_div; + *optimal_dclk_div = dclk_div; + optimal_score = score; + if (optimal_score == 0) + break; /* it can't get better than this */ + } + } + + /* did we found a valid setup ? */ + if (optimal_score == ~0) + return -EINVAL; + + return 0; +} + +int radeon_uvd_send_upll_ctlreq(struct radeon_device *rdev, + unsigned cg_upll_func_cntl) +{ + unsigned i; + + /* make sure UPLL_CTLREQ is deasserted */ + WREG32_P(cg_upll_func_cntl, 0, ~UPLL_CTLREQ_MASK); + + mdelay(10); + + /* assert UPLL_CTLREQ */ + WREG32_P(cg_upll_func_cntl, UPLL_CTLREQ_MASK, ~UPLL_CTLREQ_MASK); + + /* wait for CTLACK and CTLACK2 to get asserted */ + for (i = 0; i < 100; ++i) { + uint32_t mask = UPLL_CTLACK_MASK | UPLL_CTLACK2_MASK; + if ((RREG32(cg_upll_func_cntl) & mask) == mask) + break; + mdelay(10); + } + + /* deassert UPLL_CTLREQ */ + WREG32_P(cg_upll_func_cntl, 0, ~UPLL_CTLREQ_MASK); + + if (i == 100) { + DRM_ERROR("Timeout setting UVD clocks!\n"); + return -ETIMEDOUT; + } + + return 0; +} diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 91530d4c11c4..83f612a9500b 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -44,56 +44,9 @@ void rv770_fini(struct radeon_device *rdev); static void rv770_pcie_gen2_enable(struct radeon_device *rdev); int evergreen_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk); -static int rv770_uvd_calc_post_div(unsigned target_freq, - unsigned vco_freq, - unsigned *div) -{ - /* Fclk = Fvco / PDIV */ - *div = vco_freq / target_freq; - - /* we alway need a frequency less than or equal the target */ - if ((vco_freq / *div) > target_freq) - *div += 1; - - /* out of range ? */ - if (*div > 30) - return -1; /* forget it */ - - *div -= 1; - return vco_freq / (*div + 1); -} - -static int rv770_uvd_send_upll_ctlreq(struct radeon_device *rdev) -{ - unsigned i; - - /* assert UPLL_CTLREQ */ - WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_CTLREQ_MASK, ~UPLL_CTLREQ_MASK); - - /* wait for CTLACK and CTLACK2 to get asserted */ - for (i = 0; i < 100; ++i) { - uint32_t mask = UPLL_CTLACK_MASK | UPLL_CTLACK2_MASK; - if ((RREG32(CG_UPLL_FUNC_CNTL) & mask) == mask) - break; - mdelay(10); - } - if (i == 100) - return -ETIMEDOUT; - - /* deassert UPLL_CTLREQ */ - WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_CTLREQ_MASK); - - return 0; -} - int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) { - /* start off with something large */ - int optimal_diff_score = 0x7FFFFFF; - unsigned optimal_fb_div = 0, optimal_vclk_div = 0; - unsigned optimal_dclk_div = 0, optimal_vco_freq = 0; - unsigned vco_freq, vco_min = 50000, vco_max = 160000; - unsigned ref_freq = rdev->clock.spll.reference_freq; + unsigned fb_div = 0, vclk_div = 0, dclk_div = 0; int r; /* RV740 uses evergreen uvd clk programming */ @@ -111,44 +64,15 @@ int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) return 0; } - /* loop through vco from low to high */ - vco_min = max(max(vco_min, vclk), dclk); - for (vco_freq = vco_min; vco_freq <= vco_max; vco_freq += 500) { - uint64_t fb_div = (uint64_t)vco_freq * 43663; - int calc_clk, diff_score, diff_vclk, diff_dclk; - unsigned vclk_div, dclk_div; - - do_div(fb_div, ref_freq); - fb_div |= 1; - - /* fb div out of range ? */ - if (fb_div > 0x03FFFFFF) - break; /* it can oly get worse */ - - /* calc vclk with current vco freq. */ - calc_clk = rv770_uvd_calc_post_div(vclk, vco_freq, &vclk_div); - if (calc_clk == -1) - break; /* vco is too big, it has to stop. */ - diff_vclk = vclk - calc_clk; - - /* calc dclk with current vco freq. */ - calc_clk = rv770_uvd_calc_post_div(dclk, vco_freq, &dclk_div); - if (calc_clk == -1) - break; /* vco is too big, it has to stop. */ - diff_dclk = dclk - calc_clk; - - /* determine if this vco setting is better than current optimal settings */ - diff_score = abs(diff_vclk) + abs(diff_dclk); - if (diff_score < optimal_diff_score) { - optimal_fb_div = fb_div; - optimal_vclk_div = vclk_div; - optimal_dclk_div = dclk_div; - optimal_vco_freq = vco_freq; - optimal_diff_score = diff_score; - if (optimal_diff_score == 0) - break; /* it can't get better than this */ - } - } + r = radeon_uvd_calc_upll_dividers(rdev, vclk, dclk, 50000, 160000, + 43663, 0x03FFFFFE, 1, 30, ~0, + &fb_div, &vclk_div, &dclk_div); + if (r) + return r; + + fb_div |= 1; + vclk_div -= 1; + dclk_div -= 1; /* set UPLL_FB_DIV to 0x50000 */ WREG32_P(CG_UPLL_FUNC_CNTL_3, UPLL_FB_DIV(0x50000), ~UPLL_FB_DIV_MASK); @@ -160,7 +84,7 @@ int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_BYPASS_EN_MASK, ~UPLL_BYPASS_EN_MASK); WREG32_P(CG_UPLL_FUNC_CNTL_3, UPLL_FB_DIV(1), ~UPLL_FB_DIV(1)); - r = rv770_uvd_send_upll_ctlreq(rdev); + r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL); if (r) return r; @@ -170,13 +94,13 @@ int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) /* set the required FB_DIV, REF_DIV, Post divder values */ WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_REF_DIV(1), ~UPLL_REF_DIV_MASK); WREG32_P(CG_UPLL_FUNC_CNTL_2, - UPLL_SW_HILEN(optimal_vclk_div >> 1) | - UPLL_SW_LOLEN((optimal_vclk_div >> 1) + (optimal_vclk_div & 1)) | - UPLL_SW_HILEN2(optimal_dclk_div >> 1) | - UPLL_SW_LOLEN2((optimal_dclk_div >> 1) + (optimal_dclk_div & 1)), + UPLL_SW_HILEN(vclk_div >> 1) | + UPLL_SW_LOLEN((vclk_div >> 1) + (vclk_div & 1)) | + UPLL_SW_HILEN2(dclk_div >> 1) | + UPLL_SW_LOLEN2((dclk_div >> 1) + (dclk_div & 1)), ~UPLL_SW_MASK); - WREG32_P(CG_UPLL_FUNC_CNTL_3, UPLL_FB_DIV(optimal_fb_div), + WREG32_P(CG_UPLL_FUNC_CNTL_3, UPLL_FB_DIV(fb_div), ~UPLL_FB_DIV_MASK); /* give the PLL some time to settle */ @@ -191,7 +115,7 @@ int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_BYPASS_EN_MASK); WREG32_P(CG_UPLL_FUNC_CNTL_3, 0, ~UPLL_FB_DIV(1)); - r = rv770_uvd_send_upll_ctlreq(rdev); + r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL); if (r) return r; diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index 6a52b2054f32..85b16266f748 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h @@ -45,7 +45,7 @@ # define UPLL_BYPASS_EN_MASK 0x00000004 # define UPLL_CTLREQ_MASK 0x00000008 # define UPLL_REF_DIV(x) ((x) << 16) -# define UPLL_REF_DIV_MASK 0x001F0000 +# define UPLL_REF_DIV_MASK 0x003F0000 # define UPLL_CTLACK_MASK 0x40000000 # define UPLL_CTLACK2_MASK 0x80000000 #define CG_UPLL_FUNC_CNTL_2 0x71c diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index fe6b14e0021c..f0b6c2f87c4d 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -5415,62 +5415,9 @@ uint64_t si_get_gpu_clock_counter(struct radeon_device *rdev) return clock; } -static int si_uvd_calc_post_div(unsigned target_freq, - unsigned vco_freq, - unsigned *div) -{ - /* target larger than vco frequency ? */ - if (vco_freq < target_freq) - return -1; /* forget it */ - - /* Fclk = Fvco / PDIV */ - *div = vco_freq / target_freq; - - /* we alway need a frequency less than or equal the target */ - if ((vco_freq / *div) > target_freq) - *div += 1; - - /* dividers above 5 must be even */ - if (*div > 5 && *div % 2) - *div += 1; - - /* out of range ? */ - if (*div >= 128) - return -1; /* forget it */ - - return vco_freq / *div; -} - -static int si_uvd_send_upll_ctlreq(struct radeon_device *rdev) -{ - unsigned i; - - /* assert UPLL_CTLREQ */ - WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_CTLREQ_MASK, ~UPLL_CTLREQ_MASK); - - /* wait for CTLACK and CTLACK2 to get asserted */ - for (i = 0; i < 100; ++i) { - uint32_t mask = UPLL_CTLACK_MASK | UPLL_CTLACK2_MASK; - if ((RREG32(CG_UPLL_FUNC_CNTL) & mask) == mask) - break; - mdelay(10); - } - if (i == 100) - return -ETIMEDOUT; - - /* deassert UPLL_CTLREQ */ - WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_CTLREQ_MASK); - - return 0; -} - int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) { - /* start off with something large */ - int optimal_diff_score = 0x7FFFFFF; - unsigned optimal_fb_div = 0, optimal_vclk_div = 0; - unsigned optimal_dclk_div = 0, optimal_vco_freq = 0; - unsigned vco_freq; + unsigned fb_div = 0, vclk_div = 0, dclk_div = 0; int r; /* bypass vclk and dclk with bclk */ @@ -5487,40 +5434,11 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) return 0; } - /* loop through vco from low to high */ - for (vco_freq = 125000; vco_freq <= 250000; vco_freq += 100) { - unsigned fb_div = vco_freq / rdev->clock.spll.reference_freq * 16384; - int calc_clk, diff_score, diff_vclk, diff_dclk; - unsigned vclk_div, dclk_div; - - /* fb div out of range ? */ - if (fb_div > 0x03FFFFFF) - break; /* it can oly get worse */ - - /* calc vclk with current vco freq. */ - calc_clk = si_uvd_calc_post_div(vclk, vco_freq, &vclk_div); - if (calc_clk == -1) - break; /* vco is too big, it has to stop. */ - diff_vclk = vclk - calc_clk; - - /* calc dclk with current vco freq. */ - calc_clk = si_uvd_calc_post_div(dclk, vco_freq, &dclk_div); - if (calc_clk == -1) - break; /* vco is too big, it has to stop. */ - diff_dclk = dclk - calc_clk; - - /* determine if this vco setting is better than current optimal settings */ - diff_score = abs(diff_vclk) + abs(diff_dclk); - if (diff_score < optimal_diff_score) { - optimal_fb_div = fb_div; - optimal_vclk_div = vclk_div; - optimal_dclk_div = dclk_div; - optimal_vco_freq = vco_freq; - optimal_diff_score = diff_score; - if (optimal_diff_score == 0) - break; /* it can't get better than this */ - } - } + r = radeon_uvd_calc_upll_dividers(rdev, vclk, dclk, 125000, 250000, + 16384, 0x03FFFFFF, 0, 128, 5, + &fb_div, &vclk_div, &dclk_div); + if (r) + return r; /* set RESET_ANTI_MUX to 0 */ WREG32_P(CG_UPLL_FUNC_CNTL_5, 0, ~RESET_ANTI_MUX_MASK); @@ -5537,7 +5455,7 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) mdelay(1); - r = si_uvd_send_upll_ctlreq(rdev); + r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL); if (r) return r; @@ -5548,19 +5466,19 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) WREG32_P(CG_UPLL_SPREAD_SPECTRUM, 0, ~SSEN_MASK); /* set feedback divider */ - WREG32_P(CG_UPLL_FUNC_CNTL_3, UPLL_FB_DIV(optimal_fb_div), ~UPLL_FB_DIV_MASK); + WREG32_P(CG_UPLL_FUNC_CNTL_3, UPLL_FB_DIV(fb_div), ~UPLL_FB_DIV_MASK); /* set ref divider to 0 */ WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_REF_DIV_MASK); - if (optimal_vco_freq < 187500) + if (fb_div < 307200) WREG32_P(CG_UPLL_FUNC_CNTL_4, 0, ~UPLL_SPARE_ISPARE9); else WREG32_P(CG_UPLL_FUNC_CNTL_4, UPLL_SPARE_ISPARE9, ~UPLL_SPARE_ISPARE9); /* set PDIV_A and PDIV_B */ WREG32_P(CG_UPLL_FUNC_CNTL_2, - UPLL_PDIV_A(optimal_vclk_div) | UPLL_PDIV_B(optimal_dclk_div), + UPLL_PDIV_A(vclk_div) | UPLL_PDIV_B(dclk_div), ~(UPLL_PDIV_A_MASK | UPLL_PDIV_B_MASK)); /* give the PLL some time to settle */ @@ -5574,7 +5492,7 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) /* switch from bypass mode to normal mode */ WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_BYPASS_EN_MASK); - r = si_uvd_send_upll_ctlreq(rdev); + r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL); if (r) return r; diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index 042b91d6c941..222877ba6cf5 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h @@ -36,7 +36,7 @@ # define UPLL_BYPASS_EN_MASK 0x00000004 # define UPLL_CTLREQ_MASK 0x00000008 # define UPLL_VCO_MODE_MASK 0x00000600 -# define UPLL_REF_DIV_MASK 0x001F0000 +# define UPLL_REF_DIV_MASK 0x003F0000 # define UPLL_CTLACK_MASK 0x40000000 # define UPLL_CTLACK2_MASK 0x80000000 #define CG_UPLL_FUNC_CNTL_2 0x638 diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index 9f4be3d4a02e..dc0c065f8d39 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -482,7 +482,7 @@ static int udlfb_create(struct drm_fb_helper *helper, struct udl_fbdev *ufbdev = (struct udl_fbdev *)helper; struct drm_device *dev = ufbdev->helper.dev; struct fb_info *info; - struct device *device = &dev->usbdev->dev; + struct device *device = dev->dev; struct drm_framebuffer *fb; struct drm_mode_fb_cmd2 mode_cmd; struct udl_gem_object *obj; diff --git a/drivers/gpu/drm/udl/udl_gem.c b/drivers/gpu/drm/udl/udl_gem.c index 3816270ba49b..ef034fa3e6f5 100644 --- a/drivers/gpu/drm/udl/udl_gem.c +++ b/drivers/gpu/drm/udl/udl_gem.c @@ -303,6 +303,8 @@ struct drm_gem_object *udl_gem_prime_import(struct drm_device *dev, if (IS_ERR(attach)) return ERR_CAST(attach); + get_dma_buf(dma_buf); + sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); if (IS_ERR(sg)) { ret = PTR_ERR(sg); @@ -322,5 +324,7 @@ fail_unmap: dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL); fail_detach: dma_buf_detach(dma_buf, attach); + dma_buf_put(dma_buf); + return ERR_PTR(ret); } diff --git a/drivers/video/omap2/Makefile b/drivers/video/omap2/Makefile index 5ea7cb9aed17..296e5c5281c5 100644 --- a/drivers/video/omap2/Makefile +++ b/drivers/video/omap2/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_OMAP2_VRFB) += vrfb.o obj-$(CONFIG_OMAP2_DSS) += dss/ -obj-$(CONFIG_FB_OMAP2) += omapfb/ obj-y += displays/ +obj-$(CONFIG_FB_OMAP2) += omapfb/ diff --git a/drivers/video/omap2/displays/panel-tfp410.c b/drivers/video/omap2/displays/panel-tfp410.c index a1dba868cef1..46039c4bf1ed 100644 --- a/drivers/video/omap2/displays/panel-tfp410.c +++ b/drivers/video/omap2/displays/panel-tfp410.c @@ -135,7 +135,7 @@ static int tfp410_probe(struct omap_dss_device *dssdev) if (!adapter) { dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n", i2c_bus_num); - return -EINVAL; + return -EPROBE_DEFER; } ddata->i2c_adapter = adapter; diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index e93c4debea7f..757b57f7275a 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -520,7 +520,7 @@ void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) } EXPORT_SYMBOL(omapdss_dpi_set_data_lines); -static int __init dpi_verify_dsi_pll(struct platform_device *dsidev) +static int dpi_verify_dsi_pll(struct platform_device *dsidev) { int r; @@ -572,7 +572,7 @@ static enum omap_channel dpi_get_channel(void) } } -static int __init dpi_init_display(struct omap_dss_device *dssdev) +static int dpi_init_display(struct omap_dss_device *dssdev) { struct platform_device *dsidev; @@ -607,7 +607,7 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev) return 0; } -static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *pdev) +static struct omap_dss_device *dpi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; const char *def_disp_name = omapdss_get_default_display_name(); @@ -635,7 +635,7 @@ static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *p return def_dssdev; } -static void __init dpi_probe_pdata(struct platform_device *dpidev) +static int dpi_probe_pdata(struct platform_device *dpidev) { struct omap_dss_device *plat_dssdev; struct omap_dss_device *dssdev; @@ -644,11 +644,11 @@ static void __init dpi_probe_pdata(struct platform_device *dpidev) plat_dssdev = dpi_find_dssdev(dpidev); if (!plat_dssdev) - return; + return 0; dssdev = dss_alloc_and_init_device(&dpidev->dev); if (!dssdev) - return; + return -ENOMEM; dss_copy_device_pdata(dssdev, plat_dssdev); @@ -656,7 +656,7 @@ static void __init dpi_probe_pdata(struct platform_device *dpidev) if (r) { DSSERR("device %s init failed: %d\n", dssdev->name, r); dss_put_device(dssdev); - return; + return r; } r = omapdss_output_set_device(&dpi.output, dssdev); @@ -664,7 +664,7 @@ static void __init dpi_probe_pdata(struct platform_device *dpidev) DSSERR("failed to connect output to new device: %s\n", dssdev->name); dss_put_device(dssdev); - return; + return r; } r = dss_add_device(dssdev); @@ -672,11 +672,13 @@ static void __init dpi_probe_pdata(struct platform_device *dpidev) DSSERR("device %s register failed: %d\n", dssdev->name, r); omapdss_output_unset_device(&dpi.output); dss_put_device(dssdev); - return; + return r; } + + return 0; } -static void __init dpi_init_output(struct platform_device *pdev) +static void dpi_init_output(struct platform_device *pdev) { struct omap_dss_output *out = &dpi.output; @@ -696,13 +698,19 @@ static void __exit dpi_uninit_output(struct platform_device *pdev) dss_unregister_output(out); } -static int __init omap_dpi_probe(struct platform_device *pdev) +static int omap_dpi_probe(struct platform_device *pdev) { + int r; + mutex_init(&dpi.lock); dpi_init_output(pdev); - dpi_probe_pdata(pdev); + r = dpi_probe_pdata(pdev); + if (r) { + dpi_uninit_output(pdev); + return r; + } return 0; } @@ -717,6 +725,7 @@ static int __exit omap_dpi_remove(struct platform_device *pdev) } static struct platform_driver omap_dpi_driver = { + .probe = omap_dpi_probe, .remove = __exit_p(omap_dpi_remove), .driver = { .name = "omapdss_dpi", @@ -726,7 +735,7 @@ static struct platform_driver omap_dpi_driver = { int __init dpi_init_platform_driver(void) { - return platform_driver_probe(&omap_dpi_driver, omap_dpi_probe); + return platform_driver_register(&omap_dpi_driver); } void __exit dpi_uninit_platform_driver(void) diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 9b1c5ecee115..a73dedc33101 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -5225,7 +5225,7 @@ static enum omap_channel dsi_get_channel(int module_id) } } -static int __init dsi_init_display(struct omap_dss_device *dssdev) +static int dsi_init_display(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_id(dssdev->phy.dsi.module); @@ -5366,7 +5366,7 @@ static int dsi_get_clocks(struct platform_device *dsidev) return 0; } -static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *pdev) +static struct omap_dss_device *dsi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); @@ -5398,7 +5398,7 @@ static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *p return def_dssdev; } -static void __init dsi_probe_pdata(struct platform_device *dsidev) +static int dsi_probe_pdata(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct omap_dss_device *plat_dssdev; @@ -5408,11 +5408,11 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev) plat_dssdev = dsi_find_dssdev(dsidev); if (!plat_dssdev) - return; + return 0; dssdev = dss_alloc_and_init_device(&dsidev->dev); if (!dssdev) - return; + return -ENOMEM; dss_copy_device_pdata(dssdev, plat_dssdev); @@ -5420,7 +5420,7 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev) if (r) { DSSERR("device %s init failed: %d\n", dssdev->name, r); dss_put_device(dssdev); - return; + return r; } r = omapdss_output_set_device(&dsi->output, dssdev); @@ -5428,7 +5428,7 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev) DSSERR("failed to connect output to new device: %s\n", dssdev->name); dss_put_device(dssdev); - return; + return r; } r = dss_add_device(dssdev); @@ -5436,11 +5436,13 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev) DSSERR("device %s register failed: %d\n", dssdev->name, r); omapdss_output_unset_device(&dsi->output); dss_put_device(dssdev); - return; + return r; } + + return 0; } -static void __init dsi_init_output(struct platform_device *dsidev) +static void dsi_init_output(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct omap_dss_output *out = &dsi->output; @@ -5456,7 +5458,7 @@ static void __init dsi_init_output(struct platform_device *dsidev) dss_register_output(out); } -static void __exit dsi_uninit_output(struct platform_device *dsidev) +static void dsi_uninit_output(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct omap_dss_output *out = &dsi->output; @@ -5465,7 +5467,7 @@ static void __exit dsi_uninit_output(struct platform_device *dsidev) } /* DSI1 HW IP initialisation */ -static int __init omap_dsihw_probe(struct platform_device *dsidev) +static int omap_dsihw_probe(struct platform_device *dsidev) { u32 rev; int r, i; @@ -5561,7 +5563,13 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev) dsi_init_output(dsidev); - dsi_probe_pdata(dsidev); + r = dsi_probe_pdata(dsidev); + if (r) { + dsi_runtime_put(dsidev); + dsi_uninit_output(dsidev); + pm_runtime_disable(&dsidev->dev); + return r; + } dsi_runtime_put(dsidev); @@ -5632,6 +5640,7 @@ static const struct dev_pm_ops dsi_pm_ops = { }; static struct platform_driver omap_dsihw_driver = { + .probe = omap_dsihw_probe, .remove = __exit_p(omap_dsihw_remove), .driver = { .name = "omapdss_dsi", @@ -5642,7 +5651,7 @@ static struct platform_driver omap_dsihw_driver = { int __init dsi_init_platform_driver(void) { - return platform_driver_probe(&omap_dsihw_driver, omap_dsihw_probe); + return platform_driver_register(&omap_dsihw_driver); } void __exit dsi_uninit_platform_driver(void) diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index faaf35857b0e..84758936429d 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -277,6 +277,12 @@ int sdi_init_platform_driver(void) __init; void sdi_uninit_platform_driver(void) __exit; /* DSI */ + +typedef bool (*dsi_pll_calc_func)(int regn, int regm, unsigned long fint, + unsigned long pll, void *data); +typedef bool (*dsi_hsdiv_calc_func)(int regm_dispc, unsigned long dispc, + void *data); + #ifdef CONFIG_OMAP2_DSS_DSI struct dentry; @@ -295,10 +301,6 @@ u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt); unsigned long dsi_get_pll_clkin(struct platform_device *dsidev); -typedef bool (*dsi_pll_calc_func)(int regn, int regm, unsigned long fint, - unsigned long pll, void *data); -typedef bool (*dsi_hsdiv_calc_func)(int regm_dispc, unsigned long dispc, - void *data); bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll, unsigned long out_min, dsi_hsdiv_calc_func func, void *data); bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin, @@ -358,6 +360,27 @@ static inline struct platform_device *dsi_get_dsidev_from_id(int module) { return NULL; } + +static inline unsigned long dsi_get_pll_clkin(struct platform_device *dsidev) +{ + return 0; +} + +static inline bool dsi_hsdiv_calc(struct platform_device *dsidev, + unsigned long pll, unsigned long out_min, + dsi_hsdiv_calc_func func, void *data) +{ + return false; +} + +static inline bool dsi_pll_calc(struct platform_device *dsidev, + unsigned long clkin, + unsigned long pll_min, unsigned long pll_max, + dsi_pll_calc_func func, void *data) +{ + return false; +} + #endif /* DPI */ diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 79393099d505..17f4d55c621c 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -328,7 +328,7 @@ static void hdmi_runtime_put(void) WARN_ON(r < 0 && r != -ENOSYS); } -static int __init hdmi_init_display(struct omap_dss_device *dssdev) +static int hdmi_init_display(struct omap_dss_device *dssdev) { int r; @@ -954,7 +954,7 @@ int hdmi_audio_config(struct omap_dss_audio *audio) #endif -static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev) +static struct omap_dss_device *hdmi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; const char *def_disp_name = omapdss_get_default_display_name(); @@ -982,7 +982,7 @@ static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device * return def_dssdev; } -static void __init hdmi_probe_pdata(struct platform_device *pdev) +static int hdmi_probe_pdata(struct platform_device *pdev) { struct omap_dss_device *plat_dssdev; struct omap_dss_device *dssdev; @@ -992,11 +992,11 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev) plat_dssdev = hdmi_find_dssdev(pdev); if (!plat_dssdev) - return; + return 0; dssdev = dss_alloc_and_init_device(&pdev->dev); if (!dssdev) - return; + return -ENOMEM; dss_copy_device_pdata(dssdev, plat_dssdev); @@ -1010,7 +1010,7 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev) if (r) { DSSERR("device %s init failed: %d\n", dssdev->name, r); dss_put_device(dssdev); - return; + return r; } r = omapdss_output_set_device(&hdmi.output, dssdev); @@ -1018,7 +1018,7 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev) DSSERR("failed to connect output to new device: %s\n", dssdev->name); dss_put_device(dssdev); - return; + return r; } r = dss_add_device(dssdev); @@ -1027,11 +1027,13 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev) omapdss_output_unset_device(&hdmi.output); hdmi_uninit_display(dssdev); dss_put_device(dssdev); - return; + return r; } + + return 0; } -static void __init hdmi_init_output(struct platform_device *pdev) +static void hdmi_init_output(struct platform_device *pdev) { struct omap_dss_output *out = &hdmi.output; @@ -1052,7 +1054,7 @@ static void __exit hdmi_uninit_output(struct platform_device *pdev) } /* HDMI HW IP initialisation */ -static int __init omapdss_hdmihw_probe(struct platform_device *pdev) +static int omapdss_hdmihw_probe(struct platform_device *pdev) { struct resource *res; int r; @@ -1096,7 +1098,13 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) dss_debugfs_create_file("hdmi", hdmi_dump_regs); - hdmi_probe_pdata(pdev); + r = hdmi_probe_pdata(pdev); + if (r) { + hdmi_panel_exit(); + hdmi_uninit_output(pdev); + pm_runtime_disable(&pdev->dev); + return r; + } return 0; } @@ -1151,6 +1159,7 @@ static const struct dev_pm_ops hdmi_pm_ops = { }; static struct platform_driver omapdss_hdmihw_driver = { + .probe = omapdss_hdmihw_probe, .remove = __exit_p(omapdss_hdmihw_remove), .driver = { .name = "omapdss_hdmi", @@ -1161,7 +1170,7 @@ static struct platform_driver omapdss_hdmihw_driver = { int __init hdmi_init_platform_driver(void) { - return platform_driver_probe(&omapdss_hdmihw_driver, omapdss_hdmihw_probe); + return platform_driver_register(&omapdss_hdmihw_driver); } void __exit hdmi_uninit_platform_driver(void) diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 1a691bb27547..1a17dd1447dc 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -943,13 +943,13 @@ void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev) } EXPORT_SYMBOL(omapdss_rfbi_display_disable); -static int __init rfbi_init_display(struct omap_dss_device *dssdev) +static int rfbi_init_display(struct omap_dss_device *dssdev) { rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev; return 0; } -static struct omap_dss_device * __init rfbi_find_dssdev(struct platform_device *pdev) +static struct omap_dss_device *rfbi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; const char *def_disp_name = omapdss_get_default_display_name(); @@ -977,7 +977,7 @@ static struct omap_dss_device * __init rfbi_find_dssdev(struct platform_device * return def_dssdev; } -static void __init rfbi_probe_pdata(struct platform_device *rfbidev) +static int rfbi_probe_pdata(struct platform_device *rfbidev) { struct omap_dss_device *plat_dssdev; struct omap_dss_device *dssdev; @@ -986,11 +986,11 @@ static void __init rfbi_probe_pdata(struct platform_device *rfbidev) plat_dssdev = rfbi_find_dssdev(rfbidev); if (!plat_dssdev) - return; + return 0; dssdev = dss_alloc_and_init_device(&rfbidev->dev); if (!dssdev) - return; + return -ENOMEM; dss_copy_device_pdata(dssdev, plat_dssdev); @@ -998,7 +998,7 @@ static void __init rfbi_probe_pdata(struct platform_device *rfbidev) if (r) { DSSERR("device %s init failed: %d\n", dssdev->name, r); dss_put_device(dssdev); - return; + return r; } r = omapdss_output_set_device(&rfbi.output, dssdev); @@ -1006,7 +1006,7 @@ static void __init rfbi_probe_pdata(struct platform_device *rfbidev) DSSERR("failed to connect output to new device: %s\n", dssdev->name); dss_put_device(dssdev); - return; + return r; } r = dss_add_device(dssdev); @@ -1014,11 +1014,13 @@ static void __init rfbi_probe_pdata(struct platform_device *rfbidev) DSSERR("device %s register failed: %d\n", dssdev->name, r); omapdss_output_unset_device(&rfbi.output); dss_put_device(dssdev); - return; + return r; } + + return 0; } -static void __init rfbi_init_output(struct platform_device *pdev) +static void rfbi_init_output(struct platform_device *pdev) { struct omap_dss_output *out = &rfbi.output; @@ -1039,7 +1041,7 @@ static void __exit rfbi_uninit_output(struct platform_device *pdev) } /* RFBI HW IP initialisation */ -static int __init omap_rfbihw_probe(struct platform_device *pdev) +static int omap_rfbihw_probe(struct platform_device *pdev) { u32 rev; struct resource *rfbi_mem; @@ -1091,7 +1093,12 @@ static int __init omap_rfbihw_probe(struct platform_device *pdev) rfbi_init_output(pdev); - rfbi_probe_pdata(pdev); + r = rfbi_probe_pdata(pdev); + if (r) { + rfbi_uninit_output(pdev); + pm_runtime_disable(&pdev->dev); + return r; + } return 0; @@ -1135,6 +1142,7 @@ static const struct dev_pm_ops rfbi_pm_ops = { }; static struct platform_driver omap_rfbihw_driver = { + .probe = omap_rfbihw_probe, .remove = __exit_p(omap_rfbihw_remove), .driver = { .name = "omapdss_rfbi", @@ -1145,7 +1153,7 @@ static struct platform_driver omap_rfbihw_driver = { int __init rfbi_init_platform_driver(void) { - return platform_driver_probe(&omap_rfbihw_driver, omap_rfbihw_probe); + return platform_driver_register(&omap_rfbihw_driver); } void __exit rfbi_uninit_platform_driver(void) diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index e6baee2e84f8..0bcd30272f69 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -248,7 +248,7 @@ void omapdss_sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs) } EXPORT_SYMBOL(omapdss_sdi_set_datapairs); -static int __init sdi_init_display(struct omap_dss_device *dssdev) +static int sdi_init_display(struct omap_dss_device *dssdev) { DSSDBG("SDI init\n"); @@ -268,7 +268,7 @@ static int __init sdi_init_display(struct omap_dss_device *dssdev) return 0; } -static struct omap_dss_device * __init sdi_find_dssdev(struct platform_device *pdev) +static struct omap_dss_device *sdi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; const char *def_disp_name = omapdss_get_default_display_name(); @@ -296,7 +296,7 @@ static struct omap_dss_device * __init sdi_find_dssdev(struct platform_device *p return def_dssdev; } -static void __init sdi_probe_pdata(struct platform_device *sdidev) +static int sdi_probe_pdata(struct platform_device *sdidev) { struct omap_dss_device *plat_dssdev; struct omap_dss_device *dssdev; @@ -305,11 +305,11 @@ static void __init sdi_probe_pdata(struct platform_device *sdidev) plat_dssdev = sdi_find_dssdev(sdidev); if (!plat_dssdev) - return; + return 0; dssdev = dss_alloc_and_init_device(&sdidev->dev); if (!dssdev) - return; + return -ENOMEM; dss_copy_device_pdata(dssdev, plat_dssdev); @@ -317,7 +317,7 @@ static void __init sdi_probe_pdata(struct platform_device *sdidev) if (r) { DSSERR("device %s init failed: %d\n", dssdev->name, r); dss_put_device(dssdev); - return; + return r; } r = omapdss_output_set_device(&sdi.output, dssdev); @@ -325,7 +325,7 @@ static void __init sdi_probe_pdata(struct platform_device *sdidev) DSSERR("failed to connect output to new device: %s\n", dssdev->name); dss_put_device(dssdev); - return; + return r; } r = dss_add_device(dssdev); @@ -333,11 +333,13 @@ static void __init sdi_probe_pdata(struct platform_device *sdidev) DSSERR("device %s register failed: %d\n", dssdev->name, r); omapdss_output_unset_device(&sdi.output); dss_put_device(dssdev); - return; + return r; } + + return 0; } -static void __init sdi_init_output(struct platform_device *pdev) +static void sdi_init_output(struct platform_device *pdev) { struct omap_dss_output *out = &sdi.output; @@ -357,11 +359,17 @@ static void __exit sdi_uninit_output(struct platform_device *pdev) dss_unregister_output(out); } -static int __init omap_sdi_probe(struct platform_device *pdev) +static int omap_sdi_probe(struct platform_device *pdev) { + int r; + sdi_init_output(pdev); - sdi_probe_pdata(pdev); + r = sdi_probe_pdata(pdev); + if (r) { + sdi_uninit_output(pdev); + return r; + } return 0; } @@ -376,6 +384,7 @@ static int __exit omap_sdi_remove(struct platform_device *pdev) } static struct platform_driver omap_sdi_driver = { + .probe = omap_sdi_probe, .remove = __exit_p(omap_sdi_remove), .driver = { .name = "omapdss_sdi", @@ -385,7 +394,7 @@ static struct platform_driver omap_sdi_driver = { int __init sdi_init_platform_driver(void) { - return platform_driver_probe(&omap_sdi_driver, omap_sdi_probe); + return platform_driver_register(&omap_sdi_driver); } void __exit sdi_uninit_platform_driver(void) diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 17764d136398..74fdb3ee209e 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -633,7 +633,7 @@ void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev, mutex_unlock(&venc.venc_lock); } -static int __init venc_init_display(struct omap_dss_device *dssdev) +static int venc_init_display(struct omap_dss_device *dssdev) { DSSDBG("init_display\n"); @@ -726,7 +726,7 @@ static int venc_get_clocks(struct platform_device *pdev) return 0; } -static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev) +static struct omap_dss_device *venc_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; const char *def_disp_name = omapdss_get_default_display_name(); @@ -754,7 +754,7 @@ static struct omap_dss_device * __init venc_find_dssdev(struct platform_device * return def_dssdev; } -static void __init venc_probe_pdata(struct platform_device *vencdev) +static int venc_probe_pdata(struct platform_device *vencdev) { struct omap_dss_device *plat_dssdev; struct omap_dss_device *dssdev; @@ -763,11 +763,11 @@ static void __init venc_probe_pdata(struct platform_device *vencdev) plat_dssdev = venc_find_dssdev(vencdev); if (!plat_dssdev) - return; + return 0; dssdev = dss_alloc_and_init_device(&vencdev->dev); if (!dssdev) - return; + return -ENOMEM; dss_copy_device_pdata(dssdev, plat_dssdev); @@ -775,7 +775,7 @@ static void __init venc_probe_pdata(struct platform_device *vencdev) if (r) { DSSERR("device %s init failed: %d\n", dssdev->name, r); dss_put_device(dssdev); - return; + return r; } r = omapdss_output_set_device(&venc.output, dssdev); @@ -783,7 +783,7 @@ static void __init venc_probe_pdata(struct platform_device *vencdev) DSSERR("failed to connect output to new device: %s\n", dssdev->name); dss_put_device(dssdev); - return; + return r; } r = dss_add_device(dssdev); @@ -791,11 +791,13 @@ static void __init venc_probe_pdata(struct platform_device *vencdev) DSSERR("device %s register failed: %d\n", dssdev->name, r); omapdss_output_unset_device(&venc.output); dss_put_device(dssdev); - return; + return r; } + + return 0; } -static void __init venc_init_output(struct platform_device *pdev) +static void venc_init_output(struct platform_device *pdev) { struct omap_dss_output *out = &venc.output; @@ -816,7 +818,7 @@ static void __exit venc_uninit_output(struct platform_device *pdev) } /* VENC HW IP initialisation */ -static int __init omap_venchw_probe(struct platform_device *pdev) +static int omap_venchw_probe(struct platform_device *pdev) { u8 rev_id; struct resource *venc_mem; @@ -864,7 +866,13 @@ static int __init omap_venchw_probe(struct platform_device *pdev) venc_init_output(pdev); - venc_probe_pdata(pdev); + r = venc_probe_pdata(pdev); + if (r) { + venc_panel_exit(); + venc_uninit_output(pdev); + pm_runtime_disable(&pdev->dev); + return r; + } return 0; @@ -922,6 +930,7 @@ static const struct dev_pm_ops venc_pm_ops = { }; static struct platform_driver omap_venchw_driver = { + .probe = omap_venchw_probe, .remove = __exit_p(omap_venchw_remove), .driver = { .name = "omapdss_venc", @@ -932,7 +941,7 @@ static struct platform_driver omap_venchw_driver = { int __init venc_init_platform_driver(void) { - return platform_driver_probe(&omap_venchw_driver, omap_venchw_probe); + return platform_driver_register(&omap_venchw_driver); } void __exit venc_uninit_platform_driver(void) diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index f38348ea3375..ff00d1d8bd26 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -2422,7 +2422,7 @@ static int omapfb_init_connections(struct omapfb2_device *fbdev, return 0; } -static int __init omapfb_probe(struct platform_device *pdev) +static int omapfb_probe(struct platform_device *pdev) { struct omapfb2_device *fbdev = NULL; int r = 0; @@ -2484,7 +2484,7 @@ static int __init omapfb_probe(struct platform_device *pdev) if (fbdev->num_displays == 0) { dev_err(&pdev->dev, "no displays\n"); - r = -EINVAL; + r = -EPROBE_DEFER; goto cleanup; } @@ -2595,6 +2595,7 @@ static int __exit omapfb_remove(struct platform_device *pdev) } static struct platform_driver omapfb_driver = { + .probe = omapfb_probe, .remove = __exit_p(omapfb_remove), .driver = { .name = "omapfb", @@ -2602,36 +2603,13 @@ static struct platform_driver omapfb_driver = { }, }; -static int __init omapfb_init(void) -{ - DBG("omapfb_init\n"); - - if (platform_driver_probe(&omapfb_driver, omapfb_probe)) { - printk(KERN_ERR "failed to register omapfb driver\n"); - return -ENODEV; - } - - return 0; -} - -static void __exit omapfb_exit(void) -{ - DBG("omapfb_exit\n"); - platform_driver_unregister(&omapfb_driver); -} - module_param_named(mode, def_mode, charp, 0); module_param_named(vram, def_vram, charp, 0); module_param_named(rotate, def_rotate, int, 0); module_param_named(vrfb, def_vrfb, bool, 0); module_param_named(mirror, def_mirror, bool, 0); -/* late_initcall to let panel/ctrl drivers loaded first. - * I guess better option would be a more dynamic approach, - * so that omapfb reacts to new panels when they are loaded */ -late_initcall(omapfb_init); -/*module_init(omapfb_init);*/ -module_exit(omapfb_exit); +module_platform_driver(omapfb_driver); MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>"); MODULE_DESCRIPTION("OMAP2/3 Framebuffer"); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 2d94d7413d71..b092b5bcf227 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -316,6 +316,7 @@ struct drm_ioctl_desc { int flags; drm_ioctl_t *func; unsigned int cmd_drv; + const char *name; }; /** @@ -324,7 +325,7 @@ struct drm_ioctl_desc { */ #define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags) \ - [DRM_IOCTL_NR(DRM_##ioctl)] = {.cmd = DRM_##ioctl, .func = _func, .flags = _flags, .cmd_drv = DRM_IOCTL_##ioctl} + [DRM_IOCTL_NR(DRM_##ioctl)] = {.cmd = DRM_##ioctl, .func = _func, .flags = _flags, .cmd_drv = DRM_IOCTL_##ioctl, .name = #ioctl} struct drm_magic_entry { struct list_head head; @@ -1593,9 +1594,8 @@ extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *s void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv); void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv); -int drm_prime_add_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle); -int drm_prime_lookup_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle); -void drm_prime_remove_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf); +int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle); +void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf); int drm_prime_add_dma_buf(struct drm_device *dev, struct drm_gem_object *obj); int drm_prime_lookup_obj(struct drm_device *dev, struct dma_buf *buf, diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 8c7846bd74f4..adb3f9b625f6 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -120,7 +120,7 @@ enum drm_mode_status { .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, \ + .vscan = (vs), .flags = (f), \ .base.type = DRM_MODE_OBJECT_MODE #define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */ @@ -554,7 +554,6 @@ enum drm_connector_force { * @probed_modes: list of modes derived directly from the display * @display_info: information about attached display (e.g. from EDID) * @funcs: connector control functions - * @user_modes: user added mode list * @edid_blob_ptr: DRM property containing EDID if present * @properties: property tracking for this connector * @polled: a %DRM_CONNECTOR_POLL_<foo> value for core driven polling @@ -598,7 +597,6 @@ struct drm_connector { struct drm_display_info display_info; const struct drm_connector_funcs *funcs; - struct list_head user_modes; struct drm_property_blob *edid_blob_ptr; struct drm_object_properties properties; @@ -922,15 +920,11 @@ extern void drm_mode_config_reset(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(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2); +extern bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2); extern int drm_mode_width(const struct drm_display_mode *mode); extern int drm_mode_height(const struct drm_display_mode *mode); /* for us by fb module */ -extern int drm_mode_attachmode_crtc(struct drm_device *dev, - struct drm_crtc *crtc, - const struct drm_display_mode *mode); -extern int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode); - extern struct drm_display_mode *drm_mode_create(struct drm_device *dev); extern void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode); extern void drm_mode_list_concat(struct list_head *head, @@ -938,6 +932,9 @@ extern void drm_mode_list_concat(struct list_head *head, 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_validate_clocks(struct drm_device *dev, + struct list_head *mode_list, + int *min, int *max, int n_ranges); 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); @@ -1036,14 +1033,6 @@ extern int drm_mode_getfb(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_dirtyfb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_mode_addmode_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); -extern int drm_mode_rmmode_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); -extern int drm_mode_attachmode_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); -extern int drm_mode_detachmode_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); extern int drm_mode_getproperty_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 8230b46fdd73..471f276ce8f7 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -50,13 +50,14 @@ struct drm_fb_helper_surface_size { /** * struct drm_fb_helper_funcs - driver callbacks for the fbdev emulation library - * @gamma_set: - Set the given gamma lut register on the given crtc. - * @gamma_get: - Read the given gamma lut register on the given crtc, used to - * save the current lut when force-restoring the fbdev for e.g. - * kdbg. - * @fb_probe: - Driver callback to allocate and initialize the fbdev info - * structure. Futhermore it also needs to allocate the drm - * framebuffer used to back the fbdev. + * @gamma_set: Set the given gamma lut register on the given crtc. + * @gamma_get: Read the given gamma lut register on the given crtc, used to + * save the current lut when force-restoring the fbdev for e.g. + * kdbg. + * @fb_probe: Driver callback to allocate and initialize the fbdev info + * structure. Futhermore it also needs to allocate the drm + * framebuffer used to back the fbdev. + * @initial_config: Setup an initial fbdev display configuration * * Driver callbacks used by the fbdev emulation helper library. */ diff --git a/include/drm/drm_os_linux.h b/include/drm/drm_os_linux.h index 393369147a2d..675ddf4b441f 100644 --- a/include/drm/drm_os_linux.h +++ b/include/drm/drm_os_linux.h @@ -87,15 +87,6 @@ static __inline__ int mtrr_del(int reg, unsigned long base, unsigned long size) /** Other copying of data from kernel space */ #define DRM_COPY_TO_USER(arg1, arg2, arg3) \ copy_to_user(arg1, arg2, arg3) -/* Macros for copyfrom user, but checking readability only once */ -#define DRM_VERIFYAREA_READ( uaddr, size ) \ - (access_ok( VERIFY_READ, uaddr, size ) ? 0 : -EFAULT) -#define DRM_COPY_FROM_USER_UNCHECKED(arg1, arg2, arg3) \ - __copy_from_user(arg1, arg2, arg3) -#define DRM_COPY_TO_USER_UNCHECKED(arg1, arg2, arg3) \ - __copy_to_user(arg1, arg2, arg3) -#define DRM_GET_USER_UNCHECKED(val, uaddr) \ - __get_user(val, uaddr) #define DRM_HZ HZ diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index 918e8fe2f5e9..c2af598f701d 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -240,6 +240,7 @@ {0x1002, 0x6819, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6821, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6822, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6823, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6824, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ @@ -247,11 +248,13 @@ {0x1002, 0x6827, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6829, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x682A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x682B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x682D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x682F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6831, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6838, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6839, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ @@ -603,6 +606,8 @@ {0x1002, 0x9999, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x999A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x999B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x999C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x999D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x99A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x99A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x99A4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 73a99e4664be..5a57be68bab7 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -711,8 +711,8 @@ struct drm_prime_handle { #define DRM_IOCTL_MODE_SETGAMMA DRM_IOWR(0xA5, struct drm_mode_crtc_lut) #define DRM_IOCTL_MODE_GETENCODER DRM_IOWR(0xA6, struct drm_mode_get_encoder) #define DRM_IOCTL_MODE_GETCONNECTOR DRM_IOWR(0xA7, struct drm_mode_get_connector) -#define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA8, struct drm_mode_mode_cmd) -#define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) +#define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA8, struct drm_mode_mode_cmd) /* deprecated (never worked) */ +#define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) /* deprecated (never worked) */ #define DRM_IOCTL_MODE_GETPROPERTY DRM_IOWR(0xAA, struct drm_mode_get_property) #define DRM_IOCTL_MODE_SETPROPERTY DRM_IOWR(0xAB, struct drm_mode_connector_set_property) |