diff options
Diffstat (limited to 'drivers')
115 files changed, 2944 insertions, 1490 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index b136c9c..449c556 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -943,6 +943,10 @@ static int acpi_bus_get_flags(struct acpi_device *device) if (ACPI_SUCCESS(status)) device->flags.lockable = 1; + /* Power resources cannot be power manageable. */ + if (device->device_type == ACPI_BUS_TYPE_POWER) + return 0; + /* Presence of _PS0|_PR0 indicates 'power manageable' */ status = acpi_get_handle(device->handle, "_PS0", &temp); if (ACPI_FAILURE(status)) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index fbc5b6e..abe3ab7 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -63,6 +63,7 @@ void device_pm_init(struct device *dev) dev->power.wakeup = NULL; spin_lock_init(&dev->power.lock); pm_runtime_init(dev); + INIT_LIST_HEAD(&dev->power.entry); } /** diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 4573c83..abbbd33 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -258,7 +258,7 @@ void device_set_wakeup_capable(struct device *dev, bool capable) if (!!dev->power.can_wakeup == !!capable) return; - if (device_is_registered(dev)) { + if (device_is_registered(dev) && !list_empty(&dev->power.entry)) { if (capable) { if (wakeup_sysfs_add(dev)) return; diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index b0a0dcc..b427711 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -903,6 +903,9 @@ static struct pci_device_id agp_intel_pci_table[] = { ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB), ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB), ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB), + ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_HB), + ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_HB), + ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_HB), { } }; diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h index 5feebe2..999803c 100644 --- a/drivers/char/agp/intel-agp.h +++ b/drivers/char/agp/intel-agp.h @@ -225,6 +225,14 @@ #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG 0x0126 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB 0x0108 /* Server */ #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG 0x010A +#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_HB 0x0150 /* Desktop */ +#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT1_IG 0x0152 +#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT2_IG 0x0162 +#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_HB 0x0154 /* Mobile */ +#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT1_IG 0x0156 +#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT2_IG 0x0166 +#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_HB 0x0158 /* Server */ +#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT1_IG 0x015A int intel_gmch_probe(struct pci_dev *pdev, struct agp_bridge_data *bridge); diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 0d09b53..8515101 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1420,6 +1420,16 @@ static const struct intel_gtt_driver_description { "Sandybridge", &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG, "Sandybridge", &sandybridge_gtt_driver }, + { PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT1_IG, + "Ivybridge", &sandybridge_gtt_driver }, + { PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT2_IG, + "Ivybridge", &sandybridge_gtt_driver }, + { PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT1_IG, + "Ivybridge", &sandybridge_gtt_driver }, + { PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT2_IG, + "Ivybridge", &sandybridge_gtt_driver }, + { PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT1_IG, + "Ivybridge", &sandybridge_gtt_driver }, { 0, NULL, NULL } }; diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 0fc0a79..6db161f 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -32,10 +32,9 @@ static DEFINE_MUTEX(clocks_mutex); * Then we take the most specific entry - with the following * order of precedence: dev+con > dev only > con only. */ -static struct clk *clk_find(const char *dev_id, const char *con_id) +static struct clk_lookup *clk_find(const char *dev_id, const char *con_id) { - struct clk_lookup *p; - struct clk *clk = NULL; + struct clk_lookup *p, *cl = NULL; int match, best = 0; list_for_each_entry(p, &clocks, node) { @@ -52,27 +51,27 @@ static struct clk *clk_find(const char *dev_id, const char *con_id) } if (match > best) { - clk = p->clk; + cl = p; if (match != 3) best = match; else break; } } - return clk; + return cl; } struct clk *clk_get_sys(const char *dev_id, const char *con_id) { - struct clk *clk; + struct clk_lookup *cl; mutex_lock(&clocks_mutex); - clk = clk_find(dev_id, con_id); - if (clk && !__clk_get(clk)) - clk = NULL; + cl = clk_find(dev_id, con_id); + if (cl && !__clk_get(cl->clk)) + cl = NULL; mutex_unlock(&clocks_mutex); - return clk ? clk : ERR_PTR(-ENOENT); + return cl ? cl->clk : ERR_PTR(-ENOENT); } EXPORT_SYMBOL(clk_get_sys); diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 62ced75..2022a5c 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -933,11 +933,34 @@ EXPORT_SYMBOL(drm_vblank_put); void drm_vblank_off(struct drm_device *dev, int crtc) { + struct drm_pending_vblank_event *e, *t; + struct timeval now; unsigned long irqflags; + unsigned int seq; spin_lock_irqsave(&dev->vbl_lock, irqflags); vblank_disable_and_save(dev, crtc); DRM_WAKEUP(&dev->vbl_queue[crtc]); + + /* Send any queued vblank events, lest the natives grow disquiet */ + seq = drm_vblank_count_and_time(dev, crtc, &now); + list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { + if (e->pipe != crtc) + continue; + DRM_DEBUG("Sending premature vblank event on disable: \ + wanted %d, current %d\n", + e->event.sequence, seq); + + e->event.sequence = seq; + e->event.tv_sec = now.tv_sec; + e->event.tv_usec = now.tv_usec; + drm_vblank_put(dev, e->pipe); + list_move_tail(&e->base.link, &e->base.file_priv->event_list); + wake_up_interruptible(&e->base.file_priv->event_wait); + trace_drm_vblank_event_delivered(e->base.pid, e->pipe, + e->event.sequence); + } + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } EXPORT_SYMBOL(drm_vblank_off); diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 87c8e29..183eaac 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -106,11 +106,12 @@ static const char *get_tiling_flag(struct drm_i915_gem_object *obj) } } -static const char *agp_type_str(int type) +static const char *cache_level_str(int type) { switch (type) { - case 0: return " uncached"; - case 1: return " snooped"; + case I915_CACHE_NONE: return " uncached"; + case I915_CACHE_LLC: return " snooped (LLC)"; + case I915_CACHE_LLC_MLC: return " snooped (LLC+MLC)"; default: return ""; } } @@ -127,7 +128,7 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) obj->base.write_domain, obj->last_rendering_seqno, obj->last_fenced_seqno, - agp_type_str(obj->agp_type == AGP_USER_CACHED_MEMORY), + cache_level_str(obj->cache_level), obj->dirty ? " dirty" : "", obj->madv == I915_MADV_DONTNEED ? " purgeable" : ""); if (obj->base.name) @@ -714,7 +715,7 @@ static void print_error_buffers(struct seq_file *m, dirty_flag(err->dirty), purgeable_flag(err->purgeable), ring_str(err->ring), - agp_type_str(err->agp_type)); + cache_level_str(err->cache_level)); if (err->name) seq_printf(m, " (name: %d)", err->name); @@ -852,6 +853,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; + int ret; if (IS_GEN5(dev)) { u16 rgvswctl = I915_READ16(MEMSWCTL); @@ -873,7 +875,11 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) int max_freq; /* RPSTAT1 is in the GT power well */ - __gen6_gt_force_wake_get(dev_priv); + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + gen6_gt_force_wake_get(dev_priv); rpstat = I915_READ(GEN6_RPSTAT1); rpupei = I915_READ(GEN6_RP_CUR_UP_EI); @@ -883,6 +889,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) rpcurdown = I915_READ(GEN6_RP_CUR_DOWN); rpprevdown = I915_READ(GEN6_RP_PREV_DOWN); + gen6_gt_force_wake_put(dev_priv); + mutex_unlock(&dev->struct_mutex); + seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status); seq_printf(m, "RPSTAT1: 0x%08x\n", rpstat); seq_printf(m, "Render p-state ratio: %d\n", @@ -917,8 +926,6 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) max_freq = rp_state_cap & 0xff; seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n", max_freq * 50); - - __gen6_gt_force_wake_put(dev_priv); } else { seq_printf(m, "no P-state info available\n"); } @@ -1186,6 +1193,42 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) return 0; } +static int i915_context_status(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + int ret; + + ret = mutex_lock_interruptible(&dev->mode_config.mutex); + if (ret) + return ret; + + seq_printf(m, "power context "); + describe_obj(m, dev_priv->pwrctx); + seq_printf(m, "\n"); + + seq_printf(m, "render context "); + describe_obj(m, dev_priv->renderctx); + seq_printf(m, "\n"); + + mutex_unlock(&dev->mode_config.mutex); + + return 0; +} + +static int i915_gen6_forcewake_count_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 drm_i915_private *dev_priv = dev->dev_private; + + seq_printf(m, "forcewake count = %d\n", + atomic_read(&dev_priv->forcewake_count)); + + return 0; +} + static int i915_wedged_open(struct inode *inode, struct file *filp) @@ -1288,6 +1331,67 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor) return drm_add_fake_info_node(minor, ent, &i915_wedged_fops); } +static int i915_forcewake_open(struct inode *inode, struct file *file) +{ + struct drm_device *dev = inode->i_private; + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + if (!IS_GEN6(dev)) + return 0; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + gen6_gt_force_wake_get(dev_priv); + mutex_unlock(&dev->struct_mutex); + + return 0; +} + +int i915_forcewake_release(struct inode *inode, struct file *file) +{ + struct drm_device *dev = inode->i_private; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!IS_GEN6(dev)) + return 0; + + /* + * It's bad that we can potentially hang userspace if struct_mutex gets + * forever stuck. However, if we cannot acquire this lock it means that + * almost certainly the driver has hung, is not unload-able. Therefore + * hanging here is probably a minor inconvenience not to be seen my + * almost every user. + */ + mutex_lock(&dev->struct_mutex); + gen6_gt_force_wake_put(dev_priv); + mutex_unlock(&dev->struct_mutex); + + return 0; +} + +static const struct file_operations i915_forcewake_fops = { + .owner = THIS_MODULE, + .open = i915_forcewake_open, + .release = i915_forcewake_release, +}; + +static int i915_forcewake_create(struct dentry *root, struct drm_minor *minor) +{ + struct drm_device *dev = minor->dev; + struct dentry *ent; + + ent = debugfs_create_file("i915_forcewake_user", + S_IRUSR, + root, dev, + &i915_forcewake_fops); + if (IS_ERR(ent)) + return PTR_ERR(ent); + + return drm_add_fake_info_node(minor, ent, &i915_forcewake_fops); +} + static struct drm_info_list i915_debugfs_list[] = { {"i915_capabilities", i915_capabilities, 0}, {"i915_gem_objects", i915_gem_object_info, 0}, @@ -1324,6 +1428,8 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_sr_status", i915_sr_status, 0}, {"i915_opregion", i915_opregion, 0}, {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0}, + {"i915_context_status", i915_context_status, 0}, + {"i915_gen6_forcewake_count", i915_gen6_forcewake_count_info, 0}, }; #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list) @@ -1335,6 +1441,10 @@ int i915_debugfs_init(struct drm_minor *minor) if (ret) return ret; + ret = i915_forcewake_create(minor->debugfs_root, minor); + if (ret) + return ret; + return drm_debugfs_create_files(i915_debugfs_list, I915_DEBUGFS_ENTRIES, minor->debugfs_root, minor); @@ -1344,6 +1454,8 @@ void i915_debugfs_cleanup(struct drm_minor *minor) { drm_debugfs_remove_files(i915_debugfs_list, I915_DEBUGFS_ENTRIES, minor); + drm_debugfs_remove_files((struct drm_info_list *) &i915_forcewake_fops, + 1, minor); drm_debugfs_remove_files((struct drm_info_list *) &i915_wedged_fops, 1, minor); } diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 12876f2..0239e99 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -571,7 +571,7 @@ static int i915_quiescent(struct drm_device *dev) struct intel_ring_buffer *ring = LP_RING(dev->dev_private); i915_kernel_lost_context(dev); - return intel_wait_ring_buffer(ring, ring->size - 8); + return intel_wait_ring_idle(ring); } static int i915_flush_ioctl(struct drm_device *dev, void *data, @@ -1176,11 +1176,11 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev) return can_switch; } -static int i915_load_modeset_init(struct drm_device *dev) +static int i915_load_gem_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; unsigned long prealloc_size, gtt_size, mappable_size; - int ret = 0; + int ret; prealloc_size = dev_priv->mm.gtt->stolen_size; gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT; @@ -1204,7 +1204,7 @@ static int i915_load_modeset_init(struct drm_device *dev) ret = i915_gem_init_ringbuffer(dev); mutex_unlock(&dev->struct_mutex); if (ret) - goto out; + return ret; /* Try to set up FBC with a reasonable compressed buffer size */ if (I915_HAS_FBC(dev) && i915_powersave) { @@ -1222,6 +1222,13 @@ static int i915_load_modeset_init(struct drm_device *dev) /* Allow hardware batchbuffers unless told otherwise. */ dev_priv->allow_batchbuffer = 1; + return 0; +} + +static int i915_load_modeset_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; ret = intel_parse_bios(dev); if (ret) @@ -1236,7 +1243,7 @@ static int i915_load_modeset_init(struct drm_device *dev) */ ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode); if (ret && ret != -ENODEV) - goto cleanup_ringbuffer; + goto out; intel_register_dsm_handler(); @@ -1253,10 +1260,40 @@ static int i915_load_modeset_init(struct drm_device *dev) intel_modeset_init(dev); - ret = drm_irq_install(dev); + ret = i915_load_gem_init(dev); if (ret) goto cleanup_vga_switcheroo; + intel_modeset_gem_init(dev); + + if (IS_IVYBRIDGE(dev)) { + /* Share pre & uninstall handlers with ILK/SNB */ + dev->driver->irq_handler = ivybridge_irq_handler; + dev->driver->irq_preinstall = ironlake_irq_preinstall; + dev->driver->irq_postinstall = ivybridge_irq_postinstall; + dev->driver->irq_uninstall = ironlake_irq_uninstall; + dev->driver->enable_vblank = ivybridge_enable_vblank; + dev->driver->disable_vblank = ivybridge_disable_vblank; + } else if (HAS_PCH_SPLIT(dev)) { + dev->driver->irq_handler = ironlake_irq_handler; + dev->driver->irq_preinstall = ironlake_irq_preinstall; + dev->driver->irq_postinstall = ironlake_irq_postinstall; + dev->driver->irq_uninstall = ironlake_irq_uninstall; + dev->driver->enable_vblank = ironlake_enable_vblank; + dev->driver->disable_vblank = ironlake_disable_vblank; + } else { + dev->driver->irq_preinstall = i915_driver_irq_preinstall; + dev->driver->irq_postinstall = i915_driver_irq_postinstall; + dev->driver->irq_uninstall = i915_driver_irq_uninstall; + dev->driver->irq_handler = i915_driver_irq_handler; + dev->driver->enable_vblank = i915_enable_vblank; + dev->driver->disable_vblank = i915_disable_vblank; + } + + ret = drm_irq_install(dev); + if (ret) + goto cleanup_gem; + /* Always safe in the mode setting case. */ /* FIXME: do pre/post-mode set stuff in core KMS code */ dev->vblank_disable_allowed = 1; @@ -1274,14 +1311,14 @@ static int i915_load_modeset_init(struct drm_device *dev) cleanup_irq: drm_irq_uninstall(dev); +cleanup_gem: + mutex_lock(&dev->struct_mutex); + i915_gem_cleanup_ringbuffer(dev); + mutex_unlock(&dev->struct_mutex); cleanup_vga_switcheroo: vga_switcheroo_unregister_client(dev->pdev); cleanup_vga_client: vga_client_register(dev->pdev, NULL, NULL, NULL); -cleanup_ringbuffer: - mutex_lock(&dev->struct_mutex); - i915_gem_cleanup_ringbuffer(dev); - mutex_unlock(&dev->struct_mutex); out: return ret; } @@ -1982,7 +2019,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev->driver->get_vblank_counter = i915_get_vblank_counter; dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ - if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev)) { + if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev)) { dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */ dev->driver->get_vblank_counter = gm45_get_vblank_counter; } @@ -2025,6 +2062,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&dev_priv->irq_lock); spin_lock_init(&dev_priv->error_lock); + spin_lock_init(&dev_priv->rps_lock); if (IS_MOBILE(dev) || !IS_GEN2(dev)) dev_priv->num_pipe = 2; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c34a8dd..8c4fcbb 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -188,6 +188,21 @@ static const struct intel_device_info intel_sandybridge_m_info = { .has_blt_ring = 1, }; +static const struct intel_device_info intel_ivybridge_d_info = { + .is_ivybridge = 1, .gen = 7, + .need_gfx_hws = 1, .has_hotplug = 1, + .has_bsd_ring = 1, + .has_blt_ring = 1, +}; + +static const struct intel_device_info intel_ivybridge_m_info = { + .is_ivybridge = 1, .gen = 7, .is_mobile = 1, + .need_gfx_hws = 1, .has_hotplug = 1, + .has_fbc = 0, /* FBC is not enabled on Ivybridge mobile yet */ + .has_bsd_ring = 1, + .has_blt_ring = 1, +}; + static const struct pci_device_id pciidlist[] = { /* aka */ INTEL_VGA_DEVICE(0x3577, &intel_i830_info), /* I830_M */ INTEL_VGA_DEVICE(0x2562, &intel_845g_info), /* 845_G */ @@ -227,6 +242,11 @@ static const struct pci_device_id pciidlist[] = { /* aka */ INTEL_VGA_DEVICE(0x0116, &intel_sandybridge_m_info), INTEL_VGA_DEVICE(0x0126, &intel_sandybridge_m_info), INTEL_VGA_DEVICE(0x010A, &intel_sandybridge_d_info), + INTEL_VGA_DEVICE(0x0156, &intel_ivybridge_m_info), /* GT1 mobile */ + INTEL_VGA_DEVICE(0x0166, &intel_ivybridge_m_info), /* GT2 mobile */ + INTEL_VGA_DEVICE(0x0152, &intel_ivybridge_d_info), /* GT1 desktop */ + INTEL_VGA_DEVICE(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */ + INTEL_VGA_DEVICE(0x015a, &intel_ivybridge_d_info), /* GT1 server */ {0, 0, 0} }; @@ -235,7 +255,9 @@ MODULE_DEVICE_TABLE(pci, pciidlist); #endif #define INTEL_PCH_DEVICE_ID_MASK 0xff00 +#define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 #define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00 +#define INTEL_PCH_PPT_DEVICE_ID_TYPE 0x1e00 void intel_detect_pch (struct drm_device *dev) { @@ -254,16 +276,23 @@ void intel_detect_pch (struct drm_device *dev) int id; id = pch->device & INTEL_PCH_DEVICE_ID_MASK; - if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) { + if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_IBX; + DRM_DEBUG_KMS("Found Ibex Peak PCH\n"); + } else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_CPT; DRM_DEBUG_KMS("Found CougarPoint PCH\n"); + } else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) { + /* PantherPoint is CPT compatible */ + dev_priv->pch_type = PCH_CPT; + DRM_DEBUG_KMS("Found PatherPoint PCH\n"); } } pci_dev_put(pch); } } -void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) +static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) { int count; @@ -279,12 +308,38 @@ void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) udelay(10); } -void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) +/* + * Generally this is called implicitly by the register read function. However, + * if some sequence requires the GT to not power down then this function should + * be called at the beginning of the sequence followed by a call to + * gen6_gt_force_wake_put() at the end of the sequence. + */ +void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) +{ + WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); + + /* Forcewake is atomic in case we get in here without the lock */ + if (atomic_add_return(1, &dev_priv->forcewake_count) == 1) + __gen6_gt_force_wake_get(dev_priv); +} + +static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) { I915_WRITE_NOTRACE(FORCEWAKE, 0); POSTING_READ(FORCEWAKE); } +/* + * see gen6_gt_force_wake_get() + */ +void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) +{ + WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); + + if (atomic_dec_and_test(&dev_priv->forcewake_count)) + __gen6_gt_force_wake_put(dev_priv); +} + void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) { int loop = 500; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1c1b27c..3a1c277 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -188,7 +188,7 @@ struct drm_i915_error_state { u32 dirty:1; u32 purgeable:1; u32 ring:4; - u32 agp_type:1; + u32 cache_level:2; } *active_bo, *pinned_bo; u32 active_bo_count, pinned_bo_count; struct intel_overlay_error_state *overlay; @@ -203,12 +203,19 @@ struct drm_i915_display_funcs { int (*get_display_clock_speed)(struct drm_device *dev); int (*get_fifo_size)(struct drm_device *dev, int plane); void (*update_wm)(struct drm_device *dev); + int (*crtc_mode_set)(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, + struct drm_framebuffer *old_fb); + void (*fdi_link_train)(struct drm_crtc *crtc); + void (*init_clock_gating)(struct drm_device *dev); + void (*init_pch_clock_gating)(struct drm_device *dev); /* clock updates for mode set */ /* cursor updates */ /* render clock increase/decrease */ /* display clock increase/decrease */ /* pll clock increase/decrease */ - /* clock gating init */ }; struct intel_device_info { @@ -223,6 +230,7 @@ struct intel_device_info { u8 is_pineview : 1; u8 is_broadwater : 1; u8 is_crestline : 1; + u8 is_ivybridge : 1; u8 has_fbc : 1; u8 has_pipe_cxsr : 1; u8 has_hotplug : 1; @@ -676,6 +684,10 @@ typedef struct drm_i915_private { bool mchbar_need_disable; + struct work_struct rps_work; + spinlock_t rps_lock; + u32 pm_iir; + u8 cur_delay; u8 min_delay; u8 max_delay; @@ -703,8 +715,16 @@ typedef struct drm_i915_private { struct intel_fbdev *fbdev; struct drm_property *broadcast_rgb_property; + + atomic_t forcewake_count; } drm_i915_private_t; +enum i915_cache_level { + I915_CACHE_NONE, + I915_CACHE_LLC, + I915_CACHE_LLC_MLC, /* gen6+ */ +}; + struct drm_i915_gem_object { struct drm_gem_object base; @@ -791,6 +811,8 @@ struct drm_i915_gem_object { unsigned int pending_fenced_gpu_access:1; unsigned int fenced_gpu_access:1; + unsigned int cache_level:2; + struct page **pages; /** @@ -827,8 +849,6 @@ struct drm_i915_gem_object { /** Record of address bit 17 of each page at last unbind. */ unsigned long *bit_17; - /** AGP mapping type (AGP_USER_MEMORY or AGP_USER_CACHED_MEMORY */ - uint32_t agp_type; /** * If present, while GEM_DOMAIN_CPU is in the read domain this array @@ -915,13 +935,21 @@ enum intel_chip_family { #define IS_G33(dev) (INTEL_INFO(dev)->is_g33) #define IS_IRONLAKE_D(dev) ((dev)->pci_device == 0x0042) #define IS_IRONLAKE_M(dev) ((dev)->pci_device == 0x0046) +#define IS_IVYBRIDGE(dev) (INTEL_INFO(dev)->is_ivybridge) #define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile) +/* + * The genX designation typically refers to the render engine, so render + * capability related checks should use IS_GEN, while display and other checks + * have their own (e.g. HAS_PCH_SPLIT for ILK+ display, IS_foo for particular + * chips, etc.). + */ #define IS_GEN2(dev) (INTEL_INFO(dev)->gen == 2) #define IS_GEN3(dev) (INTEL_INFO(dev)->gen == 3) #define IS_GEN4(dev) (INTEL_INFO(dev)->gen == 4) #define IS_GEN5(dev) (INTEL_INFO(dev)->gen == 5) #define IS_GEN6(dev) (INTEL_INFO(dev)->gen == 6) +#define IS_GEN7(dev) (INTEL_INFO(dev)->gen == 7) #define HAS_BSD(dev) (INTEL_INFO(dev)->has_bsd_ring) #define HAS_BLT(dev) (INTEL_INFO(dev)->has_blt_ring) @@ -948,8 +976,8 @@ enum intel_chip_family { #define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr) #define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc) -#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev)) -#define HAS_PIPE_CONTROL(dev) (IS_GEN5(dev) || IS_GEN6(dev)) +#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev)) +#define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5) #define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type) #define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT) @@ -1010,12 +1038,27 @@ extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); extern void i915_driver_irq_preinstall(struct drm_device * dev); extern int i915_driver_irq_postinstall(struct drm_device *dev); extern void i915_driver_irq_uninstall(struct drm_device * dev); + +extern irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS); +extern void ironlake_irq_preinstall(struct drm_device *dev); +extern int ironlake_irq_postinstall(struct drm_device *dev); +extern void ironlake_irq_uninstall(struct drm_device *dev); + +extern irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS); +extern void ivybridge_irq_preinstall(struct drm_device *dev); +extern int ivybridge_irq_postinstall(struct drm_device *dev); +extern void ivybridge_irq_uninstall(struct drm_device *dev); + extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int i915_vblank_pipe_get(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int i915_enable_vblank(struct drm_device *dev, int crtc); extern void i915_disable_vblank(struct drm_device *dev, int crtc); +extern int ironlake_enable_vblank(struct drm_device *dev, int crtc); +extern void ironlake_disable_vblank(struct drm_device *dev, int crtc); +extern int ivybridge_enable_vblank(struct drm_device *dev, int crtc); +extern void ivybridge_disable_vblank(struct drm_device *dev, int crtc); extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc); extern u32 gm45_get_vblank_counter(struct drm_device *dev, int crtc); extern int i915_vblank_swap(struct drm_device *dev, void *data, @@ -1265,6 +1308,7 @@ static inline void intel_unregister_dsm_handler(void) { return; } /* modesetting */ extern void intel_modeset_init(struct drm_device *dev); +extern void intel_modeset_gem_init(struct drm_device *dev); extern void intel_modeset_cleanup(struct drm_device *dev); extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state); extern void i8xx_disable_fbc(struct drm_device *dev); @@ -1312,13 +1356,34 @@ extern void intel_display_print_error_state(struct seq_file *m, LOCK_TEST_WITH_RETURN(dev, file); \ } while (0) +/* On SNB platform, before reading ring registers forcewake bit + * must be set to prevent GT core from power down and stale values being + * returned. + */ +void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv); +void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv); +void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv); + +/* We give fast paths for the really cool registers */ +#define NEEDS_FORCE_WAKE(dev_priv, reg) \ + (((dev_priv)->info->gen >= 6) && \ + ((reg) < 0x40000) && \ + ((reg) != FORCEWAKE)) #define __i915_read(x, y) \ static inline u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ - u##x val = read##y(dev_priv->regs + reg); \ + u##x val = 0; \ + if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ + gen6_gt_force_wake_get(dev_priv); \ + val = read##y(dev_priv->regs + reg); \ + gen6_gt_force_wake_put(dev_priv); \ + } else { \ + val = read##y(dev_priv->regs + reg); \ + } \ trace_i915_reg_rw(false, reg, val, sizeof(val)); \ return val; \ } + __i915_read(8, b) __i915_read(16, w) __i915_read(32, l) @@ -1328,6 +1393,9 @@ __i915_read(64, q) #define __i915_write(x, y) \ static inline void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \ trace_i915_reg_rw(true, reg, val, sizeof(val)); \ + if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ + __gen6_gt_wait_for_fifo(dev_priv); \ + } \ write##y(val, dev_priv->regs + reg); \ } __i915_write(8, b) @@ -1356,33 +1424,4 @@ __i915_write(64, q) #define POSTING_READ16(reg) (void)I915_READ16_NOTRACE(reg) -/* On SNB platform, before reading ring registers forcewake bit - * must be set to prevent GT core from power down and stale values being - * returned. - */ -void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv); -void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv); -void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv); - -static inline u32 i915_gt_read(struct drm_i915_private *dev_priv, u32 reg) -{ - u32 val; - - if (dev_priv->info->gen >= 6) { - __gen6_gt_force_wake_get(dev_priv); - val = I915_READ(reg); - __gen6_gt_force_wake_put(dev_priv); - } else - val = I915_READ(reg); - - return val; -} - -static inline void i915_gt_write(struct drm_i915_private *dev_priv, - u32 reg, u32 val) -{ - if (dev_priv->info->gen >= 6) - __gen6_gt_wait_for_fifo(dev_priv); - I915_WRITE(reg, val); -} #endif diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 7ce3f35..c628903 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2673,6 +2673,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj, update: obj->tiling_changed = false; switch (INTEL_INFO(dev)->gen) { + case 7: case 6: ret = sandybridge_write_fence_reg(obj, pipelined); break; @@ -2706,6 +2707,7 @@ i915_gem_clear_fence_reg(struct drm_device *dev, uint32_t fence_reg = reg - dev_priv->fence_regs; switch (INTEL_INFO(dev)->gen) { + case 7: case 6: I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + fence_reg*8, 0); break; @@ -2878,6 +2880,17 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj) if (obj->pages == NULL) return; + /* If the GPU is snooping the contents of the CPU cache, + * we do not need to manually clear the CPU cache lines. However, + * the caches are only snooped when the render cache is + * flushed/invalidated. As we always have to emit invalidations + * and flushes when moving into and out of the RENDER domain, correct + * snooping behaviour occurs naturally as the result of our domain + * tracking. + */ + if (obj->cache_level != I915_CACHE_NONE) + return; + trace_i915_gem_object_clflush(obj); drm_clflush_pages(obj->pages, obj->base.size / PAGE_SIZE); @@ -3569,7 +3582,7 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, obj->base.write_domain = I915_GEM_DOMAIN_CPU; obj->base.read_domains = I915_GEM_DOMAIN_CPU; - obj->agp_type = AGP_USER_MEMORY; + obj->cache_level = I915_CACHE_NONE; obj->base.driver_private = NULL; obj->fence_reg = I915_FENCE_REG_NONE; INIT_LIST_HEAD(&obj->mm_list); @@ -3845,25 +3858,10 @@ i915_gem_load(struct drm_device *dev) dev_priv->num_fence_regs = 8; /* Initialize fence registers to zero */ - switch (INTEL_INFO(dev)->gen) { - case 6: - for (i = 0; i < 16; i++) - I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), 0); - break; - case 5: - case 4: - for (i = 0; i < 16; i++) - I915_WRITE64(FENCE_REG_965_0 + (i * 8), 0); - break; - case 3: - if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) - for (i = 0; i < 8; i++) - I915_WRITE(FENCE_REG_945_8 + (i * 4), 0); - case 2: - for (i = 0; i < 8; i++) - I915_WRITE(FENCE_REG_830_0 + (i * 4), 0); - break; + for (i = 0; i < dev_priv->num_fence_regs; i++) { + i915_gem_clear_fence_reg(dev, &dev_priv->fence_regs[i]); } + i915_gem_detect_bit_6_swizzle(dev); init_waitqueue_head(&dev_priv->pending_flip_queue); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index b0abdc6..e46b645 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -29,6 +29,26 @@ #include "i915_trace.h" #include "intel_drv.h" +/* XXX kill agp_type! */ +static unsigned int cache_level_to_agp_type(struct drm_device *dev, + enum i915_cache_level cache_level) +{ + switch (cache_level) { + case I915_CACHE_LLC_MLC: + if (INTEL_INFO(dev)->gen >= 6) + return AGP_USER_CACHED_MEMORY_LLC_MLC; + /* Older chipsets do not have this extra level of CPU + * cacheing, so fallthrough and request the PTE simply + * as cached. + */ + case I915_CACHE_LLC: + return AGP_USER_CACHED_MEMORY; + default: + case I915_CACHE_NONE: + return AGP_USER_MEMORY; + } +} + void i915_gem_restore_gtt_mappings(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -39,6 +59,9 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) (dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE); list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) { + unsigned int agp_type = + cache_level_to_agp_type(dev, obj->cache_level); + i915_gem_clflush_object(obj); if (dev_priv->mm.gtt->needs_dmar) { @@ -46,15 +69,14 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) intel_gtt_insert_sg_entries(obj->sg_list, obj->num_sg, - obj->gtt_space->start - >> PAGE_SHIFT, - obj->agp_type); + obj->gtt_space->start >> PAGE_SHIFT, + agp_type); } else intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT, obj->base.size >> PAGE_SHIFT, obj->pages, - obj->agp_type); + agp_type); } intel_gtt_chipset_flush(); @@ -64,6 +86,7 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj) { struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + unsigned int agp_type = cache_level_to_agp_type(dev, obj->cache_level); int ret; if (dev_priv->mm.gtt->needs_dmar) { @@ -77,12 +100,12 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj) intel_gtt_insert_sg_entries(obj->sg_list, obj->num_sg, obj->gtt_space->start >> PAGE_SHIFT, - obj->agp_type); + agp_type); } else intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT, obj->base.size >> PAGE_SHIFT, obj->pages, - obj->agp_type); + agp_type); return 0; } diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 281ad3d..82d70fd 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -92,7 +92,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; - if (IS_GEN5(dev) || IS_GEN6(dev)) { + if (INTEL_INFO(dev)->gen >= 5) { /* On Ironlake whatever DRAM config, GPU always do * same swizzling setup. */ diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 188b497..349a03e 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -367,22 +367,30 @@ static void notify_ring(struct drm_device *dev, jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); } -static void gen6_pm_irq_handler(struct drm_device *dev) +static void gen6_pm_rps_work(struct work_struct *work) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, + rps_work); u8 new_delay = dev_priv->cur_delay; - u32 pm_iir; + u32 pm_iir, pm_imr; + + spin_lock_irq(&dev_priv->rps_lock); + pm_iir = dev_priv->pm_iir; + dev_priv->pm_iir = 0; + pm_imr = I915_READ(GEN6_PMIMR); + spin_unlock_irq(&dev_priv->rps_lock); - pm_iir = I915_READ(GEN6_PMIIR); if (!pm_iir) return; + mutex_lock(&dev_priv->dev->struct_mutex); if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) { if (dev_priv->cur_delay != dev_priv->max_delay) new_delay = dev_priv->cur_delay + 1; if (new_delay > dev_priv->max_delay) new_delay = dev_priv->max_delay; } else if (pm_iir & (GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT)) { + gen6_gt_force_wake_get(dev_priv); if (dev_priv->cur_delay != dev_priv->min_delay) new_delay = dev_priv->cur_delay - 1; if (new_delay < dev_priv->min_delay) { @@ -396,13 +404,19 @@ static void gen6_pm_irq_handler(struct drm_device *dev) I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, I915_READ(GEN6_RP_INTERRUPT_LIMITS) & ~0x3f0000); } - + gen6_gt_force_wake_put(dev_priv); } - gen6_set_rps(dev, new_delay); + gen6_set_rps(dev_priv->dev, new_delay); dev_priv->cur_delay = new_delay; - I915_WRITE(GEN6_PMIIR, pm_iir); + /* + * rps_lock not held here because clearing is non-destructive. There is + * an *extremely* unlikely race with gen6_rps_enable() that is prevented + * by holding struct_mutex for the duration of the write. + */ + I915_WRITE(GEN6_PMIMR, pm_imr & ~pm_iir); + mutex_unlock(&dev_priv->dev->struct_mutex); } static void pch_irq_handler(struct drm_device *dev) @@ -448,8 +462,97 @@ static void pch_irq_handler(struct drm_device *dev) DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n"); } -static irqreturn_t ironlake_irq_handler(struct drm_device *dev) +irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS) +{ + struct drm_device *dev = (struct drm_device *) arg; + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int ret = IRQ_NONE; + u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir; + struct drm_i915_master_private *master_priv; + + atomic_inc(&dev_priv->irq_received); + + /* disable master interrupt before clearing iir */ + de_ier = I915_READ(DEIER); + I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); + POSTING_READ(DEIER); + + de_iir = I915_READ(DEIIR); + gt_iir = I915_READ(GTIIR); + pch_iir = I915_READ(SDEIIR); + pm_iir = I915_READ(GEN6_PMIIR); + + if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 && pm_iir == 0) + goto done; + + ret = IRQ_HANDLED; + + if (dev->primary->master) { + master_priv = dev->primary->master->driver_priv; + if (master_priv->sarea_priv) + master_priv->sarea_priv->last_dispatch = + READ_BREADCRUMB(dev_priv); + } + + if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY)) + notify_ring(dev, &dev_priv->ring[RCS]); + if (gt_iir & GT_GEN6_BSD_USER_INTERRUPT) + notify_ring(dev, &dev_priv->ring[VCS]); + if (gt_iir & GT_BLT_USER_INTERRUPT) + notify_ring(dev, &dev_priv->ring[BCS]); + + if (de_iir & DE_GSE_IVB) + intel_opregion_gse_intr(dev); + + if (de_iir & DE_PLANEA_FLIP_DONE_IVB) { + intel_prepare_page_flip(dev, 0); + intel_finish_page_flip_plane(dev, 0); + } + + if (de_iir & DE_PLANEB_FLIP_DONE_IVB) { + intel_prepare_page_flip(dev, 1); + intel_finish_page_flip_plane(dev, 1); + } + + if (de_iir & DE_PIPEA_VBLANK_IVB) + drm_handle_vblank(dev, 0); + + if (de_iir & DE_PIPEB_VBLANK_IVB); + drm_handle_vblank(dev, 1); + + /* check event from PCH */ + if (de_iir & DE_PCH_EVENT_IVB) { + if (pch_iir & SDE_HOTPLUG_MASK_CPT) + queue_work(dev_priv->wq, &dev_priv->hotplug_work); + pch_irq_handler(dev); + } + + if (pm_iir & GEN6_PM_DEFERRED_EVENTS) { + unsigned long flags; + spin_lock_irqsave(&dev_priv->rps_lock, flags); + WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n"); + I915_WRITE(GEN6_PMIMR, pm_iir); + dev_priv->pm_iir |= pm_iir; + spin_unlock_irqrestore(&dev_priv->rps_lock, flags); + queue_work(dev_priv->wq, &dev_priv->rps_work); + } + + /* should clear PCH hotplug event before clear CPU irq */ + I915_WRITE(SDEIIR, pch_iir); + I915_WRITE(GTIIR, gt_iir); + I915_WRITE(DEIIR, de_iir); + I915_WRITE(GEN6_PMIIR, pm_iir); + +done: + I915_WRITE(DEIER, de_ier); + POSTING_READ(DEIER); + + return ret; +} + +irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS) { + struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int ret = IRQ_NONE; u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir; @@ -457,6 +560,8 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev) struct drm_i915_master_private *master_priv; u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT; + atomic_inc(&dev_priv->irq_received); + if (IS_GEN6(dev)) bsd_usr_interrupt = GT_GEN6_BSD_USER_INTERRUPT; @@ -526,13 +631,30 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev) i915_handle_rps_change(dev); } - if (IS_GEN6(dev)) - gen6_pm_irq_handler(dev); + if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS) { + /* + * IIR bits should never already be set because IMR should + * prevent an interrupt from being shown in IIR. The warning + * displays a case where we've unsafely cleared + * dev_priv->pm_iir. Although missing an interrupt of the same + * type is not a problem, it displays a problem in the logic. + * + * The mask bit in IMR is cleared by rps_work. + */ + unsigned long flags; + spin_lock_irqsave(&dev_priv->rps_lock, flags); + WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n"); + I915_WRITE(GEN6_PMIMR, pm_iir); + dev_priv->pm_iir |= pm_iir; + spin_unlock_irqrestore(&dev_priv->rps_lock, flags); + queue_work(dev_priv->wq, &dev_priv->rps_work); + } /* should clear PCH hotplug event before clear CPU irq */ I915_WRITE(SDEIIR, pch_iir); I915_WRITE(GTIIR, gt_iir); I915_WRITE(DEIIR, de_iir); + I915_WRITE(GEN6_PMIIR, pm_iir); done: I915_WRITE(DEIER, de_ier); @@ -676,7 +798,7 @@ static u32 capture_bo_list(struct drm_i915_error_buffer *err, err->dirty = obj->dirty; err->purgeable = obj->madv != I915_MADV_WILLNEED; err->ring = obj->ring ? obj->ring->id : 0; - err->agp_type = obj->agp_type == AGP_USER_CACHED_MEMORY; + err->cache_level = obj->cache_level; if (++i == count) break; @@ -1103,9 +1225,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) atomic_inc(&dev_priv->irq_received); - if (HAS_PCH_SPLIT(dev)) - return ironlake_irq_handler(dev); - iir = I915_READ(IIR); if (INTEL_INFO(dev)->gen >= 4) @@ -1344,10 +1463,7 @@ int i915_enable_vblank(struct drm_device *dev, int pipe) return -EINVAL; spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - if (HAS_PCH_SPLIT(dev)) - ironlake_enable_display_irq(dev_priv, (pipe == 0) ? - DE_PIPEA_VBLANK: DE_PIPEB_VBLANK); - else if (INTEL_INFO(dev)->gen >= 4) + if (INTEL_INFO(dev)->gen >= 4) i915_enable_pipestat(dev_priv, pipe, PIPE_START_VBLANK_INTERRUPT_ENABLE); else @@ -1362,6 +1478,38 @@ int i915_enable_vblank(struct drm_device *dev, int pipe) return 0; } +int ironlake_enable_vblank(struct drm_device *dev, int pipe) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned long irqflags; + + if (!i915_pipe_enabled(dev, pipe)) + return -EINVAL; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + ironlake_enable_display_irq(dev_priv, (pipe == 0) ? + DE_PIPEA_VBLANK: DE_PIPEB_VBLANK); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + + return 0; +} + +int ivybridge_enable_vblank(struct drm_device *dev, int pipe) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned long irqflags; + + if (!i915_pipe_enabled(dev, pipe)) + return -EINVAL; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + ironlake_enable_display_irq(dev_priv, (pipe == 0) ? + DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + + return 0; +} + /* Called from drm generic code, passed 'crtc' which * we use as a pipe index */ @@ -1375,13 +1523,31 @@ void i915_disable_vblank(struct drm_device *dev, int pipe) I915_WRITE(INSTPM, INSTPM_AGPBUSY_DIS << 16 | INSTPM_AGPBUSY_DIS); - if (HAS_PCH_SPLIT(dev)) - ironlake_disable_display_irq(dev_priv, (pipe == 0) ? - DE_PIPEA_VBLANK: DE_PIPEB_VBLANK); - else - i915_disable_pipestat(dev_priv, pipe, - PIPE_VBLANK_INTERRUPT_ENABLE | - PIPE_START_VBLANK_INTERRUPT_ENABLE); + i915_disable_pipestat(dev_priv, pipe, + PIPE_VBLANK_INTERRUPT_ENABLE | + PIPE_START_VBLANK_INTERRUPT_ENABLE); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); +} + +void ironlake_disable_vblank(struct drm_device *dev, int pipe) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + ironlake_disable_display_irq(dev_priv, (pipe == 0) ? + DE_PIPEA_VBLANK: DE_PIPEB_VBLANK); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); +} + +void ivybridge_disable_vblank(struct drm_device *dev, int pipe) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + ironlake_disable_display_irq(dev_priv, (pipe == 0) ? + DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } @@ -1562,10 +1728,15 @@ repeat: /* drm_dma.h hooks */ -static void ironlake_irq_preinstall(struct drm_device *dev) +void ironlake_irq_preinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + atomic_set(&dev_priv->irq_received, 0); + + INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); + INIT_WORK(&dev_priv->error_work, i915_error_work_func); + I915_WRITE(HWSTAM, 0xeffe); /* XXX hotplug from PCH */ @@ -1585,7 +1756,7 @@ static void ironlake_irq_preinstall(struct drm_device *dev) POSTING_READ(SDEIER); } -static int ironlake_irq_postinstall(struct drm_device *dev) +int ironlake_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; /* enable kind of interrupts always enabled */ @@ -1594,6 +1765,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev) u32 render_irqs; u32 hotplug_mask; + DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue); + if (HAS_BSD(dev)) + DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue); + if (HAS_BLT(dev)) + DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue); + + dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; dev_priv->irq_mask = ~display_mask; /* should always can generate irq */ @@ -1650,6 +1828,56 @@ static int ironlake_irq_postinstall(struct drm_device *dev) return 0; } +int ivybridge_irq_postinstall(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + /* enable kind of interrupts always enabled */ + u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | + DE_PCH_EVENT_IVB | DE_PLANEA_FLIP_DONE_IVB | + DE_PLANEB_FLIP_DONE_IVB; + u32 render_irqs; + u32 hotplug_mask; + + DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue); + if (HAS_BSD(dev)) + DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue); + if (HAS_BLT(dev)) + DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue); + + dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; + dev_priv->irq_mask = ~display_mask; + + /* should always can generate irq */ + I915_WRITE(DEIIR, I915_READ(DEIIR)); + I915_WRITE(DEIMR, dev_priv->irq_mask); + I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK_IVB | + DE_PIPEB_VBLANK_IVB); + POSTING_READ(DEIER); + + dev_priv->gt_irq_mask = ~0; + + I915_WRITE(GTIIR, I915_READ(GTIIR)); + I915_WRITE(GTIMR, dev_priv->gt_irq_mask); + + render_irqs = GT_USER_INTERRUPT | GT_GEN6_BSD_USER_INTERRUPT | + GT_BLT_USER_INTERRUPT; + I915_WRITE(GTIER, render_irqs); + POSTING_READ(GTIER); + + hotplug_mask = (SDE_CRT_HOTPLUG_CPT | + SDE_PORTB_HOTPLUG_CPT | + SDE_PORTC_HOTPLUG_CPT | + SDE_PORTD_HOTPLUG_CPT); + dev_priv->pch_irq_mask = ~hotplug_mask; + + I915_WRITE(SDEIIR, I915_READ(SDEIIR)); + I915_WRITE(SDEIMR, dev_priv->pch_irq_mask); + I915_WRITE(SDEIER, hotplug_mask); + POSTING_READ(SDEIER); + + return 0; +} + void i915_driver_irq_preinstall(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -1659,11 +1887,7 @@ void i915_driver_irq_preinstall(struct drm_device * dev) INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); INIT_WORK(&dev_priv->error_work, i915_error_work_func); - - if (HAS_PCH_SPLIT(dev)) { - ironlake_irq_preinstall(dev); - return; - } + INIT_WORK(&dev_priv->rps_work, gen6_pm_rps_work); if (I915_HAS_HOTPLUG(dev)) { I915_WRITE(PORT_HOTPLUG_EN, 0); @@ -1688,17 +1912,8 @@ int i915_driver_irq_postinstall(struct drm_device *dev) u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR; u32 error_mask; - DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue); - if (HAS_BSD(dev)) - DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue); - if (HAS_BLT(dev)) - DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue); - dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; - if (HAS_PCH_SPLIT(dev)) - return ironlake_irq_postinstall(dev); - /* Unmask the interrupts that we always want on. */ dev_priv->irq_mask = ~I915_INTERRUPT_ENABLE_FIX; @@ -1767,9 +1982,15 @@ int i915_driver_irq_postinstall(struct drm_device *dev) return 0; } -static void ironlake_irq_uninstall(struct drm_device *dev) +void ironlake_irq_uninstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + + if (!dev_priv) + return; + + dev_priv->vblank_pipe = 0; + I915_WRITE(HWSTAM, 0xffffffff); I915_WRITE(DEIMR, 0xffffffff); @@ -1791,11 +2012,6 @@ void i915_driver_irq_uninstall(struct drm_device * dev) dev_priv->vblank_pipe = 0; - if (HAS_PCH_SPLIT(dev)) { - ironlake_irq_uninstall(dev); - return; - } - if (I915_HAS_HOTPLUG(dev)) { I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f39ac3a..2f967af 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -291,6 +291,9 @@ #define RING_MAX_IDLE(base) ((base)+0x54) #define RING_HWS_PGA(base) ((base)+0x80) #define RING_HWS_PGA_GEN6(base) ((base)+0x2080) +#define RENDER_HWS_PGA_GEN7 (0x04080) +#define BSD_HWS_PGA_GEN7 (0x04180) +#define BLT_HWS_PGA_GEN7 (0x04280) #define RING_ACTHD(base) ((base)+0x74) #define RING_NOPID(base) ((base)+0x94) #define RING_IMR(base) ((base)+0xa8) @@ -2778,6 +2781,19 @@ #define DE_PIPEA_VSYNC (1 << 3) #define DE_PIPEA_FIFO_UNDERRUN (1 << 0) +/* More Ivybridge lolz */ +#define DE_ERR_DEBUG_IVB (1<<30) +#define DE_GSE_IVB (1<<29) +#define DE_PCH_EVENT_IVB (1<<28) +#define DE_DP_A_HOTPLUG_IVB (1<<27) +#define DE_AUX_CHANNEL_A_IVB (1<<26) +#define DE_SPRITEB_FLIP_DONE_IVB (1<<9) +#define DE_SPRITEA_FLIP_DONE_IVB (1<<4) +#define DE_PLANEB_FLIP_DONE_IVB (1<<8) +#define DE_PLANEA_FLIP_DONE_IVB (1<<3) +#define DE_PIPEB_VBLANK_IVB (1<<5) +#define DE_PIPEA_VBLANK_IVB (1<<0) + #define DEISR 0x44000 #define DEIMR 0x44004 #define DEIIR 0x44008 @@ -2809,6 +2825,7 @@ #define ILK_eDP_A_DISABLE (1<<24) #define ILK_DESKTOP (1<<23) #define ILK_DSPCLK_GATE 0x42020 +#define IVB_VRHUNIT_CLK_GATE (1<<28) #define ILK_DPARB_CLK_GATE (1<<5) #define ILK_DPFD_CLK_GATE (1<<7) @@ -3057,6 +3074,9 @@ #define TRANS_6BPC (2<<5) #define TRANS_12BPC (3<<5) +#define SOUTH_CHICKEN2 0xc2004 +#define DPLS_EDP_PPS_FIX_DIS (1<<0) + #define _FDI_RXA_CHICKEN 0xc200c #define _FDI_RXB_CHICKEN 0xc2010 #define FDI_RX_PHASE_SYNC_POINTER_OVR (1<<1) @@ -3104,7 +3124,15 @@ #define FDI_TX_ENHANCE_FRAME_ENABLE (1<<18) /* Ironlake: hardwired to 1 */ #define FDI_TX_PLL_ENABLE (1<<14) + +/* Ivybridge has different bits for lolz */ +#define FDI_LINK_TRAIN_PATTERN_1_IVB (0<<8) +#define FDI_LINK_TRAIN_PATTERN_2_IVB (1<<8) +#define FDI_LINK_TRAIN_PATTERN_IDLE_IVB (2<<8) +#define FDI_LINK_TRAIN_NONE_IVB (3<<8) + /* both Tx and Rx */ +#define FDI_LINK_TRAIN_AUTO (1<<10) #define FDI_SCRAMBLING_ENABLE (0<<7) #define FDI_SCRAMBLING_DISABLE (1<<7) @@ -3114,6 +3142,8 @@ #define FDI_RX_CTL(pipe) _PIPE(pipe, _FDI_RXA_CTL, _FDI_RXB_CTL) #define FDI_RX_ENABLE (1<<31) /* train, dp width same as FDI_TX */ +#define FDI_FS_ERRC_ENABLE (1<<27) +#define FDI_FE_ERRC_ENABLE (1<<26) #define FDI_DP_PORT_WIDTH_X8 (7<<19) #define FDI_8BPC (0<<16) #define FDI_10BPC (1<<16) @@ -3386,7 +3416,7 @@ #define GEN6_PMINTRMSK 0xA168 #define GEN6_PMISR 0x44020 -#define GEN6_PMIMR 0x44024 +#define GEN6_PMIMR 0x44024 /* rps_lock */ #define GEN6_PMIIR 0x44028 #define GEN6_PMIER 0x4402C #define GEN6_PM_MBOX_EVENT (1<<25) @@ -3396,6 +3426,9 @@ #define GEN6_PM_RP_DOWN_THRESHOLD (1<<4) #define GEN6_PM_RP_UP_EI_EXPIRED (1<<2) #define GEN6_PM_RP_DOWN_EI_EXPIRED (1<<1) +#define GEN6_PM_DEFERRED_EVENTS (GEN6_PM_RP_UP_THRESHOLD | \ + GEN6_PM_RP_DOWN_THRESHOLD | \ + GEN6_PM_RP_DOWN_TIMEOUT) #define GEN6_PCODE_MAILBOX 0x138124 #define GEN6_PCODE_READY (1<<31) diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index da47415..60a94d2 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -863,8 +863,7 @@ int i915_restore_state(struct drm_device *dev) I915_WRITE(IMR, dev_priv->saveIMR); } - /* Clock gating state */ - intel_enable_clock_gating(dev); + intel_init_clock_gating(dev); if (IS_IRONLAKE_M(dev)) { ironlake_enable_drps(dev); diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index d03fc05..e93f93c 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -305,13 +305,11 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector) } static enum drm_connector_status -intel_crt_load_detect(struct drm_crtc *crtc, struct intel_crt *crt) +intel_crt_load_detect(struct intel_crt *crt) { - struct drm_encoder *encoder = &crt->base.base; - struct drm_device *dev = encoder->dev; + struct drm_device *dev = crt->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - uint32_t pipe = intel_crtc->pipe; + uint32_t pipe = to_intel_crtc(crt->base.base.crtc)->pipe; uint32_t save_bclrpat; uint32_t save_vtotal; uint32_t vtotal, vactive; @@ -432,7 +430,6 @@ intel_crt_detect(struct drm_connector *connector, bool force) struct drm_device *dev = connector->dev; struct intel_crt *crt = intel_attached_crt(connector); struct drm_crtc *crtc; - int dpms_mode; enum drm_connector_status status; if (I915_HAS_HOTPLUG(dev)) { @@ -454,17 +451,18 @@ intel_crt_detect(struct drm_connector *connector, bool force) /* for pre-945g platforms use load detect */ crtc = crt->base.base.crtc; if (crtc && crtc->enabled) { - status = intel_crt_load_detect(crtc, crt); + status = intel_crt_load_detect(crt); } else { - crtc = intel_get_load_detect_pipe(&crt->base, connector, - NULL, &dpms_mode); - if (crtc) { + struct intel_load_detect_pipe tmp; + + if (intel_get_load_detect_pipe(&crt->base, connector, NULL, + &tmp)) { if (intel_crt_detect_ddc(connector)) status = connector_status_connected; else - status = intel_crt_load_detect(crtc, crt); - intel_release_load_detect_pipe(&crt->base, - connector, dpms_mode); + status = intel_crt_load_detect(crt); + intel_release_load_detect_pipe(&crt->base, connector, + &tmp); } else status = connector_status_unknown; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 21a7e70..565eb2c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -76,255 +76,6 @@ struct intel_limit { int, int, intel_clock_t *); }; -#define I8XX_DOT_MIN 25000 -#define I8XX_DOT_MAX 350000 -#define I8XX_VCO_MIN 930000 -#define I8XX_VCO_MAX 1400000 -#define I8XX_N_MIN 3 -#define I8XX_N_MAX 16 -#define I8XX_M_MIN 96 -#define I8XX_M_MAX 140 -#define I8XX_M1_MIN 18 -#define I8XX_M1_MAX 26 -#define I8XX_M2_MIN 6 -#define I8XX_M2_MAX 16 -#define I8XX_P_MIN 4 -#define I8XX_P_MAX 128 -#define I8XX_P1_MIN 2 -#define I8XX_P1_MAX 33 -#define I8XX_P1_LVDS_MIN 1 -#define I8XX_P1_LVDS_MAX 6 -#define I8XX_P2_SLOW 4 -#define I8XX_P2_FAST 2 -#define I8XX_P2_LVDS_SLOW 14 -#define I8XX_P2_LVDS_FAST 7 -#define I8XX_P2_SLOW_LIMIT 165000 - -#define I9XX_DOT_MIN 20000 -#define I9XX_DOT_MAX 400000 -#define I9XX_VCO_MIN 1400000 -#define I9XX_VCO_MAX 2800000 -#define PINEVIEW_VCO_MIN 1700000 -#define PINEVIEW_VCO_MAX 3500000 -#define I9XX_N_MIN 1 -#define I9XX_N_MAX 6 -/* Pineview's Ncounter is a ring counter */ -#define PINEVIEW_N_MIN 3 -#define PINEVIEW_N_MAX 6 -#define I9XX_M_MIN 70 -#define I9XX_M_MAX 120 -#define PINEVIEW_M_MIN 2 -#define PINEVIEW_M_MAX 256 -#define I9XX_M1_MIN 10 -#define I9XX_M1_MAX 22 -#define I9XX_M2_MIN 5 -#define I9XX_M2_MAX 9 -/* Pineview M1 is reserved, and must be 0 */ -#define PINEVIEW_M1_MIN 0 -#define PINEVIEW_M1_MAX 0 -#define PINEVIEW_M2_MIN 0 -#define PINEVIEW_M2_MAX 254 -#define I9XX_P_SDVO_DAC_MIN 5 -#define I9XX_P_SDVO_DAC_MAX 80 -#define I9XX_P_LVDS_MIN 7 -#define I9XX_P_LVDS_MAX 98 -#define PINEVIEW_P_LVDS_MIN 7 -#define PINEVIEW_P_LVDS_MAX 112 -#define I9XX_P1_MIN 1 -#define I9XX_P1_MAX 8 -#define I9XX_P2_SDVO_DAC_SLOW 10 -#define I9XX_P2_SDVO_DAC_FAST 5 -#define I9XX_P2_SDVO_DAC_SLOW_LIMIT 200000 -#define I9XX_P2_LVDS_SLOW 14 -#define I9XX_P2_LVDS_FAST 7 -#define I9XX_P2_LVDS_SLOW_LIMIT 112000 - -/*The parameter is for SDVO on G4x platform*/ -#define G4X_DOT_SDVO_MIN 25000 -#define G4X_DOT_SDVO_MAX 270000 -#define G4X_VCO_MIN 1750000 -#define G4X_VCO_MAX 3500000 -#define G4X_N_SDVO_MIN 1 -#define G4X_N_SDVO_MAX 4 -#define G4X_M_SDVO_MIN 104 -#define G4X_M_SDVO_MAX 138 -#define G4X_M1_SDVO_MIN 17 -#define G4X_M1_SDVO_MAX 23 -#define G4X_M2_SDVO_MIN 5 -#define G4X_M2_SDVO_MAX 11 -#define G4X_P_SDVO_MIN 10 -#define G4X_P_SDVO_MAX 30 -#define G4X_P1_SDVO_MIN 1 -#define G4X_P1_SDVO_MAX 3 -#define G4X_P2_SDVO_SLOW 10 -#define G4X_P2_SDVO_FAST 10 -#define G4X_P2_SDVO_LIMIT 270000 - -/*The parameter is for HDMI_DAC on G4x platform*/ -#define G4X_DOT_HDMI_DAC_MIN 22000 -#define G4X_DOT_HDMI_DAC_MAX 400000 -#define G4X_N_HDMI_DAC_MIN 1 -#define G4X_N_HDMI_DAC_MAX 4 -#define G4X_M_HDMI_DAC_MIN 104 -#define G4X_M_HDMI_DAC_MAX 138 -#define G4X_M1_HDMI_DAC_MIN 16 -#define G4X_M1_HDMI_DAC_MAX 23 -#define G4X_M2_HDMI_DAC_MIN 5 -#define G4X_M2_HDMI_DAC_MAX 11 -#define G4X_P_HDMI_DAC_MIN 5 -#define G4X_P_HDMI_DAC_MAX 80 -#define G4X_P1_HDMI_DAC_MIN 1 -#define G4X_P1_HDMI_DAC_MAX 8 -#define G4X_P2_HDMI_DAC_SLOW 10 -#define G4X_P2_HDMI_DAC_FAST 5 -#define G4X_P2_HDMI_DAC_LIMIT 165000 - -/*The parameter is for SINGLE_CHANNEL_LVDS on G4x platform*/ -#define G4X_DOT_SINGLE_CHANNEL_LVDS_MIN 20000 -#define G4X_DOT_SINGLE_CHANNEL_LVDS_MAX 115000 -#define G4X_N_SINGLE_CHANNEL_LVDS_MIN 1 -#define G4X_N_SINGLE_CHANNEL_LVDS_MAX 3 -#define G4X_M_SINGLE_CHANNEL_LVDS_MIN 104 -#define G4X_M_SINGLE_CHANNEL_LVDS_MAX 138 -#define G4X_M1_SINGLE_CHANNEL_LVDS_MIN 17 -#define G4X_M1_SINGLE_CHANNEL_LVDS_MAX 23 -#define G4X_M2_SINGLE_CHANNEL_LVDS_MIN 5 -#define G4X_M2_SINGLE_CHANNEL_LVDS_MAX 11 -#define G4X_P_SINGLE_CHANNEL_LVDS_MIN 28 -#define G4X_P_SINGLE_CHANNEL_LVDS_MAX 112 -#define G4X_P1_SINGLE_CHANNEL_LVDS_MIN 2 -#define G4X_P1_SINGLE_CHANNEL_LVDS_MAX 8 -#define G4X_P2_SINGLE_CHANNEL_LVDS_SLOW 14 -#define G4X_P2_SINGLE_CHANNEL_LVDS_FAST 14 -#define G4X_P2_SINGLE_CHANNEL_LVDS_LIMIT 0 - -/*The parameter is for DUAL_CHANNEL_LVDS on G4x platform*/ -#define G4X_DOT_DUAL_CHANNEL_LVDS_MIN 80000 -#define G4X_DOT_DUAL_CHANNEL_LVDS_MAX 224000 -#define G4X_N_DUAL_CHANNEL_LVDS_MIN 1 -#define G4X_N_DUAL_CHANNEL_LVDS_MAX 3 -#define G4X_M_DUAL_CHANNEL_LVDS_MIN 104 -#define G4X_M_DUAL_CHANNEL_LVDS_MAX 138 -#define G4X_M1_DUAL_CHANNEL_LVDS_MIN 17 -#define G4X_M1_DUAL_CHANNEL_LVDS_MAX 23 -#define G4X_M2_DUAL_CHANNEL_LVDS_MIN 5 -#define G4X_M2_DUAL_CHANNEL_LVDS_MAX 11 -#define G4X_P_DUAL_CHANNEL_LVDS_MIN 14 -#define G4X_P_DUAL_CHANNEL_LVDS_MAX 42 -#define G4X_P1_DUAL_CHANNEL_LVDS_MIN 2 -#define G4X_P1_DUAL_CHANNEL_LVDS_MAX 6 -#define G4X_P2_DUAL_CHANNEL_LVDS_SLOW 7 -#define G4X_P2_DUAL_CHANNEL_LVDS_FAST 7 -#define G4X_P2_DUAL_CHANNEL_LVDS_LIMIT 0 - -/*The parameter is for DISPLAY PORT on G4x platform*/ -#define G4X_DOT_DISPLAY_PORT_MIN 161670 -#define G4X_DOT_DISPLAY_PORT_MAX 227000 -#define G4X_N_DISPLAY_PORT_MIN 1 -#define G4X_N_DISPLAY_PORT_MAX 2 -#define G4X_M_DISPLAY_PORT_MIN 97 -#define G4X_M_DISPLAY_PORT_MAX 108 -#define G4X_M1_DISPLAY_PORT_MIN 0x10 -#define G4X_M1_DISPLAY_PORT_MAX 0x12 -#define G4X_M2_DISPLAY_PORT_MIN 0x05 -#define G4X_M2_DISPLAY_PORT_MAX 0x06 -#define G4X_P_DISPLAY_PORT_MIN 10 -#define G4X_P_DISPLAY_PORT_MAX 20 -#define G4X_P1_DISPLAY_PORT_MIN 1 -#define G4X_P1_DISPLAY_PORT_MAX 2 -#define G4X_P2_DISPLAY_PORT_SLOW 10 -#define G4X_P2_DISPLAY_PORT_FAST 10 -#define G4X_P2_DISPLAY_PORT_LIMIT 0 - -/* Ironlake / Sandybridge */ -/* as we calculate clock using (register_value + 2) for - N/M1/M2, so here the range value for them is (actual_value-2). - */ -#define IRONLAKE_DOT_MIN 25000 -#define IRONLAKE_DOT_MAX 350000 -#define IRONLAKE_VCO_MIN 1760000 -#define IRONLAKE_VCO_MAX 3510000 -#define IRONLAKE_M1_MIN 12 -#define IRONLAKE_M1_MAX 22 -#define IRONLAKE_M2_MIN 5 -#define IRONLAKE_M2_MAX 9 -#define IRONLAKE_P2_DOT_LIMIT 225000 /* 225Mhz */ - -/* We have parameter ranges for different type of outputs. */ - -/* DAC & HDMI Refclk 120Mhz */ -#define IRONLAKE_DAC_N_MIN 1 -#define IRONLAKE_DAC_N_MAX 5 -#define IRONLAKE_DAC_M_MIN 79 -#define IRONLAKE_DAC_M_MAX 127 -#define IRONLAKE_DAC_P_MIN 5 -#define IRONLAKE_DAC_P_MAX 80 -#define IRONLAKE_DAC_P1_MIN 1 -#define IRONLAKE_DAC_P1_MAX 8 -#define IRONLAKE_DAC_P2_SLOW 10 -#define IRONLAKE_DAC_P2_FAST 5 - -/* LVDS single-channel 120Mhz refclk */ -#define IRONLAKE_LVDS_S_N_MIN 1 -#define IRONLAKE_LVDS_S_N_MAX 3 -#define IRONLAKE_LVDS_S_M_MIN 79 -#define IRONLAKE_LVDS_S_M_MAX 118 -#define IRONLAKE_LVDS_S_P_MIN 28 -#define IRONLAKE_LVDS_S_P_MAX 112 -#define IRONLAKE_LVDS_S_P1_MIN 2 -#define IRONLAKE_LVDS_S_P1_MAX 8 -#define IRONLAKE_LVDS_S_P2_SLOW 14 -#define IRONLAKE_LVDS_S_P2_FAST 14 - -/* LVDS dual-channel 120Mhz refclk */ -#define IRONLAKE_LVDS_D_N_MIN 1 -#define IRONLAKE_LVDS_D_N_MAX 3 -#define IRONLAKE_LVDS_D_M_MIN 79 -#define IRONLAKE_LVDS_D_M_MAX 127 -#define IRONLAKE_LVDS_D_P_MIN 14 -#define IRONLAKE_LVDS_D_P_MAX 56 -#define IRONLAKE_LVDS_D_P1_MIN 2 -#define IRONLAKE_LVDS_D_P1_MAX 8 -#define IRONLAKE_LVDS_D_P2_SLOW 7 -#define IRONLAKE_LVDS_D_P2_FAST 7 - -/* LVDS single-channel 100Mhz refclk */ -#define IRONLAKE_LVDS_S_SSC_N_MIN 1 -#define IRONLAKE_LVDS_S_SSC_N_MAX 2 -#define IRONLAKE_LVDS_S_SSC_M_MIN 79 -#define IRONLAKE_LVDS_S_SSC_M_MAX 126 -#define IRONLAKE_LVDS_S_SSC_P_MIN 28 -#define IRONLAKE_LVDS_S_SSC_P_MAX 112 -#define IRONLAKE_LVDS_S_SSC_P1_MIN 2 -#define IRONLAKE_LVDS_S_SSC_P1_MAX 8 -#define IRONLAKE_LVDS_S_SSC_P2_SLOW 14 -#define IRONLAKE_LVDS_S_SSC_P2_FAST 14 - -/* LVDS dual-channel 100Mhz refclk */ -#define IRONLAKE_LVDS_D_SSC_N_MIN 1 -#define IRONLAKE_LVDS_D_SSC_N_MAX 3 -#define IRONLAKE_LVDS_D_SSC_M_MIN 79 -#define IRONLAKE_LVDS_D_SSC_M_MAX 126 -#define IRONLAKE_LVDS_D_SSC_P_MIN 14 -#define IRONLAKE_LVDS_D_SSC_P_MAX 42 -#define IRONLAKE_LVDS_D_SSC_P1_MIN 2 -#define IRONLAKE_LVDS_D_SSC_P1_MAX 6 -#define IRONLAKE_LVDS_D_SSC_P2_SLOW 7 -#define IRONLAKE_LVDS_D_SSC_P2_FAST 7 - -/* DisplayPort */ -#define IRONLAKE_DP_N_MIN 1 -#define IRONLAKE_DP_N_MAX 2 -#define IRONLAKE_DP_M_MIN 81 -#define IRONLAKE_DP_M_MAX 90 -#define IRONLAKE_DP_P_MIN 10 -#define IRONLAKE_DP_P_MAX 20 -#define IRONLAKE_DP_P2_FAST 10 -#define IRONLAKE_DP_P2_SLOW 10 -#define IRONLAKE_DP_P2_LIMIT 0 -#define IRONLAKE_DP_P1_MIN 1 -#define IRONLAKE_DP_P1_MAX 2 - /* FDI */ #define IRONLAKE_FDI_FREQ 2700000 /* in kHz for mode->clock */ @@ -353,292 +104,253 @@ intel_fdi_link_freq(struct drm_device *dev) } static const intel_limit_t intel_limits_i8xx_dvo = { - .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, - .vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX }, - .n = { .min = I8XX_N_MIN, .max = I8XX_N_MAX }, - .m = { .min = I8XX_M_MIN, .max = I8XX_M_MAX }, - .m1 = { .min = I8XX_M1_MIN, .max = I8XX_M1_MAX }, - .m2 = { .min = I8XX_M2_MIN, .max = I8XX_M2_MAX }, - .p = { .min = I8XX_P_MIN, .max = I8XX_P_MAX }, - .p1 = { .min = I8XX_P1_MIN, .max = I8XX_P1_MAX }, - .p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT, - .p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST }, + .dot = { .min = 25000, .max = 350000 }, + .vco = { .min = 930000, .max = 1400000 }, + .n = { .min = 3, .max = 16 }, + .m = { .min = 96, .max = 140 }, + .m1 = { .min = 18, .max = 26 }, + .m2 = { .min = 6, .max = 16 }, + .p = { .min = 4, .max = 128 }, + .p1 = { .min = 2, .max = 33 }, + .p2 = { .dot_limit = 165000, + .p2_slow = 4, .p2_fast = 2 }, .find_pll = intel_find_best_PLL, }; static const intel_limit_t intel_limits_i8xx_lvds = { - .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, - .vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX }, - .n = { .min = I8XX_N_MIN, .max = I8XX_N_MAX }, - .m = { .min = I8XX_M_MIN, .max = I8XX_M_MAX }, - .m1 = { .min = I8XX_M1_MIN, .max = I8XX_M1_MAX }, - .m2 = { .min = I8XX_M2_MIN, .max = I8XX_M2_MAX }, - .p = { .min = I8XX_P_MIN, .max = I8XX_P_MAX }, - .p1 = { .min = I8XX_P1_LVDS_MIN, .max = I8XX_P1_LVDS_MAX }, - .p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT, - .p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST }, + .dot = { .min = 25000, .max = 350000 }, + .vco = { .min = 930000, .max = 1400000 }, + .n = { .min = 3, .max = 16 }, + .m = { .min = 96, .max = 140 }, + .m1 = { .min = 18, .max = 26 }, + .m2 = { .min = 6, .max = 16 }, + .p = { .min = 4, .max = 128 }, + .p1 = { .min = 1, .max = 6 }, + .p2 = { .dot_limit = 165000, + .p2_slow = 14, .p2_fast = 7 }, .find_pll = intel_find_best_PLL, }; - + static const intel_limit_t intel_limits_i9xx_sdvo = { - .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, - .vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX }, - .n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX }, - .m = { .min = I9XX_M_MIN, .max = I9XX_M_MAX }, - .m1 = { .min = I9XX_M1_MIN, .max = I9XX_M1_MAX }, - .m2 = { .min = I9XX_M2_MIN, .max = I9XX_M2_MAX }, - .p = { .min = I9XX_P_SDVO_DAC_MIN, .max = I9XX_P_SDVO_DAC_MAX }, - .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX }, - .p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT, - .p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST }, + .dot = { .min = 20000, .max = 400000 }, + .vco = { .min = 1400000, .max = 2800000 }, + .n = { .min = 1, .max = 6 }, + .m = { .min = 70, .max = 120 }, + .m1 = { .min = 10, .max = 22 }, + .m2 = { .min = 5, .max = 9 }, + .p = { .min = 5, .max = 80 }, + .p1 = { .min = 1, .max = 8 }, + .p2 = { .dot_limit = 200000, + .p2_slow = 10, .p2_fast = 5 }, .find_pll = intel_find_best_PLL, }; static const intel_limit_t intel_limits_i9xx_lvds = { - .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, - .vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX }, - .n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX }, - .m = { .min = I9XX_M_MIN, .max = I9XX_M_MAX }, - .m1 = { .min = I9XX_M1_MIN, .max = I9XX_M1_MAX }, - .m2 = { .min = I9XX_M2_MIN, .max = I9XX_M2_MAX }, - .p = { .min = I9XX_P_LVDS_MIN, .max = I9XX_P_LVDS_MAX }, - .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX }, - /* The single-channel range is 25-112Mhz, and dual-channel - * is 80-224Mhz. Prefer single channel as much as possible. - */ - .p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT, - .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST }, + .dot = { .min = 20000, .max = 400000 }, + .vco = { .min = 1400000, .max = 2800000 }, + .n = { .min = 1, .max = 6 }, + .m = { .min = 70, .max = 120 }, + .m1 = { .min = 10, .max = 22 }, + .m2 = { .min = 5, .max = 9 }, + .p = { .min = 7, .max = 98 }, + .p1 = { .min = 1, .max = 8 }, + .p2 = { .dot_limit = 112000, + .p2_slow = 14, .p2_fast = 7 }, .find_pll = intel_find_best_PLL, }; - /* below parameter and function is for G4X Chipset Family*/ + static const intel_limit_t intel_limits_g4x_sdvo = { - .dot = { .min = G4X_DOT_SDVO_MIN, .max = G4X_DOT_SDVO_MAX }, - .vco = { .min = G4X_VCO_MIN, .max = G4X_VCO_MAX}, - .n = { .min = G4X_N_SDVO_MIN, .max = G4X_N_SDVO_MAX }, - .m = { .min = G4X_M_SDVO_MIN, .max = G4X_M_SDVO_MAX }, - .m1 = { .min = G4X_M1_SDVO_MIN, .max = G4X_M1_SDVO_MAX }, - .m2 = { .min = G4X_M2_SDVO_MIN, .max = G4X_M2_SDVO_MAX }, - .p = { .min = G4X_P_SDVO_MIN, .max = G4X_P_SDVO_MAX }, - .p1 = { .min = G4X_P1_SDVO_MIN, .max = G4X_P1_SDVO_MAX}, - .p2 = { .dot_limit = G4X_P2_SDVO_LIMIT, - .p2_slow = G4X_P2_SDVO_SLOW, - .p2_fast = G4X_P2_SDVO_FAST + .dot = { .min = 25000, .max = 270000 }, + .vco = { .min = 1750000, .max = 3500000}, + .n = { .min = 1, .max = 4 }, + .m = { .min = 104, .max = 138 }, + .m1 = { .min = 17, .max = 23 }, + .m2 = { .min = 5, .max = 11 }, + .p = { .min = 10, .max = 30 }, + .p1 = { .min = 1, .max = 3}, + .p2 = { .dot_limit = 270000, + .p2_slow = 10, + .p2_fast = 10 }, .find_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_g4x_hdmi = { - .dot = { .min = G4X_DOT_HDMI_DAC_MIN, .max = G4X_DOT_HDMI_DAC_MAX }, - .vco = { .min = G4X_VCO_MIN, .max = G4X_VCO_MAX}, - .n = { .min = G4X_N_HDMI_DAC_MIN, .max = G4X_N_HDMI_DAC_MAX }, - .m = { .min = G4X_M_HDMI_DAC_MIN, .max = G4X_M_HDMI_DAC_MAX }, - .m1 = { .min = G4X_M1_HDMI_DAC_MIN, .max = G4X_M1_HDMI_DAC_MAX }, - .m2 = { .min = G4X_M2_HDMI_DAC_MIN, .max = G4X_M2_HDMI_DAC_MAX }, - .p = { .min = G4X_P_HDMI_DAC_MIN, .max = G4X_P_HDMI_DAC_MAX }, - .p1 = { .min = G4X_P1_HDMI_DAC_MIN, .max = G4X_P1_HDMI_DAC_MAX}, - .p2 = { .dot_limit = G4X_P2_HDMI_DAC_LIMIT, - .p2_slow = G4X_P2_HDMI_DAC_SLOW, - .p2_fast = G4X_P2_HDMI_DAC_FAST - }, + .dot = { .min = 22000, .max = 400000 }, + .vco = { .min = 1750000, .max = 3500000}, + .n = { .min = 1, .max = 4 }, + .m = { .min = 104, .max = 138 }, + .m1 = { .min = 16, .max = 23 }, + .m2 = { .min = 5, .max = 11 }, + .p = { .min = 5, .max = 80 }, + .p1 = { .min = 1, .max = 8}, + .p2 = { .dot_limit = 165000, + .p2_slow = 10, .p2_fast = 5 }, .find_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_g4x_single_channel_lvds = { - .dot = { .min = G4X_DOT_SINGLE_CHANNEL_LVDS_MIN, - .max = G4X_DOT_SINGLE_CHANNEL_LVDS_MAX }, - .vco = { .min = G4X_VCO_MIN, - .max = G4X_VCO_MAX }, - .n = { .min = G4X_N_SINGLE_CHANNEL_LVDS_MIN, - .max = G4X_N_SINGLE_CHANNEL_LVDS_MAX }, - .m = { .min = G4X_M_SINGLE_CHANNEL_LVDS_MIN, - .max = G4X_M_SINGLE_CHANNEL_LVDS_MAX }, - .m1 = { .min = G4X_M1_SINGLE_CHANNEL_LVDS_MIN, - .max = G4X_M1_SINGLE_CHANNEL_LVDS_MAX }, - .m2 = { .min = G4X_M2_SINGLE_CHANNEL_LVDS_MIN, - .max = G4X_M2_SINGLE_CHANNEL_LVDS_MAX }, - .p = { .min = G4X_P_SINGLE_CHANNEL_LVDS_MIN, - .max = G4X_P_SINGLE_CHANNEL_LVDS_MAX }, - .p1 = { .min = G4X_P1_SINGLE_CHANNEL_LVDS_MIN, - .max = G4X_P1_SINGLE_CHANNEL_LVDS_MAX }, - .p2 = { .dot_limit = G4X_P2_SINGLE_CHANNEL_LVDS_LIMIT, - .p2_slow = G4X_P2_SINGLE_CHANNEL_LVDS_SLOW, - .p2_fast = G4X_P2_SINGLE_CHANNEL_LVDS_FAST + .dot = { .min = 20000, .max = 115000 }, + .vco = { .min = 1750000, .max = 3500000 }, + .n = { .min = 1, .max = 3 }, + .m = { .min = 104, .max = 138 }, + .m1 = { .min = 17, .max = 23 }, + .m2 = { .min = 5, .max = 11 }, + .p = { .min = 28, .max = 112 }, + .p1 = { .min = 2, .max = 8 }, + .p2 = { .dot_limit = 0, + .p2_slow = 14, .p2_fast = 14 }, .find_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_g4x_dual_channel_lvds = { - .dot = { .min = G4X_DOT_DUAL_CHANNEL_LVDS_MIN, - .max = G4X_DOT_DUAL_CHANNEL_LVDS_MAX }, - .vco = { .min = G4X_VCO_MIN, - .max = G4X_VCO_MAX }, - .n = { .min = G4X_N_DUAL_CHANNEL_LVDS_MIN, - .max = G4X_N_DUAL_CHANNEL_LVDS_MAX }, - .m = { .min = G4X_M_DUAL_CHANNEL_LVDS_MIN, - .max = G4X_M_DUAL_CHANNEL_LVDS_MAX }, - .m1 = { .min = G4X_M1_DUAL_CHANNEL_LVDS_MIN, - .max = G4X_M1_DUAL_CHANNEL_LVDS_MAX }, - .m2 = { .min = G4X_M2_DUAL_CHANNEL_LVDS_MIN, - .max = G4X_M2_DUAL_CHANNEL_LVDS_MAX }, - .p = { .min = G4X_P_DUAL_CHANNEL_LVDS_MIN, - .max = G4X_P_DUAL_CHANNEL_LVDS_MAX }, - .p1 = { .min = G4X_P1_DUAL_CHANNEL_LVDS_MIN, - .max = G4X_P1_DUAL_CHANNEL_LVDS_MAX }, - .p2 = { .dot_limit = G4X_P2_DUAL_CHANNEL_LVDS_LIMIT, - .p2_slow = G4X_P2_DUAL_CHANNEL_LVDS_SLOW, - .p2_fast = G4X_P2_DUAL_CHANNEL_LVDS_FAST + .dot = { .min = 80000, .max = 224000 }, + .vco = { .min = 1750000, .max = 3500000 }, + .n = { .min = 1, .max = 3 }, + .m = { .min = 104, .max = 138 }, + .m1 = { .min = 17, .max = 23 }, + .m2 = { .min = 5, .max = 11 }, + .p = { .min = 14, .max = 42 }, + .p1 = { .min = 2, .max = 6 }, + .p2 = { .dot_limit = 0, + .p2_slow = 7, .p2_fast = 7 }, .find_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_g4x_display_port = { - .dot = { .min = G4X_DOT_DISPLAY_PORT_MIN, - .max = G4X_DOT_DISPLAY_PORT_MAX }, - .vco = { .min = G4X_VCO_MIN, - .max = G4X_VCO_MAX}, - .n = { .min = G4X_N_DISPLAY_PORT_MIN, - .max = G4X_N_DISPLAY_PORT_MAX }, - .m = { .min = G4X_M_DISPLAY_PORT_MIN, - .max = G4X_M_DISPLAY_PORT_MAX }, - .m1 = { .min = G4X_M1_DISPLAY_PORT_MIN, - .max = G4X_M1_DISPLAY_PORT_MAX }, - .m2 = { .min = G4X_M2_DISPLAY_PORT_MIN, - .max = G4X_M2_DISPLAY_PORT_MAX }, - .p = { .min = G4X_P_DISPLAY_PORT_MIN, - .max = G4X_P_DISPLAY_PORT_MAX }, - .p1 = { .min = G4X_P1_DISPLAY_PORT_MIN, - .max = G4X_P1_DISPLAY_PORT_MAX}, - .p2 = { .dot_limit = G4X_P2_DISPLAY_PORT_LIMIT, - .p2_slow = G4X_P2_DISPLAY_PORT_SLOW, - .p2_fast = G4X_P2_DISPLAY_PORT_FAST }, + .dot = { .min = 161670, .max = 227000 }, + .vco = { .min = 1750000, .max = 3500000}, + .n = { .min = 1, .max = 2 }, + .m = { .min = 97, .max = 108 }, + .m1 = { .min = 0x10, .max = 0x12 }, + .m2 = { .min = 0x05, .max = 0x06 }, + .p = { .min = 10, .max = 20 }, + .p1 = { .min = 1, .max = 2}, + .p2 = { .dot_limit = 0, + .p2_slow = 10, .p2_fast = 10 }, .find_pll = intel_find_pll_g4x_dp, }; static const intel_limit_t intel_limits_pineview_sdvo = { - .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX}, - .vco = { .min = PINEVIEW_VCO_MIN, .max = PINEVIEW_VCO_MAX }, - .n = { .min = PINEVIEW_N_MIN, .max = PINEVIEW_N_MAX }, - .m = { .min = PINEVIEW_M_MIN, .max = PINEVIEW_M_MAX }, - .m1 = { .min = PINEVIEW_M1_MIN, .max = PINEVIEW_M1_MAX }, - .m2 = { .min = PINEVIEW_M2_MIN, .max = PINEVIEW_M2_MAX }, - .p = { .min = I9XX_P_SDVO_DAC_MIN, .max = I9XX_P_SDVO_DAC_MAX }, - .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX }, - .p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT, - .p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST }, + .dot = { .min = 20000, .max = 400000}, + .vco = { .min = 1700000, .max = 3500000 }, + /* Pineview's Ncounter is a ring counter */ + .n = { .min = 3, .max = 6 }, + .m = { .min = 2, .max = 256 }, + /* Pineview only has one combined m divider, which we treat as m2. */ + .m1 = { .min = 0, .max = 0 }, + .m2 = { .min = 0, .max = 254 }, + .p = { .min = 5, .max = 80 }, + .p1 = { .min = 1, .max = 8 }, + .p2 = { .dot_limit = 200000, + .p2_slow = 10, .p2_fast = 5 }, .find_pll = intel_find_best_PLL, }; static const intel_limit_t intel_limits_pineview_lvds = { - .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, - .vco = { .min = PINEVIEW_VCO_MIN, .max = PINEVIEW_VCO_MAX }, - .n = { .min = PINEVIEW_N_MIN, .max = PINEVIEW_N_MAX }, - .m = { .min = PINEVIEW_M_MIN, .max = PINEVIEW_M_MAX }, - .m1 = { .min = PINEVIEW_M1_MIN, .max = PINEVIEW_M1_MAX }, - .m2 = { .min = PINEVIEW_M2_MIN, .max = PINEVIEW_M2_MAX }, - .p = { .min = PINEVIEW_P_LVDS_MIN, .max = PINEVIEW_P_LVDS_MAX }, - .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX }, - /* Pineview only supports single-channel mode. */ - .p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT, - .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_SLOW }, + .dot = { .min = 20000, .max = 400000 }, + .vco = { .min = 1700000, .max = 3500000 }, + .n = { .min = 3, .max = 6 }, + .m = { .min = 2, .max = 256 }, + .m1 = { .min = 0, .max = 0 }, + .m2 = { .min = 0, .max = 254 }, + .p = { .min = 7, .max = 112 }, + .p1 = { .min = 1, .max = 8 }, + .p2 = { .dot_limit = 112000, + .p2_slow = 14, .p2_fast = 14 }, .find_pll = intel_find_best_PLL, }; +/* Ironlake / Sandybridge + * + * We calculate clock using (register_value + 2) for N/M1/M2, so here + * the range value for them is (actual_value - 2). + */ static const intel_limit_t intel_limits_ironlake_dac = { - .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, - .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, - .n = { .min = IRONLAKE_DAC_N_MIN, .max = IRONLAKE_DAC_N_MAX }, - .m = { .min = IRONLAKE_DAC_M_MIN, .max = IRONLAKE_DAC_M_MAX }, - .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, - .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, - .p = { .min = IRONLAKE_DAC_P_MIN, .max = IRONLAKE_DAC_P_MAX }, - .p1 = { .min = IRONLAKE_DAC_P1_MIN, .max = IRONLAKE_DAC_P1_MAX }, - .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, - .p2_slow = IRONLAKE_DAC_P2_SLOW, - .p2_fast = IRONLAKE_DAC_P2_FAST }, + .dot = { .min = 25000, .max = 350000 }, + .vco = { .min = 1760000, .max = 3510000 }, + .n = { .min = 1, .max = 5 }, + .m = { .min = 79, .max = 127 }, + .m1 = { .min = 12, .max = 22 }, + .m2 = { .min = 5, .max = 9 }, + .p = { .min = 5, .max = 80 }, + .p1 = { .min = 1, .max = 8 }, + .p2 = { .dot_limit = 225000, + .p2_slow = 10, .p2_fast = 5 }, .find_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_ironlake_single_lvds = { - .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, - .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, - .n = { .min = IRONLAKE_LVDS_S_N_MIN, .max = IRONLAKE_LVDS_S_N_MAX }, - .m = { .min = IRONLAKE_LVDS_S_M_MIN, .max = IRONLAKE_LVDS_S_M_MAX }, - .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, - .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, - .p = { .min = IRONLAKE_LVDS_S_P_MIN, .max = IRONLAKE_LVDS_S_P_MAX }, - .p1 = { .min = IRONLAKE_LVDS_S_P1_MIN, .max = IRONLAKE_LVDS_S_P1_MAX }, - .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, - .p2_slow = IRONLAKE_LVDS_S_P2_SLOW, - .p2_fast = IRONLAKE_LVDS_S_P2_FAST }, + .dot = { .min = 25000, .max = 350000 }, + .vco = { .min = 1760000, .max = 3510000 }, + .n = { .min = 1, .max = 3 }, + .m = { .min = 79, .max = 118 }, + .m1 = { .min = 12, .max = 22 }, + .m2 = { .min = 5, .max = 9 }, + .p = { .min = 28, .max = 112 }, + .p1 = { .min = 2, .max = 8 }, + .p2 = { .dot_limit = 225000, + .p2_slow = 14, .p2_fast = 14 }, .find_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_ironlake_dual_lvds = { - .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, - .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, - .n = { .min = IRONLAKE_LVDS_D_N_MIN, .max = IRONLAKE_LVDS_D_N_MAX }, - .m = { .min = IRONLAKE_LVDS_D_M_MIN, .max = IRONLAKE_LVDS_D_M_MAX }, - .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, - .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, - .p = { .min = IRONLAKE_LVDS_D_P_MIN, .max = IRONLAKE_LVDS_D_P_MAX }, - .p1 = { .min = IRONLAKE_LVDS_D_P1_MIN, .max = IRONLAKE_LVDS_D_P1_MAX }, - .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, - .p2_slow = IRONLAKE_LVDS_D_P2_SLOW, - .p2_fast = IRONLAKE_LVDS_D_P2_FAST }, + .dot = { .min = 25000, .max = 350000 }, + .vco = { .min = 1760000, .max = 3510000 }, + .n = { .min = 1, .max = 3 }, + .m = { .min = 79, .max = 127 }, + .m1 = { .min = 12, .max = 22 }, + .m2 = { .min = 5, .max = 9 }, + .p = { .min = 14, .max = 56 }, + .p1 = { .min = 2, .max = 8 }, + .p2 = { .dot_limit = 225000, + .p2_slow = 7, .p2_fast = 7 }, .find_pll = intel_g4x_find_best_PLL, }; +/* LVDS 100mhz refclk limits. */ static const intel_limit_t intel_limits_ironlake_single_lvds_100m = { - .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, - .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, - .n = { .min = IRONLAKE_LVDS_S_SSC_N_MIN, .max = IRONLAKE_LVDS_S_SSC_N_MAX }, - .m = { .min = IRONLAKE_LVDS_S_SSC_M_MIN, .max = IRONLAKE_LVDS_S_SSC_M_MAX }, - .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, - .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, - .p = { .min = IRONLAKE_LVDS_S_SSC_P_MIN, .max = IRONLAKE_LVDS_S_SSC_P_MAX }, - .p1 = { .min = IRONLAKE_LVDS_S_SSC_P1_MIN,.max = IRONLAKE_LVDS_S_SSC_P1_MAX }, - .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, - .p2_slow = IRONLAKE_LVDS_S_SSC_P2_SLOW, - .p2_fast = IRONLAKE_LVDS_S_SSC_P2_FAST }, + .dot = { .min = 25000, .max = 350000 }, + .vco = { .min = 1760000, .max = 3510000 }, + .n = { .min = 1, .max = 2 }, + .m = { .min = 79, .max = 126 }, + .m1 = { .min = 12, .max = 22 }, + .m2 = { .min = 5, .max = 9 }, + .p = { .min = 28, .max = 112 }, + .p1 = { .min = 2,.max = 8 }, + .p2 = { .dot_limit = 225000, + .p2_slow = 14, .p2_fast = 14 }, .find_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = { - .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX }, - .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX }, - .n = { .min = IRONLAKE_LVDS_D_SSC_N_MIN, .max = IRONLAKE_LVDS_D_SSC_N_MAX }, - .m = { .min = IRONLAKE_LVDS_D_SSC_M_MIN, .max = IRONLAKE_LVDS_D_SSC_M_MAX }, - .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX }, - .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX }, - .p = { .min = IRONLAKE_LVDS_D_SSC_P_MIN, .max = IRONLAKE_LVDS_D_SSC_P_MAX }, - .p1 = { .min = IRONLAKE_LVDS_D_SSC_P1_MIN,.max = IRONLAKE_LVDS_D_SSC_P1_MAX }, - .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT, - .p2_slow = IRONLAKE_LVDS_D_SSC_P2_SLOW, - .p2_fast = IRONLAKE_LVDS_D_SSC_P2_FAST }, + .dot = { .min = 25000, .max = 350000 }, + .vco = { .min = 1760000, .max = 3510000 }, + .n = { .min = 1, .max = 3 }, + .m = { .min = 79, .max = 126 }, + .m1 = { .min = 12, .max = 22 }, + .m2 = { .min = 5, .max = 9 }, + .p = { .min = 14, .max = 42 }, + .p1 = { .min = 2,.max = 6 }, + .p2 = { .dot_limit = 225000, + .p2_slow = 7, .p2_fast = 7 }, .find_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_ironlake_display_port = { - .dot = { .min = IRONLAKE_DOT_MIN, - .max = IRONLAKE_DOT_MAX }, - .vco = { .min = IRONLAKE_VCO_MIN, - .max = IRONLAKE_VCO_MAX}, - .n = { .min = IRONLAKE_DP_N_MIN, - .max = IRONLAKE_DP_N_MAX }, - .m = { .min = IRONLAKE_DP_M_MIN, - .max = IRONLAKE_DP_M_MAX }, - .m1 = { .min = IRONLAKE_M1_MIN, - .max = IRONLAKE_M1_MAX }, - .m2 = { .min = IRONLAKE_M2_MIN, - .max = IRONLAKE_M2_MAX }, - .p = { .min = IRONLAKE_DP_P_MIN, - .max = IRONLAKE_DP_P_MAX }, - .p1 = { .min = IRONLAKE_DP_P1_MIN, - .max = IRONLAKE_DP_P1_MAX}, - .p2 = { .dot_limit = IRONLAKE_DP_P2_LIMIT, - .p2_slow = IRONLAKE_DP_P2_SLOW, - .p2_fast = IRONLAKE_DP_P2_FAST }, + .dot = { .min = 25000, .max = 350000 }, + .vco = { .min = 1760000, .max = 3510000}, + .n = { .min = 1, .max = 2 }, + .m = { .min = 81, .max = 90 }, + .m1 = { .min = 12, .max = 22 }, + .m2 = { .min = 5, .max = 9 }, + .p = { .min = 10, .max = 20 }, + .p1 = { .min = 1, .max = 2}, + .p2 = { .dot_limit = 0, + .p2_slow = 10, .p2_fast = 10 }, .find_pll = intel_find_pll_ironlake_dp, }; @@ -1828,7 +1540,7 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev) u32 blt_ecoskpd; /* Make sure blitter notifies FBC of writes */ - __gen6_gt_force_wake_get(dev_priv); + gen6_gt_force_wake_get(dev_priv); blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD); blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY << GEN6_BLITTER_LOCK_SHIFT; @@ -1839,7 +1551,7 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev) GEN6_BLITTER_LOCK_SHIFT); I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); POSTING_READ(GEN6_BLITTER_ECOSKPD); - __gen6_gt_force_wake_put(dev_priv); + gen6_gt_force_wake_put(dev_priv); } static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) @@ -2339,8 +2051,13 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc) /* enable normal train */ reg = FDI_TX_CTL(pipe); temp = I915_READ(reg); - temp &= ~FDI_LINK_TRAIN_NONE; - temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE; + if (IS_GEN6(dev)) { + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE; + } else if (IS_IVYBRIDGE(dev)) { + temp &= ~FDI_LINK_TRAIN_NONE_IVB; + temp |= FDI_LINK_TRAIN_NONE_IVB | FDI_TX_ENHANCE_FRAME_ENABLE; + } I915_WRITE(reg, temp); reg = FDI_RX_CTL(pipe); @@ -2357,6 +2074,11 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc) /* wait one idle pattern time */ POSTING_READ(reg); udelay(1000); + + /* IVB wants error correction enabled */ + if (IS_IVYBRIDGE(dev)) + I915_WRITE(reg, I915_READ(reg) | FDI_FS_ERRC_ENABLE | + FDI_FE_ERRC_ENABLE); } /* The FDI link training functions for ILK/Ibexpeak. */ @@ -2584,7 +2306,116 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) DRM_DEBUG_KMS("FDI train done.\n"); } -static void ironlake_fdi_enable(struct drm_crtc *crtc) +/* Manual link training for Ivy Bridge A0 parts */ +static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + u32 reg, temp, i; + + /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit + for train result */ + reg = FDI_RX_IMR(pipe); + temp = I915_READ(reg); + temp &= ~FDI_RX_SYMBOL_LOCK; + temp &= ~FDI_RX_BIT_LOCK; + I915_WRITE(reg, temp); + + POSTING_READ(reg); + udelay(150); + + /* enable CPU FDI TX and PCH FDI RX */ + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~(7 << 19); + temp |= (intel_crtc->fdi_lanes - 1) << 19; + temp &= ~(FDI_LINK_TRAIN_AUTO | FDI_LINK_TRAIN_NONE_IVB); + temp |= FDI_LINK_TRAIN_PATTERN_1_IVB; + temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; + temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B; + I915_WRITE(reg, temp | FDI_TX_ENABLE); + + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~FDI_LINK_TRAIN_AUTO; + temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; + temp |= FDI_LINK_TRAIN_PATTERN_1_CPT; + I915_WRITE(reg, temp | FDI_RX_ENABLE); + + POSTING_READ(reg); + udelay(150); + + for (i = 0; i < 4; i++ ) { + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; + temp |= snb_b_fdi_train_param[i]; + I915_WRITE(reg, temp); + + POSTING_READ(reg); + udelay(500); + + reg = FDI_RX_IIR(pipe); + temp = I915_READ(reg); + DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); + + if (temp & FDI_RX_BIT_LOCK || + (I915_READ(reg) & FDI_RX_BIT_LOCK)) { + I915_WRITE(reg, temp | FDI_RX_BIT_LOCK); + DRM_DEBUG_KMS("FDI train 1 done.\n"); + break; + } + } + if (i == 4) + DRM_ERROR("FDI train 1 fail!\n"); + + /* Train 2 */ + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~FDI_LINK_TRAIN_NONE_IVB; + temp |= FDI_LINK_TRAIN_PATTERN_2_IVB; + temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; + temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B; + I915_WRITE(reg, temp); + + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; + temp |= FDI_LINK_TRAIN_PATTERN_2_CPT; + I915_WRITE(reg, temp); + + POSTING_READ(reg); + udelay(150); + + for (i = 0; i < 4; i++ ) { + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; + temp |= snb_b_fdi_train_param[i]; + I915_WRITE(reg, temp); + + POSTING_READ(reg); + udelay(500); + + reg = FDI_RX_IIR(pipe); + temp = I915_READ(reg); + DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); + + if (temp & FDI_RX_SYMBOL_LOCK) { + I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK); + DRM_DEBUG_KMS("FDI train 2 done.\n"); + break; + } + } + if (i == 4) + DRM_ERROR("FDI train 2 fail!\n"); + + DRM_DEBUG_KMS("FDI train done.\n"); +} + +static void ironlake_fdi_pll_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -2757,10 +2588,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) u32 reg, temp; /* For PCH output, training FDI link */ - if (IS_GEN6(dev)) - gen6_fdi_link_train(crtc); - else - ironlake_fdi_link_train(crtc); + dev_priv->display.fdi_link_train(crtc); intel_enable_pch_pll(dev_priv, pipe); @@ -2850,7 +2678,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) is_pch_port = intel_crtc_driving_pch(crtc); if (is_pch_port) - ironlake_fdi_enable(crtc); + ironlake_fdi_pll_enable(crtc); else ironlake_fdi_disable(crtc); @@ -2873,7 +2701,11 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) ironlake_pch_enable(crtc); intel_crtc_load_lut(crtc); + + mutex_lock(&dev->struct_mutex); intel_update_fbc(dev); + mutex_unlock(&dev->struct_mutex); + intel_crtc_update_cursor(crtc, true); } @@ -2969,8 +2801,11 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) intel_crtc->active = false; intel_update_watermarks(dev); + + mutex_lock(&dev->struct_mutex); intel_update_fbc(dev); intel_clear_scanline_wait(dev); + mutex_unlock(&dev->struct_mutex); } static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) @@ -4516,34 +4351,28 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) return dev_priv->lvds_use_ssc && i915_panel_use_ssc; } -static int intel_crtc_mode_set(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, - int x, int y, - struct drm_framebuffer *old_fb) +static int i9xx_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, + struct drm_framebuffer *old_fb) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - u32 fp_reg, dpll_reg; int refclk, num_connectors = 0; intel_clock_t clock, reduced_clock; u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf; bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false; bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false; - struct intel_encoder *has_edp_encoder = NULL; struct drm_mode_config *mode_config = &dev->mode_config; struct intel_encoder *encoder; const intel_limit_t *limit; int ret; - struct fdi_m_n m_n = {0}; - u32 reg, temp; + u32 temp; u32 lvds_sync = 0; - int target_clock; - - drm_vblank_pre_modeset(dev, pipe); list_for_each_entry(encoder, &mode_config->encoder_list, base.head) { if (encoder->base.crtc != crtc) @@ -4571,9 +4400,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, case INTEL_OUTPUT_DISPLAYPORT: is_dp = true; break; - case INTEL_OUTPUT_EDP: - has_edp_encoder = encoder; - break; } num_connectors++; @@ -4585,9 +4411,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, refclk / 1000); } else if (!IS_GEN2(dev)) { refclk = 96000; - if (HAS_PCH_SPLIT(dev) && - (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base))) - refclk = 120000; /* 120Mhz refclk */ } else { refclk = 48000; } @@ -4601,7 +4424,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock); if (!ok) { DRM_ERROR("Couldn't find PLL settings for mode!\n"); - drm_vblank_post_modeset(dev, pipe); return -EINVAL; } @@ -4645,143 +4467,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } } - /* FDI link */ - if (HAS_PCH_SPLIT(dev)) { - int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); - int lane = 0, link_bw, bpp; - /* CPU eDP doesn't require FDI link, so just set DP M/N - according to current link config */ - if (has_edp_encoder && !intel_encoder_is_pch_edp(&has_edp_encoder->base)) { - target_clock = mode->clock; - intel_edp_link_config(has_edp_encoder, - &lane, &link_bw); - } else { - /* [e]DP over FDI requires target mode clock - instead of link clock */ - if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) - target_clock = mode->clock; - else - target_clock = adjusted_mode->clock; - - /* FDI is a binary signal running at ~2.7GHz, encoding - * each output octet as 10 bits. The actual frequency - * is stored as a divider into a 100MHz clock, and the - * mode pixel clock is stored in units of 1KHz. - * Hence the bw of each lane in terms of the mode signal - * is: - */ - link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10; - } - - /* determine panel color depth */ - temp = I915_READ(PIPECONF(pipe)); - temp &= ~PIPE_BPC_MASK; - if (is_lvds) { - /* the BPC will be 6 if it is 18-bit LVDS panel */ - if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP) - temp |= PIPE_8BPC; - else - temp |= PIPE_6BPC; - } else if (has_edp_encoder) { - switch (dev_priv->edp.bpp/3) { - case 8: - temp |= PIPE_8BPC; - break; - case 10: - temp |= PIPE_10BPC; - break; - case 6: - temp |= PIPE_6BPC; - break; - case 12: - temp |= PIPE_12BPC; - break; - } - } else - temp |= PIPE_8BPC; - I915_WRITE(PIPECONF(pipe), temp); - - switch (temp & PIPE_BPC_MASK) { - case PIPE_8BPC: - bpp = 24; - break; - case PIPE_10BPC: - bpp = 30; - break; - case PIPE_6BPC: - bpp = 18; - break; - case PIPE_12BPC: - bpp = 36; - break; - default: - DRM_ERROR("unknown pipe bpc value\n"); - bpp = 24; - } - - if (!lane) { - /* - * Account for spread spectrum to avoid - * oversubscribing the link. Max center spread - * is 2.5%; use 5% for safety's sake. - */ - u32 bps = target_clock * bpp * 21 / 20; - lane = bps / (link_bw * 8) + 1; - } - - intel_crtc->fdi_lanes = lane; - - if (pixel_multiplier > 1) - link_bw *= pixel_multiplier; - ironlake_compute_m_n(bpp, lane, target_clock, link_bw, &m_n); - } - - /* Ironlake: try to setup display ref clock before DPLL - * enabling. This is only under driver's control after - * PCH B stepping, previous chipset stepping should be - * ignoring this setting. - */ - if (HAS_PCH_SPLIT(dev)) { - temp = I915_READ(PCH_DREF_CONTROL); - /* Always enable nonspread source */ - temp &= ~DREF_NONSPREAD_SOURCE_MASK; - temp |= DREF_NONSPREAD_SOURCE_ENABLE; - temp &= ~DREF_SSC_SOURCE_MASK; - temp |= DREF_SSC_SOURCE_ENABLE; - I915_WRITE(PCH_DREF_CONTROL, temp); - - POSTING_READ(PCH_DREF_CONTROL); - udelay(200); - - if (has_edp_encoder) { - if (intel_panel_use_ssc(dev_priv)) { - temp |= DREF_SSC1_ENABLE; - I915_WRITE(PCH_DREF_CONTROL, temp); - - POSTING_READ(PCH_DREF_CONTROL); - udelay(200); - } - temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK; - - /* Enable CPU source on CPU attached eDP */ - if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) { - if (intel_panel_use_ssc(dev_priv)) - temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; - else - temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; - } else { - /* Enable SSC on PCH eDP if needed */ - if (intel_panel_use_ssc(dev_priv)) { - DRM_ERROR("enabling SSC on PCH\n"); - temp |= DREF_SUPERSPREAD_SOURCE_ENABLE; - } - } - I915_WRITE(PCH_DREF_CONTROL, temp); - POSTING_READ(PCH_DREF_CONTROL); - udelay(200); - } - } - if (IS_PINEVIEW(dev)) { fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2; if (has_reduced_clock) @@ -4794,25 +4479,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, reduced_clock.m2; } - /* Enable autotuning of the PLL clock (if permissible) */ - if (HAS_PCH_SPLIT(dev)) { - int factor = 21; - - if (is_lvds) { - if ((intel_panel_use_ssc(dev_priv) && - dev_priv->lvds_ssc_freq == 100) || - (I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) - factor = 25; - } else if (is_sdvo && is_tv) - factor = 20; - - if (clock.m1 < factor * clock.n) - fp |= FP_CB_TUNE; - } - - dpll = 0; - if (!HAS_PCH_SPLIT(dev)) - dpll = DPLL_VGA_MODE_DIS; + dpll = DPLL_VGA_MODE_DIS; if (!IS_GEN2(dev)) { if (is_lvds) @@ -4824,12 +4491,10 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, if (pixel_multiplier > 1) { if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; - else if (HAS_PCH_SPLIT(dev)) - dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; } dpll |= DPLL_DVO_HIGH_SPEED; } - if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) + if (is_dp) dpll |= DPLL_DVO_HIGH_SPEED; /* compute bitmask from p1 value */ @@ -4837,9 +4502,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW; else { dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; - /* also FPA1 */ - if (HAS_PCH_SPLIT(dev)) - dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT; if (IS_G4X(dev) && has_reduced_clock) dpll |= (1 << (reduced_clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT; } @@ -4857,7 +4519,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; break; } - if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) + if (INTEL_INFO(dev)->gen >= 4) dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); } else { if (is_lvds) { @@ -4891,12 +4553,10 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* Ironlake's plane is forced to pipe, bit 24 is to enable color space conversion */ - if (!HAS_PCH_SPLIT(dev)) { - if (pipe == 0) - dspcntr &= ~DISPPLANE_SEL_PIPE_MASK; - else - dspcntr |= DISPPLANE_SEL_PIPE_B; - } + if (pipe == 0) + dspcntr &= ~DISPPLANE_SEL_PIPE_MASK; + else + dspcntr |= DISPPLANE_SEL_PIPE_B; if (pipe == 0 && INTEL_INFO(dev)->gen < 4) { /* Enable pixel doubling when the dot clock is > 90% of the (display) @@ -4912,27 +4572,506 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, pipeconf &= ~PIPECONF_DOUBLE_WIDE; } - if (!HAS_PCH_SPLIT(dev)) - dpll |= DPLL_VCO_ENABLE; + dpll |= DPLL_VCO_ENABLE; DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); drm_mode_debug_printmodeline(mode); - /* assign to Ironlake registers */ - if (HAS_PCH_SPLIT(dev)) { - fp_reg = PCH_FP0(pipe); - dpll_reg = PCH_DPLL(pipe); + I915_WRITE(FP0(pipe), fp); + I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE); + + POSTING_READ(DPLL(pipe)); + udelay(150); + + /* The LVDS pin pair needs to be on before the DPLLs are enabled. + * This is an exception to the general rule that mode_set doesn't turn + * things on. + */ + if (is_lvds) { + temp = I915_READ(LVDS); + temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; + if (pipe == 1) { + temp |= LVDS_PIPEB_SELECT; + } else { + temp &= ~LVDS_PIPEB_SELECT; + } + /* set the corresponsding LVDS_BORDER bit */ + temp |= dev_priv->lvds_border_bits; + /* Set the B0-B3 data pairs corresponding to whether we're going to + * set the DPLLs for dual-channel mode or not. + */ + if (clock.p2 == 7) + temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; + else + temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); + + /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) + * appropriately here, but we need to look more thoroughly into how + * panels behave in the two modes. + */ + /* set the dithering flag on LVDS as needed */ + if (INTEL_INFO(dev)->gen >= 4) { + if (dev_priv->lvds_dither) + temp |= LVDS_ENABLE_DITHER; + else + temp &= ~LVDS_ENABLE_DITHER; + } + if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) + lvds_sync |= LVDS_HSYNC_POLARITY; + if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) + lvds_sync |= LVDS_VSYNC_POLARITY; + if ((temp & (LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY)) + != lvds_sync) { + char flags[2] = "-+"; + DRM_INFO("Changing LVDS panel from " + "(%chsync, %cvsync) to (%chsync, %cvsync)\n", + flags[!(temp & LVDS_HSYNC_POLARITY)], + flags[!(temp & LVDS_VSYNC_POLARITY)], + flags[!(lvds_sync & LVDS_HSYNC_POLARITY)], + flags[!(lvds_sync & LVDS_VSYNC_POLARITY)]); + temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); + temp |= lvds_sync; + } + I915_WRITE(LVDS, temp); + } + + if (is_dp) { + intel_dp_set_m_n(crtc, mode, adjusted_mode); + } + + I915_WRITE(DPLL(pipe), dpll); + + /* Wait for the clocks to stabilize. */ + POSTING_READ(DPLL(pipe)); + udelay(150); + + if (INTEL_INFO(dev)->gen >= 4) { + temp = 0; + if (is_sdvo) { + temp = intel_mode_get_pixel_multiplier(adjusted_mode); + if (temp > 1) + temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; + else + temp = 0; + } + I915_WRITE(DPLL_MD(pipe), temp); } else { - fp_reg = FP0(pipe); - dpll_reg = DPLL(pipe); + /* The pixel multiplier can only be updated once the + * DPLL is enabled and the clocks are stable. + * + * So write it again. + */ + I915_WRITE(DPLL(pipe), dpll); + } + + intel_crtc->lowfreq_avail = false; + if (is_lvds && has_reduced_clock && i915_powersave) { + I915_WRITE(FP1(pipe), fp2); + intel_crtc->lowfreq_avail = true; + if (HAS_PIPE_CXSR(dev)) { + DRM_DEBUG_KMS("enabling CxSR downclocking\n"); + pipeconf |= PIPECONF_CXSR_DOWNCLOCK; + } + } else { + I915_WRITE(FP1(pipe), fp); + if (HAS_PIPE_CXSR(dev)) { + DRM_DEBUG_KMS("disabling CxSR downclocking\n"); + pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK; + } } + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { + pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION; + /* the chip adds 2 halflines automatically */ + adjusted_mode->crtc_vdisplay -= 1; + adjusted_mode->crtc_vtotal -= 1; + adjusted_mode->crtc_vblank_start -= 1; + adjusted_mode->crtc_vblank_end -= 1; + adjusted_mode->crtc_vsync_end -= 1; + adjusted_mode->crtc_vsync_start -= 1; + } else + pipeconf &= ~PIPECONF_INTERLACE_W_FIELD_INDICATION; /* progressive */ + + I915_WRITE(HTOTAL(pipe), + (adjusted_mode->crtc_hdisplay - 1) | + ((adjusted_mode->crtc_htotal - 1) << 16)); + I915_WRITE(HBLANK(pipe), + (adjusted_mode->crtc_hblank_start - 1) | + ((adjusted_mode->crtc_hblank_end - 1) << 16)); + I915_WRITE(HSYNC(pipe), + (adjusted_mode->crtc_hsync_start - 1) | + ((adjusted_mode->crtc_hsync_end - 1) << 16)); + + I915_WRITE(VTOTAL(pipe), + (adjusted_mode->crtc_vdisplay - 1) | + ((adjusted_mode->crtc_vtotal - 1) << 16)); + I915_WRITE(VBLANK(pipe), + (adjusted_mode->crtc_vblank_start - 1) | + ((adjusted_mode->crtc_vblank_end - 1) << 16)); + I915_WRITE(VSYNC(pipe), + (adjusted_mode->crtc_vsync_start - 1) | + ((adjusted_mode->crtc_vsync_end - 1) << 16)); + + /* pipesrc and dspsize control the size that is scaled from, + * which should always be the user's requested size. + */ + I915_WRITE(DSPSIZE(plane), + ((mode->vdisplay - 1) << 16) | + (mode->hdisplay - 1)); + I915_WRITE(DSPPOS(plane), 0); + I915_WRITE(PIPESRC(pipe), + ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); + + I915_WRITE(PIPECONF(pipe), pipeconf); + POSTING_READ(PIPECONF(pipe)); + intel_enable_pipe(dev_priv, pipe, false); + + intel_wait_for_vblank(dev, pipe); + + I915_WRITE(DSPCNTR(plane), dspcntr); + POSTING_READ(DSPCNTR(plane)); + + ret = intel_pipe_set_base(crtc, x, y, old_fb); + + intel_update_watermarks(dev); + + return ret; +} + +static int ironlake_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, + struct drm_framebuffer *old_fb) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + int refclk, num_connectors = 0; + intel_clock_t clock, reduced_clock; + u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf; + bool ok, has_reduced_clock = false, is_sdvo = false; + bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false; + struct intel_encoder *has_edp_encoder = NULL; + struct drm_mode_config *mode_config = &dev->mode_config; + struct intel_encoder *encoder; + const intel_limit_t *limit; + int ret; + struct fdi_m_n m_n = {0}; + u32 temp; + u32 lvds_sync = 0; + int target_clock, pixel_multiplier, lane, link_bw, bpp, factor; + + list_for_each_entry(encoder, &mode_config->encoder_list, base.head) { + if (encoder->base.crtc != crtc) + continue; + + switch (encoder->type) { + case INTEL_OUTPUT_LVDS: + is_lvds = true; + break; + case INTEL_OUTPUT_SDVO: + case INTEL_OUTPUT_HDMI: + is_sdvo = true; + if (encoder->needs_tv_clock) + is_tv = true; + break; + case INTEL_OUTPUT_TVOUT: + is_tv = true; + break; + case INTEL_OUTPUT_ANALOG: + is_crt = true; + break; + case INTEL_OUTPUT_DISPLAYPORT: + is_dp = true; + break; + case INTEL_OUTPUT_EDP: + has_edp_encoder = encoder; + break; + } + + num_connectors++; + } + + if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) { + refclk = dev_priv->lvds_ssc_freq * 1000; + DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n", + refclk / 1000); + } else { + refclk = 96000; + if (!has_edp_encoder || + intel_encoder_is_pch_edp(&has_edp_encoder->base)) + refclk = 120000; /* 120Mhz refclk */ + } + + /* + * Returns a set of divisors for the desired target clock with the given + * refclk, or FALSE. The returned values represent the clock equation: + * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. + */ + limit = intel_limit(crtc, refclk); + ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock); + if (!ok) { + DRM_ERROR("Couldn't find PLL settings for mode!\n"); + return -EINVAL; + } + + /* Ensure that the cursor is valid for the new mode before changing... */ + intel_crtc_update_cursor(crtc, true); + + if (is_lvds && dev_priv->lvds_downclock_avail) { + has_reduced_clock = limit->find_pll(limit, crtc, + dev_priv->lvds_downclock, + refclk, + &reduced_clock); + if (has_reduced_clock && (clock.p != reduced_clock.p)) { + /* + * If the different P is found, it means that we can't + * switch the display clock by using the FP0/FP1. + * In such case we will disable the LVDS downclock + * feature. + */ + DRM_DEBUG_KMS("Different P is found for " + "LVDS clock/downclock\n"); + has_reduced_clock = 0; + } + } + /* SDVO TV has fixed PLL values depend on its clock range, + this mirrors vbios setting. */ + if (is_sdvo && is_tv) { + if (adjusted_mode->clock >= 100000 + && adjusted_mode->clock < 140500) { + clock.p1 = 2; + clock.p2 = 10; + clock.n = 3; + clock.m1 = 16; + clock.m2 = 8; + } else if (adjusted_mode->clock >= 140500 + && adjusted_mode->clock <= 200000) { + clock.p1 = 1; + clock.p2 = 10; + clock.n = 6; + clock.m1 = 12; + clock.m2 = 8; + } + } + + /* FDI link */ + pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); + lane = 0; + /* CPU eDP doesn't require FDI link, so just set DP M/N + according to current link config */ + if (has_edp_encoder && + !intel_encoder_is_pch_edp(&has_edp_encoder->base)) { + target_clock = mode->clock; + intel_edp_link_config(has_edp_encoder, + &lane, &link_bw); + } else { + /* [e]DP over FDI requires target mode clock + instead of link clock */ + if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) + target_clock = mode->clock; + else + target_clock = adjusted_mode->clock; + + /* FDI is a binary signal running at ~2.7GHz, encoding + * each output octet as 10 bits. The actual frequency + * is stored as a divider into a 100MHz clock, and the + * mode pixel clock is stored in units of 1KHz. + * Hence the bw of each lane in terms of the mode signal + * is: + */ + link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10; + } + + /* determine panel color depth */ + temp = I915_READ(PIPECONF(pipe)); + temp &= ~PIPE_BPC_MASK; + if (is_lvds) { + /* the BPC will be 6 if it is 18-bit LVDS panel */ + if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP) + temp |= PIPE_8BPC; + else + temp |= PIPE_6BPC; + } else if (has_edp_encoder) { + switch (dev_priv->edp.bpp/3) { + case 8: + temp |= PIPE_8BPC; + break; + case 10: + temp |= PIPE_10BPC; + break; + case 6: + temp |= PIPE_6BPC; + break; + case 12: + temp |= PIPE_12BPC; + break; + } + } else + temp |= PIPE_8BPC; + I915_WRITE(PIPECONF(pipe), temp); + + switch (temp & PIPE_BPC_MASK) { + case PIPE_8BPC: + bpp = 24; + break; + case PIPE_10BPC: + bpp = 30; + break; + case PIPE_6BPC: + bpp = 18; + break; + case PIPE_12BPC: + bpp = 36; + break; + default: + DRM_ERROR("unknown pipe bpc value\n"); + bpp = 24; + } + + if (!lane) { + /* + * Account for spread spectrum to avoid + * oversubscribing the link. Max center spread + * is 2.5%; use 5% for safety's sake. + */ + u32 bps = target_clock * bpp * 21 / 20; + lane = bps / (link_bw * 8) + 1; + } + + intel_crtc->fdi_lanes = lane; + + if (pixel_multiplier > 1) + link_bw *= pixel_multiplier; + ironlake_compute_m_n(bpp, lane, target_clock, link_bw, &m_n); + + /* Ironlake: try to setup display ref clock before DPLL + * enabling. This is only under driver's control after + * PCH B stepping, previous chipset stepping should be + * ignoring this setting. + */ + temp = I915_READ(PCH_DREF_CONTROL); + /* Always enable nonspread source */ + temp &= ~DREF_NONSPREAD_SOURCE_MASK; + temp |= DREF_NONSPREAD_SOURCE_ENABLE; + temp &= ~DREF_SSC_SOURCE_MASK; + temp |= DREF_SSC_SOURCE_ENABLE; + I915_WRITE(PCH_DREF_CONTROL, temp); + + POSTING_READ(PCH_DREF_CONTROL); + udelay(200); + + if (has_edp_encoder) { + if (intel_panel_use_ssc(dev_priv)) { + temp |= DREF_SSC1_ENABLE; + I915_WRITE(PCH_DREF_CONTROL, temp); + + POSTING_READ(PCH_DREF_CONTROL); + udelay(200); + } + temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK; + + /* Enable CPU source on CPU attached eDP */ + if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) { + if (intel_panel_use_ssc(dev_priv)) + temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; + else + temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; + } else { + /* Enable SSC on PCH eDP if needed */ + if (intel_panel_use_ssc(dev_priv)) { + DRM_ERROR("enabling SSC on PCH\n"); + temp |= DREF_SUPERSPREAD_SOURCE_ENABLE; + } + } + I915_WRITE(PCH_DREF_CONTROL, temp); + POSTING_READ(PCH_DREF_CONTROL); + udelay(200); + } + + fp = clock.n << 16 | clock.m1 << 8 | clock.m2; + if (has_reduced_clock) + fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | + reduced_clock.m2; + + /* Enable autotuning of the PLL clock (if permissible) */ + factor = 21; + if (is_lvds) { + if ((intel_panel_use_ssc(dev_priv) && + dev_priv->lvds_ssc_freq == 100) || + (I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) + factor = 25; + } else if (is_sdvo && is_tv) + factor = 20; + + if (clock.m1 < factor * clock.n) + fp |= FP_CB_TUNE; + + dpll = 0; + + if (is_lvds) + dpll |= DPLLB_MODE_LVDS; + else + dpll |= DPLLB_MODE_DAC_SERIAL; + if (is_sdvo) { + int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); + if (pixel_multiplier > 1) { + dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; + } + dpll |= DPLL_DVO_HIGH_SPEED; + } + if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) + dpll |= DPLL_DVO_HIGH_SPEED; + + /* compute bitmask from p1 value */ + dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; + /* also FPA1 */ + dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT; + + switch (clock.p2) { + case 5: + dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; + break; + case 7: + dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7; + break; + case 10: + dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10; + break; + case 14: + dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; + break; + } + + if (is_sdvo && is_tv) + dpll |= PLL_REF_INPUT_TVCLKINBC; + else if (is_tv) + /* XXX: just matching BIOS for now */ + /* dpll |= PLL_REF_INPUT_TVCLKINBC; */ + dpll |= 3; + else if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) + dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; + else + dpll |= PLL_REF_INPUT_DREFCLK; + + /* setup pipeconf */ + pipeconf = I915_READ(PIPECONF(pipe)); + + /* Set up the display plane register */ + dspcntr = DISPPLANE_GAMMA_ENABLE; + + DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); + drm_mode_debug_printmodeline(mode); + /* PCH eDP needs FDI, but CPU eDP does not */ if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) { - I915_WRITE(fp_reg, fp); - I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE); + I915_WRITE(PCH_FP0(pipe), fp); + I915_WRITE(PCH_DPLL(pipe), dpll & ~DPLL_VCO_ENABLE); - POSTING_READ(dpll_reg); + POSTING_READ(PCH_DPLL(pipe)); udelay(150); } @@ -4964,11 +5103,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, * things on. */ if (is_lvds) { - reg = LVDS; - if (HAS_PCH_SPLIT(dev)) - reg = PCH_LVDS; - - temp = I915_READ(reg); + temp = I915_READ(PCH_LVDS); temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; if (pipe == 1) { if (HAS_PCH_CPT(dev)) @@ -4995,13 +5130,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, * appropriately here, but we need to look more thoroughly into how * panels behave in the two modes. */ - /* set the dithering flag on non-PCH LVDS as needed */ - if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { - if (dev_priv->lvds_dither) - temp |= LVDS_ENABLE_DITHER; - else - temp &= ~LVDS_ENABLE_DITHER; - } if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) lvds_sync |= LVDS_HSYNC_POLARITY; if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) @@ -5018,22 +5146,20 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); temp |= lvds_sync; } - I915_WRITE(reg, temp); + I915_WRITE(PCH_LVDS, temp); } /* set the dithering flag and clear for anything other than a panel. */ - if (HAS_PCH_SPLIT(dev)) { - pipeconf &= ~PIPECONF_DITHER_EN; - pipeconf &= ~PIPECONF_DITHER_TYPE_MASK; - if (dev_priv->lvds_dither && (is_lvds || has_edp_encoder)) { - pipeconf |= PIPECONF_DITHER_EN; - pipeconf |= PIPECONF_DITHER_TYPE_ST1; - } + pipeconf &= ~PIPECONF_DITHER_EN; + pipeconf &= ~PIPECONF_DITHER_TYPE_MASK; + if (dev_priv->lvds_dither && (is_lvds || has_edp_encoder)) { + pipeconf |= PIPECONF_DITHER_EN; + pipeconf |= PIPECONF_DITHER_TYPE_ST1; } if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) { intel_dp_set_m_n(crtc, mode, adjusted_mode); - } else if (HAS_PCH_SPLIT(dev)) { + } else { /* For non-DP output, clear any trans DP clock recovery setting.*/ I915_WRITE(TRANSDATA_M1(pipe), 0); I915_WRITE(TRANSDATA_N1(pipe), 0); @@ -5041,43 +5167,32 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(TRANSDPLINK_N1(pipe), 0); } - if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) { - I915_WRITE(dpll_reg, dpll); + if (!has_edp_encoder || + intel_encoder_is_pch_edp(&has_edp_encoder->base)) { + I915_WRITE(PCH_DPLL(pipe), dpll); /* Wait for the clocks to stabilize. */ - POSTING_READ(dpll_reg); + POSTING_READ(PCH_DPLL(pipe)); udelay(150); - if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { - temp = 0; - if (is_sdvo) { - temp = intel_mode_get_pixel_multiplier(adjusted_mode); - if (temp > 1) - temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; - else - temp = 0; - } - I915_WRITE(DPLL_MD(pipe), temp); - } else { - /* The pixel multiplier can only be updated once the - * DPLL is enabled and the clocks are stable. - * - * So write it again. - */ - I915_WRITE(dpll_reg, dpll); - } + /* The pixel multiplier can only be updated once the + * DPLL is enabled and the clocks are stable. + * + * So write it again. + */ + I915_WRITE(PCH_DPLL(pipe), dpll); } intel_crtc->lowfreq_avail = false; if (is_lvds && has_reduced_clock && i915_powersave) { - I915_WRITE(fp_reg + 4, fp2); + I915_WRITE(PCH_FP1(pipe), fp2); intel_crtc->lowfreq_avail = true; if (HAS_PIPE_CXSR(dev)) { DRM_DEBUG_KMS("enabling CxSR downclocking\n"); pipeconf |= PIPECONF_CXSR_DOWNCLOCK; } } else { - I915_WRITE(fp_reg + 4, fp); + I915_WRITE(PCH_FP1(pipe), fp); if (HAS_PIPE_CXSR(dev)) { DRM_DEBUG_KMS("disabling CxSR downclocking\n"); pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK; @@ -5116,33 +5231,24 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, (adjusted_mode->crtc_vsync_start - 1) | ((adjusted_mode->crtc_vsync_end - 1) << 16)); - /* pipesrc and dspsize control the size that is scaled from, - * which should always be the user's requested size. + /* pipesrc controls the size that is scaled from, which should + * always be the user's requested size. */ - if (!HAS_PCH_SPLIT(dev)) { - I915_WRITE(DSPSIZE(plane), - ((mode->vdisplay - 1) << 16) | - (mode->hdisplay - 1)); - I915_WRITE(DSPPOS(plane), 0); - } I915_WRITE(PIPESRC(pipe), ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); - if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m); - I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n); - I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m); - I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n); + I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m); + I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n); + I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m); + I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n); - if (has_edp_encoder && !intel_encoder_is_pch_edp(&has_edp_encoder->base)) { - ironlake_set_pll_edp(crtc, adjusted_mode->clock); - } + if (has_edp_encoder && + !intel_encoder_is_pch_edp(&has_edp_encoder->base)) { + ironlake_set_pll_edp(crtc, adjusted_mode->clock); } I915_WRITE(PIPECONF(pipe), pipeconf); POSTING_READ(PIPECONF(pipe)); - if (!HAS_PCH_SPLIT(dev)) - intel_enable_pipe(dev_priv, pipe, false); intel_wait_for_vblank(dev, pipe); @@ -5154,13 +5260,31 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(DSPCNTR(plane), dspcntr); POSTING_READ(DSPCNTR(plane)); - if (!HAS_PCH_SPLIT(dev)) - intel_enable_plane(dev_priv, plane, pipe); ret = intel_pipe_set_base(crtc, x, y, old_fb); intel_update_watermarks(dev); + return ret; +} + +static int intel_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, + struct drm_framebuffer *old_fb) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int ret; + + drm_vblank_pre_modeset(dev, pipe); + + ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode, + x, y, old_fb); + drm_vblank_post_modeset(dev, pipe); return ret; @@ -5483,43 +5607,140 @@ static struct drm_display_mode load_detect_mode = { 704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), }; -struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, - struct drm_connector *connector, - struct drm_display_mode *mode, - int *dpms_mode) +static struct drm_framebuffer * +intel_framebuffer_create(struct drm_device *dev, + struct drm_mode_fb_cmd *mode_cmd, + struct drm_i915_gem_object *obj) +{ + struct intel_framebuffer *intel_fb; + int ret; + + intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); + if (!intel_fb) { + drm_gem_object_unreference_unlocked(&obj->base); + return ERR_PTR(-ENOMEM); + } + + ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj); + if (ret) { + drm_gem_object_unreference_unlocked(&obj->base); + kfree(intel_fb); + return ERR_PTR(ret); + } + + return &intel_fb->base; +} + +static u32 +intel_framebuffer_pitch_for_width(int width, int bpp) +{ + u32 pitch = DIV_ROUND_UP(width * bpp, 8); + return ALIGN(pitch, 64); +} + +static u32 +intel_framebuffer_size_for_mode(struct drm_display_mode *mode, int bpp) +{ + u32 pitch = intel_framebuffer_pitch_for_width(mode->hdisplay, bpp); + return ALIGN(pitch * mode->vdisplay, PAGE_SIZE); +} + +static struct drm_framebuffer * +intel_framebuffer_create_for_mode(struct drm_device *dev, + struct drm_display_mode *mode, + int depth, int bpp) +{ + struct drm_i915_gem_object *obj; + struct drm_mode_fb_cmd mode_cmd; + + obj = i915_gem_alloc_object(dev, + intel_framebuffer_size_for_mode(mode, bpp)); + if (obj == NULL) + return ERR_PTR(-ENOMEM); + + mode_cmd.width = mode->hdisplay; + mode_cmd.height = mode->vdisplay; + mode_cmd.depth = depth; + mode_cmd.bpp = bpp; + mode_cmd.pitch = intel_framebuffer_pitch_for_width(mode_cmd.width, bpp); + + return intel_framebuffer_create(dev, &mode_cmd, obj); +} + +static struct drm_framebuffer * +mode_fits_in_fbdev(struct drm_device *dev, + struct drm_display_mode *mode) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj; + struct drm_framebuffer *fb; + + if (dev_priv->fbdev == NULL) + return NULL; + + obj = dev_priv->fbdev->ifb.obj; + if (obj == NULL) + return NULL; + + fb = &dev_priv->fbdev->ifb.base; + if (fb->pitch < intel_framebuffer_pitch_for_width(mode->hdisplay, + fb->bits_per_pixel)) + return NULL; + + if (obj->base.size < mode->vdisplay * fb->pitch) + return NULL; + + return fb; +} + +bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, + struct drm_connector *connector, + struct drm_display_mode *mode, + struct intel_load_detect_pipe *old) { struct intel_crtc *intel_crtc; struct drm_crtc *possible_crtc; - struct drm_crtc *supported_crtc =NULL; struct drm_encoder *encoder = &intel_encoder->base; struct drm_crtc *crtc = NULL; struct drm_device *dev = encoder->dev; - struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; - struct drm_crtc_helper_funcs *crtc_funcs; + struct drm_framebuffer *old_fb; int i = -1; + DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", + connector->base.id, drm_get_connector_name(connector), + encoder->base.id, drm_get_encoder_name(encoder)); + /* * Algorithm gets a little messy: + * * - if the connector already has an assigned crtc, use it (but make * sure it's on first) + * * - try to find the first unused crtc that can drive this connector, * and use that if we find one - * - if there are no unused crtcs available, try to use the first - * one we found that supports the connector */ /* See if we already have a CRTC for this connector */ if (encoder->crtc) { crtc = encoder->crtc; - /* Make sure the crtc and connector are running */ + intel_crtc = to_intel_crtc(crtc); - *dpms_mode = intel_crtc->dpms_mode; + old->dpms_mode = intel_crtc->dpms_mode; + old->load_detect_temp = false; + + /* Make sure the crtc and connector are running */ if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) { + struct drm_encoder_helper_funcs *encoder_funcs; + struct drm_crtc_helper_funcs *crtc_funcs; + crtc_funcs = crtc->helper_private; crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); + + encoder_funcs = encoder->helper_private; encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); } - return crtc; + + return true; } /* Find an unused one (if possible) */ @@ -5531,46 +5752,66 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, crtc = possible_crtc; break; } - if (!supported_crtc) - supported_crtc = possible_crtc; } /* * If we didn't find an unused CRTC, don't use any. */ if (!crtc) { - return NULL; + DRM_DEBUG_KMS("no pipe available for load-detect\n"); + return false; } encoder->crtc = crtc; connector->encoder = encoder; - intel_encoder->load_detect_temp = true; intel_crtc = to_intel_crtc(crtc); - *dpms_mode = intel_crtc->dpms_mode; + old->dpms_mode = intel_crtc->dpms_mode; + old->load_detect_temp = true; + old->release_fb = NULL; - if (!crtc->enabled) { - if (!mode) - mode = &load_detect_mode; - drm_crtc_helper_set_mode(crtc, mode, 0, 0, crtc->fb); - } else { - if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) { - crtc_funcs = crtc->helper_private; - crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); - } + if (!mode) + mode = &load_detect_mode; + + old_fb = crtc->fb; - /* Add this connector to the crtc */ - encoder_funcs->mode_set(encoder, &crtc->mode, &crtc->mode); - encoder_funcs->commit(encoder); + /* We need a framebuffer large enough to accommodate all accesses + * that the plane may generate whilst we perform load detection. + * We can not rely on the fbcon either being present (we get called + * during its initialisation to detect all boot displays, or it may + * not even exist) or that it is large enough to satisfy the + * requested mode. + */ + crtc->fb = mode_fits_in_fbdev(dev, mode); + if (crtc->fb == NULL) { + DRM_DEBUG_KMS("creating tmp fb for load-detection\n"); + crtc->fb = intel_framebuffer_create_for_mode(dev, mode, 24, 32); + old->release_fb = crtc->fb; + } else + DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n"); + if (IS_ERR(crtc->fb)) { + DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n"); + crtc->fb = old_fb; + return false; } + + if (!drm_crtc_helper_set_mode(crtc, mode, 0, 0, old_fb)) { + DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); + if (old->release_fb) + old->release_fb->funcs->destroy(old->release_fb); + crtc->fb = old_fb; + return false; + } + /* let the connector get through one full cycle before testing */ intel_wait_for_vblank(dev, intel_crtc->pipe); - return crtc; + return true; } void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, - struct drm_connector *connector, int dpms_mode) + struct drm_connector *connector, + struct intel_load_detect_pipe *old) { struct drm_encoder *encoder = &intel_encoder->base; struct drm_device *dev = encoder->dev; @@ -5578,19 +5819,24 @@ void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - if (intel_encoder->load_detect_temp) { - encoder->crtc = NULL; + DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", + connector->base.id, drm_get_connector_name(connector), + encoder->base.id, drm_get_encoder_name(encoder)); + + if (old->load_detect_temp) { connector->encoder = NULL; - intel_encoder->load_detect_temp = false; - crtc->enabled = drm_helper_crtc_in_use(crtc); drm_helper_disable_unused_functions(dev); + + if (old->release_fb) + old->release_fb->funcs->destroy(old->release_fb); + + return; } /* Switch crtc and encoder back off if necessary */ - if (crtc->enabled && dpms_mode != DRM_MODE_DPMS_ON) { - if (encoder->crtc == crtc) - encoder_funcs->dpms(encoder, dpms_mode); - crtc_funcs->dpms(crtc, dpms_mode); + if (old->dpms_mode != DRM_MODE_DPMS_ON) { + encoder_funcs->dpms(encoder, old->dpms_mode); + crtc_funcs->dpms(crtc, old->dpms_mode); } } @@ -5605,9 +5851,9 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) intel_clock_t clock; if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) - fp = FP0(pipe); + fp = I915_READ(FP0(pipe)); else - fp = FP1(pipe); + fp = I915_READ(FP1(pipe)); clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; if (IS_PINEVIEW(dev)) { @@ -6185,6 +6431,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, break; case 6: + case 7: OUT_RING(MI_DISPLAY_FLIP | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); OUT_RING(fb->pitch | obj->tiling_mode); @@ -6504,6 +6751,9 @@ static void intel_setup_outputs(struct drm_device *dev) } intel_panel_setup_backlight(dev); + + /* disable all the possible outputs/crtcs before entering KMS mode */ + drm_helper_disable_unused_functions(dev); } static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) @@ -6571,25 +6821,12 @@ intel_user_framebuffer_create(struct drm_device *dev, struct drm_mode_fb_cmd *mode_cmd) { struct drm_i915_gem_object *obj; - struct intel_framebuffer *intel_fb; - int ret; obj = to_intel_bo(drm_gem_object_lookup(dev, filp, mode_cmd->handle)); if (&obj->base == NULL) return ERR_PTR(-ENOENT); - intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); - if (!intel_fb) - return ERR_PTR(-ENOMEM); - - ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj); - if (ret) { - drm_gem_object_unreference_unlocked(&obj->base); - kfree(intel_fb); - return ERR_PTR(ret); - } - - return &intel_fb->base; + return intel_framebuffer_create(dev, mode_cmd, obj); } static const struct drm_mode_config_funcs intel_mode_funcs = { @@ -6603,13 +6840,14 @@ intel_alloc_context_page(struct drm_device *dev) struct drm_i915_gem_object *ctx; int ret; + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + ctx = i915_gem_alloc_object(dev, 4096); if (!ctx) { DRM_DEBUG("failed to alloc power context, RC6 disabled\n"); return NULL; } - mutex_lock(&dev->struct_mutex); ret = i915_gem_object_pin(ctx, 4096, true); if (ret) { DRM_ERROR("failed to pin power context: %d\n", ret); @@ -6621,7 +6859,6 @@ intel_alloc_context_page(struct drm_device *dev) DRM_ERROR("failed to set-domain on power context: %d\n", ret); goto err_unpin; } - mutex_unlock(&dev->struct_mutex); return ctx; @@ -6756,6 +6993,11 @@ void gen6_disable_rps(struct drm_device *dev) I915_WRITE(GEN6_RPNSWREQ, 1 << 31); I915_WRITE(GEN6_PMINTRMSK, 0xffffffff); I915_WRITE(GEN6_PMIER, 0); + + spin_lock_irq(&dev_priv->rps_lock); + dev_priv->pm_iir = 0; + spin_unlock_irq(&dev_priv->rps_lock); + I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); } @@ -6849,7 +7091,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) { u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); - u32 pcu_mbox; + u32 pcu_mbox, rc6_mask = 0; int cur_freq, min_freq, max_freq; int i; @@ -6860,7 +7102,8 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) * userspace... */ I915_WRITE(GEN6_RC_STATE, 0); - __gen6_gt_force_wake_get(dev_priv); + mutex_lock(&dev_priv->dev->struct_mutex); + gen6_gt_force_wake_get(dev_priv); /* disable the counters and set deterministic thresholds */ I915_WRITE(GEN6_RC_CONTROL, 0); @@ -6880,9 +7123,12 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) I915_WRITE(GEN6_RC6p_THRESHOLD, 100000); I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */ + if (i915_enable_rc6) + rc6_mask = GEN6_RC_CTL_RC6p_ENABLE | + GEN6_RC_CTL_RC6_ENABLE; + I915_WRITE(GEN6_RC_CONTROL, - GEN6_RC_CTL_RC6p_ENABLE | - GEN6_RC_CTL_RC6_ENABLE | + rc6_mask | GEN6_RC_CTL_EI_MODE(1) | GEN6_RC_CTL_HW_ENABLE); @@ -6954,168 +7200,237 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_UP_EI_EXPIRED | GEN6_PM_RP_DOWN_EI_EXPIRED); + spin_lock_irq(&dev_priv->rps_lock); + WARN_ON(dev_priv->pm_iir != 0); I915_WRITE(GEN6_PMIMR, 0); + spin_unlock_irq(&dev_priv->rps_lock); /* enable all PM interrupts */ I915_WRITE(GEN6_PMINTRMSK, 0); - __gen6_gt_force_wake_put(dev_priv); + gen6_gt_force_wake_put(dev_priv); + mutex_unlock(&dev_priv->dev->struct_mutex); +} + +static void ironlake_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; + + /* Required for FBC */ + dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE | + DPFCRUNIT_CLOCK_GATE_DISABLE | + DPFDUNIT_CLOCK_GATE_DISABLE; + /* Required for CxSR */ + dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE; + + I915_WRITE(PCH_3DCGDIS0, + MARIUNIT_CLOCK_GATE_DISABLE | + SVSMUNIT_CLOCK_GATE_DISABLE); + I915_WRITE(PCH_3DCGDIS1, + VFMUNIT_CLOCK_GATE_DISABLE); + + I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); + + /* + * According to the spec the following bits should be set in + * order to enable memory self-refresh + * The bit 22/21 of 0x42004 + * The bit 5 of 0x42020 + * The bit 15 of 0x45000 + */ + I915_WRITE(ILK_DISPLAY_CHICKEN2, + (I915_READ(ILK_DISPLAY_CHICKEN2) | + ILK_DPARB_GATE | ILK_VSDPFD_FULL)); + I915_WRITE(ILK_DSPCLK_GATE, + (I915_READ(ILK_DSPCLK_GATE) | + ILK_DPARB_CLK_GATE)); + I915_WRITE(DISP_ARB_CTL, + (I915_READ(DISP_ARB_CTL) | + DISP_FBC_WM_DIS)); + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); + + /* + * Based on the document from hardware guys the following bits + * should be set unconditionally in order to enable FBC. + * The bit 22 of 0x42000 + * The bit 22 of 0x42004 + * The bit 7,8,9 of 0x42020. + */ + if (IS_IRONLAKE_M(dev)) { + I915_WRITE(ILK_DISPLAY_CHICKEN1, + I915_READ(ILK_DISPLAY_CHICKEN1) | + ILK_FBCQ_DIS); + I915_WRITE(ILK_DISPLAY_CHICKEN2, + I915_READ(ILK_DISPLAY_CHICKEN2) | + ILK_DPARB_GATE); + I915_WRITE(ILK_DSPCLK_GATE, + I915_READ(ILK_DSPCLK_GATE) | + ILK_DPFC_DIS1 | + ILK_DPFC_DIS2 | + ILK_CLK_FBC); + } + + I915_WRITE(ILK_DISPLAY_CHICKEN2, + I915_READ(ILK_DISPLAY_CHICKEN2) | + ILK_ELPIN_409_SELECT); + I915_WRITE(_3D_CHICKEN2, + _3D_CHICKEN2_WM_READ_PIPELINED << 16 | + _3D_CHICKEN2_WM_READ_PIPELINED); } -void intel_enable_clock_gating(struct drm_device *dev) +static void gen6_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int pipe; + uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; + + I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); + + I915_WRITE(ILK_DISPLAY_CHICKEN2, + I915_READ(ILK_DISPLAY_CHICKEN2) | + ILK_ELPIN_409_SELECT); + + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); /* - * Disable clock gating reported to work incorrectly according to the - * specs, but enable as much else as we can. + * According to the spec the following bits should be + * set in order to enable memory self-refresh and fbc: + * The bit21 and bit22 of 0x42000 + * The bit21 and bit22 of 0x42004 + * The bit5 and bit7 of 0x42020 + * The bit14 of 0x70180 + * The bit14 of 0x71180 */ - if (HAS_PCH_SPLIT(dev)) { - uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; + I915_WRITE(ILK_DISPLAY_CHICKEN1, + I915_READ(ILK_DISPLAY_CHICKEN1) | + ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS); + I915_WRITE(ILK_DISPLAY_CHICKEN2, + I915_READ(ILK_DISPLAY_CHICKEN2) | + ILK_DPARB_GATE | ILK_VSDPFD_FULL); + I915_WRITE(ILK_DSPCLK_GATE, + I915_READ(ILK_DSPCLK_GATE) | + ILK_DPARB_CLK_GATE | + ILK_DPFD_CLK_GATE); - if (IS_GEN5(dev)) { - /* Required for FBC */ - dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE | - DPFCRUNIT_CLOCK_GATE_DISABLE | - DPFDUNIT_CLOCK_GATE_DISABLE; - /* Required for CxSR */ - dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE; - - I915_WRITE(PCH_3DCGDIS0, - MARIUNIT_CLOCK_GATE_DISABLE | - SVSMUNIT_CLOCK_GATE_DISABLE); - I915_WRITE(PCH_3DCGDIS1, - VFMUNIT_CLOCK_GATE_DISABLE); - } + for_each_pipe(pipe) + I915_WRITE(DSPCNTR(pipe), + I915_READ(DSPCNTR(pipe)) | + DISPPLANE_TRICKLE_FEED_DISABLE); +} - I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); +static void ivybridge_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe; + uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; - /* - * On Ibex Peak and Cougar Point, we need to disable clock - * gating for the panel power sequencer or it will fail to - * start up when no ports are active. - */ - I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); + I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); - /* - * According to the spec the following bits should be set in - * order to enable memory self-refresh - * The bit 22/21 of 0x42004 - * The bit 5 of 0x42020 - * The bit 15 of 0x45000 - */ - if (IS_GEN5(dev)) { - I915_WRITE(ILK_DISPLAY_CHICKEN2, - (I915_READ(ILK_DISPLAY_CHICKEN2) | - ILK_DPARB_GATE | ILK_VSDPFD_FULL)); - I915_WRITE(ILK_DSPCLK_GATE, - (I915_READ(ILK_DSPCLK_GATE) | - ILK_DPARB_CLK_GATE)); - I915_WRITE(DISP_ARB_CTL, - (I915_READ(DISP_ARB_CTL) | - DISP_FBC_WM_DIS)); - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); - } - /* - * Based on the document from hardware guys the following bits - * should be set unconditionally in order to enable FBC. - * The bit 22 of 0x42000 - * The bit 22 of 0x42004 - * The bit 7,8,9 of 0x42020. - */ - if (IS_IRONLAKE_M(dev)) { - I915_WRITE(ILK_DISPLAY_CHICKEN1, - I915_READ(ILK_DISPLAY_CHICKEN1) | - ILK_FBCQ_DIS); - I915_WRITE(ILK_DISPLAY_CHICKEN2, - I915_READ(ILK_DISPLAY_CHICKEN2) | - ILK_DPARB_GATE); - I915_WRITE(ILK_DSPCLK_GATE, - I915_READ(ILK_DSPCLK_GATE) | - ILK_DPFC_DIS1 | - ILK_DPFC_DIS2 | - ILK_CLK_FBC); - } + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); - I915_WRITE(ILK_DISPLAY_CHICKEN2, - I915_READ(ILK_DISPLAY_CHICKEN2) | - ILK_ELPIN_409_SELECT); + I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); - if (IS_GEN5(dev)) { - I915_WRITE(_3D_CHICKEN2, - _3D_CHICKEN2_WM_READ_PIPELINED << 16 | - _3D_CHICKEN2_WM_READ_PIPELINED); - } + for_each_pipe(pipe) + I915_WRITE(DSPCNTR(pipe), + I915_READ(DSPCNTR(pipe)) | + DISPPLANE_TRICKLE_FEED_DISABLE); +} - if (IS_GEN6(dev)) { - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); +static void g4x_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dspclk_gate; - /* - * According to the spec the following bits should be - * set in order to enable memory self-refresh and fbc: - * The bit21 and bit22 of 0x42000 - * The bit21 and bit22 of 0x42004 - * The bit5 and bit7 of 0x42020 - * The bit14 of 0x70180 - * The bit14 of 0x71180 - */ - I915_WRITE(ILK_DISPLAY_CHICKEN1, - I915_READ(ILK_DISPLAY_CHICKEN1) | - ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS); - I915_WRITE(ILK_DISPLAY_CHICKEN2, - I915_READ(ILK_DISPLAY_CHICKEN2) | - ILK_DPARB_GATE | ILK_VSDPFD_FULL); - I915_WRITE(ILK_DSPCLK_GATE, - I915_READ(ILK_DSPCLK_GATE) | - ILK_DPARB_CLK_GATE | - ILK_DPFD_CLK_GATE); - - for_each_pipe(pipe) - I915_WRITE(DSPCNTR(pipe), - I915_READ(DSPCNTR(pipe)) | - DISPPLANE_TRICKLE_FEED_DISABLE); - } - } else if (IS_G4X(dev)) { - uint32_t dspclk_gate; - I915_WRITE(RENCLK_GATE_D1, 0); - I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE | - GS_UNIT_CLOCK_GATE_DISABLE | - CL_UNIT_CLOCK_GATE_DISABLE); - I915_WRITE(RAMCLK_GATE_D, 0); - dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE | - OVRUNIT_CLOCK_GATE_DISABLE | - OVCUNIT_CLOCK_GATE_DISABLE; - if (IS_GM45(dev)) - dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE; - I915_WRITE(DSPCLK_GATE_D, dspclk_gate); - } else if (IS_CRESTLINE(dev)) { - I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE); - I915_WRITE(RENCLK_GATE_D2, 0); - I915_WRITE(DSPCLK_GATE_D, 0); - I915_WRITE(RAMCLK_GATE_D, 0); - I915_WRITE16(DEUC, 0); - } else if (IS_BROADWATER(dev)) { - I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE | - I965_RCC_CLOCK_GATE_DISABLE | - I965_RCPB_CLOCK_GATE_DISABLE | - I965_ISC_CLOCK_GATE_DISABLE | - I965_FBC_CLOCK_GATE_DISABLE); - I915_WRITE(RENCLK_GATE_D2, 0); - } else if (IS_GEN3(dev)) { - u32 dstate = I915_READ(D_STATE); + I915_WRITE(RENCLK_GATE_D1, 0); + I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE | + GS_UNIT_CLOCK_GATE_DISABLE | + CL_UNIT_CLOCK_GATE_DISABLE); + I915_WRITE(RAMCLK_GATE_D, 0); + dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE | + OVRUNIT_CLOCK_GATE_DISABLE | + OVCUNIT_CLOCK_GATE_DISABLE; + if (IS_GM45(dev)) + dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE; + I915_WRITE(DSPCLK_GATE_D, dspclk_gate); +} - dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING | - DSTATE_DOT_CLOCK_GATING; - I915_WRITE(D_STATE, dstate); - } else if (IS_I85X(dev) || IS_I865G(dev)) { - I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE); - } else if (IS_I830(dev)) { - I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE); - } +static void crestline_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE); + I915_WRITE(RENCLK_GATE_D2, 0); + I915_WRITE(DSPCLK_GATE_D, 0); + I915_WRITE(RAMCLK_GATE_D, 0); + I915_WRITE16(DEUC, 0); +} + +static void broadwater_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE | + I965_RCC_CLOCK_GATE_DISABLE | + I965_RCPB_CLOCK_GATE_DISABLE | + I965_ISC_CLOCK_GATE_DISABLE | + I965_FBC_CLOCK_GATE_DISABLE); + I915_WRITE(RENCLK_GATE_D2, 0); +} + +static void gen3_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dstate = I915_READ(D_STATE); + + dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING | + DSTATE_DOT_CLOCK_GATING; + I915_WRITE(D_STATE, dstate); +} + +static void i85x_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE); +} + +static void i830_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE); +} + +static void ibx_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* + * On Ibex Peak and Cougar Point, we need to disable clock + * gating for the panel power sequencer or it will fail to + * start up when no ports are active. + */ + I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); +} + +static void cpt_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* + * On Ibex Peak and Cougar Point, we need to disable clock + * gating for the panel power sequencer or it will fail to + * start up when no ports are active. + */ + I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); + I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) | + DPLS_EDP_PPS_FIX_DIS); } static void ironlake_teardown_rc6(struct drm_device *dev) @@ -7185,9 +7500,12 @@ void ironlake_enable_rc6(struct drm_device *dev) if (!i915_enable_rc6) return; + mutex_lock(&dev->struct_mutex); ret = ironlake_setup_rc6(dev); - if (ret) + if (ret) { + mutex_unlock(&dev->struct_mutex); return; + } /* * GPU can automatically power down the render unit if given a page @@ -7196,6 +7514,7 @@ void ironlake_enable_rc6(struct drm_device *dev) ret = BEGIN_LP_RING(6); if (ret) { ironlake_teardown_rc6(dev); + mutex_unlock(&dev->struct_mutex); return; } @@ -7211,10 +7530,33 @@ void ironlake_enable_rc6(struct drm_device *dev) OUT_RING(MI_FLUSH); ADVANCE_LP_RING(); + /* + * Wait for the command parser to advance past MI_SET_CONTEXT. The HW + * does an implicit flush, combined with MI_FLUSH above, it should be + * safe to assume that renderctx is valid + */ + ret = intel_wait_ring_idle(LP_RING(dev_priv)); + if (ret) { + DRM_ERROR("failed to enable ironlake power power savings\n"); + ironlake_teardown_rc6(dev); + mutex_unlock(&dev->struct_mutex); + return; + } + I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN); I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); + mutex_unlock(&dev->struct_mutex); } +void intel_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + dev_priv->display.init_clock_gating(dev); + + if (dev_priv->display.init_pch_clock_gating) + dev_priv->display.init_pch_clock_gating(dev); +} /* Set up chip specific display functions */ static void intel_init_display(struct drm_device *dev) @@ -7222,10 +7564,13 @@ static void intel_init_display(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; /* We always want a DPMS function */ - if (HAS_PCH_SPLIT(dev)) + if (HAS_PCH_SPLIT(dev)) { dev_priv->display.dpms = ironlake_crtc_dpms; - else + dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set; + } else { dev_priv->display.dpms = i9xx_crtc_dpms; + dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; + } if (I915_HAS_FBC(dev)) { if (HAS_PCH_SPLIT(dev)) { @@ -7269,6 +7614,11 @@ static void intel_init_display(struct drm_device *dev) /* For FIFO watermark updates */ if (HAS_PCH_SPLIT(dev)) { + if (HAS_PCH_IBX(dev)) + dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating; + else if (HAS_PCH_CPT(dev)) + dev_priv->display.init_pch_clock_gating = cpt_init_clock_gating; + if (IS_GEN5(dev)) { if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK) dev_priv->display.update_wm = ironlake_update_wm; @@ -7277,6 +7627,8 @@ static void intel_init_display(struct drm_device *dev) "Disable CxSR\n"); dev_priv->display.update_wm = NULL; } + dev_priv->display.fdi_link_train = ironlake_fdi_link_train; + dev_priv->display.init_clock_gating = ironlake_init_clock_gating; } else if (IS_GEN6(dev)) { if (SNB_READ_WM0_LATENCY()) { dev_priv->display.update_wm = sandybridge_update_wm; @@ -7285,6 +7637,20 @@ static void intel_init_display(struct drm_device *dev) "Disable CxSR\n"); dev_priv->display.update_wm = NULL; } + dev_priv->display.fdi_link_train = gen6_fdi_link_train; + dev_priv->display.init_clock_gating = gen6_init_clock_gating; + } else if (IS_IVYBRIDGE(dev)) { + /* FIXME: detect B0+ stepping and use auto training */ + dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; + if (SNB_READ_WM0_LATENCY()) { + dev_priv->display.update_wm = sandybridge_update_wm; + } else { + DRM_DEBUG_KMS("Failed to read display plane latency. " + "Disable CxSR\n"); + dev_priv->display.update_wm = NULL; + } + dev_priv->display.init_clock_gating = ivybridge_init_clock_gating; + } else dev_priv->display.update_wm = NULL; } else if (IS_PINEVIEW(dev)) { @@ -7302,18 +7668,30 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.update_wm = NULL; } else dev_priv->display.update_wm = pineview_update_wm; - } else if (IS_G4X(dev)) + } else if (IS_G4X(dev)) { dev_priv->display.update_wm = g4x_update_wm; - else if (IS_GEN4(dev)) + dev_priv->display.init_clock_gating = g4x_init_clock_gating; + } else if (IS_GEN4(dev)) { dev_priv->display.update_wm = i965_update_wm; - else if (IS_GEN3(dev)) { + if (IS_CRESTLINE(dev)) + dev_priv->display.init_clock_gating = crestline_init_clock_gating; + else if (IS_BROADWATER(dev)) + dev_priv->display.init_clock_gating = broadwater_init_clock_gating; + } else if (IS_GEN3(dev)) { dev_priv->display.update_wm = i9xx_update_wm; dev_priv->display.get_fifo_size = i9xx_get_fifo_size; + dev_priv->display.init_clock_gating = gen3_init_clock_gating; + } else if (IS_I865G(dev)) { + dev_priv->display.update_wm = i830_update_wm; + dev_priv->display.init_clock_gating = i85x_init_clock_gating; + dev_priv->display.get_fifo_size = i830_get_fifo_size; } else if (IS_I85X(dev)) { dev_priv->display.update_wm = i9xx_update_wm; dev_priv->display.get_fifo_size = i85x_get_fifo_size; + dev_priv->display.init_clock_gating = i85x_init_clock_gating; } else { dev_priv->display.update_wm = i830_update_wm; + dev_priv->display.init_clock_gating = i830_init_clock_gating; if (IS_845G(dev)) dev_priv->display.get_fifo_size = i845_get_fifo_size; else @@ -7439,12 +7817,11 @@ void intel_modeset_init(struct drm_device *dev) intel_crtc_init(dev, i); } - intel_setup_outputs(dev); - - intel_enable_clock_gating(dev); - /* Just disable it once at startup */ i915_disable_vga(dev); + intel_setup_outputs(dev); + + intel_init_clock_gating(dev); if (IS_IRONLAKE_M(dev)) { ironlake_enable_drps(dev); @@ -7454,12 +7831,15 @@ void intel_modeset_init(struct drm_device *dev) if (IS_GEN6(dev)) gen6_enable_rps(dev_priv); - if (IS_IRONLAKE_M(dev)) - ironlake_enable_rc6(dev); - INIT_WORK(&dev_priv->idle_work, intel_idle_update); setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, (unsigned long)dev); +} + +void intel_modeset_gem_init(struct drm_device *dev) +{ + if (IS_IRONLAKE_M(dev)) + ironlake_enable_rc6(dev); intel_setup_overlay(dev); } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index cb8578b..a4d8031 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1470,7 +1470,8 @@ intel_dp_link_down(struct intel_dp *intel_dp) if (!HAS_PCH_CPT(dev) && I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) { - struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc); + struct drm_crtc *crtc = intel_dp->base.base.crtc; + /* Hardware workaround: leaving our transcoder select * set to transcoder B while it's off will prevent the * corresponding HDMI output on transcoder A. @@ -1485,7 +1486,19 @@ intel_dp_link_down(struct intel_dp *intel_dp) /* Changes to enable or select take place the vblank * after being written. */ - intel_wait_for_vblank(dev, intel_crtc->pipe); + if (crtc == NULL) { + /* We can arrive here never having been attached + * to a CRTC, for instance, due to inheriting + * random state from the BIOS. + * + * If the pipe is not running, play safe and + * wait for the clocks to stabilise before + * continuing. + */ + POSTING_READ(intel_dp->output_reg); + msleep(50); + } else + intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); } I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1d20712..831d7a4 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -140,7 +140,6 @@ struct intel_fbdev { struct intel_encoder { struct drm_encoder base; int type; - bool load_detect_temp; bool needs_tv_clock; void (*hot_plug)(struct intel_encoder *); int crtc_mask; @@ -291,13 +290,19 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void intel_wait_for_vblank(struct drm_device *dev, int pipe); extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe); -extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, - struct drm_connector *connector, - struct drm_display_mode *mode, - int *dpms_mode); + +struct intel_load_detect_pipe { + struct drm_framebuffer *release_fb; + bool load_detect_temp; + int dpms_mode; +}; +extern bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, + struct drm_connector *connector, + struct drm_display_mode *mode, + struct intel_load_detect_pipe *old); extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, struct drm_connector *connector, - int dpms_mode); + struct intel_load_detect_pipe *old); extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB); extern int intel_sdvo_supports_hotplug(struct drm_connector *connector); @@ -339,4 +344,6 @@ extern int intel_overlay_attrs(struct drm_device *dev, void *data, extern void intel_fb_output_poll_changed(struct drm_device *dev); extern void intel_fb_restore_mode(struct drm_device *dev); + +extern void intel_init_clock_gating(struct drm_device *dev); #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index a562bd2..67cb076 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -539,6 +539,9 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, struct drm_device *dev = dev_priv->dev; struct drm_connector *connector = dev_priv->int_lvds_connector; + if (dev->switch_power_state != DRM_SWITCH_POWER_ON) + return NOTIFY_OK; + /* * check and update the status of LVDS connector after receiving * the LID nofication event. diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e9e6f71..3971b5e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -236,7 +236,7 @@ init_pipe_control(struct intel_ring_buffer *ring) ret = -ENOMEM; goto err; } - obj->agp_type = AGP_USER_CACHED_MEMORY; + obj->cache_level = I915_CACHE_LLC; ret = i915_gem_object_pin(obj, 4096, true); if (ret) @@ -286,7 +286,7 @@ static int init_render_ring(struct intel_ring_buffer *ring) if (INTEL_INFO(dev)->gen > 3) { int mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH; - if (IS_GEN6(dev)) + if (IS_GEN6(dev) || IS_GEN7(dev)) mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE; I915_WRITE(MI_MODE, mode); } @@ -551,10 +551,31 @@ render_ring_put_irq(struct intel_ring_buffer *ring) void intel_ring_setup_status_page(struct intel_ring_buffer *ring) { + struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = ring->dev->dev_private; - u32 mmio = IS_GEN6(ring->dev) ? - RING_HWS_PGA_GEN6(ring->mmio_base) : - RING_HWS_PGA(ring->mmio_base); + u32 mmio = 0; + + /* The ring status page addresses are no longer next to the rest of + * the ring registers as of gen7. + */ + if (IS_GEN7(dev)) { + switch (ring->id) { + case RING_RENDER: + mmio = RENDER_HWS_PGA_GEN7; + break; + case RING_BLT: + mmio = BLT_HWS_PGA_GEN7; + break; + case RING_BSD: + mmio = BSD_HWS_PGA_GEN7; + break; + } + } else if (IS_GEN6(ring->dev)) { + mmio = RING_HWS_PGA_GEN6(ring->mmio_base); + } else { + mmio = RING_HWS_PGA(ring->mmio_base); + } + I915_WRITE(mmio, (u32)ring->status_page.gfx_addr); POSTING_READ(mmio); } @@ -759,7 +780,7 @@ static int init_status_page(struct intel_ring_buffer *ring) ret = -ENOMEM; goto err; } - obj->agp_type = AGP_USER_CACHED_MEMORY; + obj->cache_level = I915_CACHE_LLC; ret = i915_gem_object_pin(obj, 4096, true); if (ret != 0) { @@ -800,6 +821,7 @@ int intel_init_ring_buffer(struct drm_device *dev, INIT_LIST_HEAD(&ring->request_list); INIT_LIST_HEAD(&ring->gpu_write_list); + init_waitqueue_head(&ring->irq_queue); spin_lock_init(&ring->irq_lock); ring->irq_mask = ~0; @@ -872,7 +894,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) /* Disable the ring buffer. The ring must be idle at this point */ dev_priv = ring->dev->dev_private; - ret = intel_wait_ring_buffer(ring, ring->size - 8); + ret = intel_wait_ring_idle(ring); if (ret) DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n", ring->name, ret); @@ -1333,7 +1355,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring = &dev_priv->ring[VCS]; - if (IS_GEN6(dev)) + if (IS_GEN6(dev) || IS_GEN7(dev)) *ring = gen6_bsd_ring; else *ring = bsd_ring; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index f23cc5f..c0e0ee6 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -14,27 +14,24 @@ struct intel_hw_status_page { struct drm_i915_gem_object *obj; }; -#define I915_RING_READ(reg) i915_gt_read(dev_priv, reg) -#define I915_RING_WRITE(reg, val) i915_gt_write(dev_priv, reg, val) +#define I915_READ_TAIL(ring) I915_READ(RING_TAIL((ring)->mmio_base)) +#define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL((ring)->mmio_base), val) -#define I915_READ_TAIL(ring) I915_RING_READ(RING_TAIL((ring)->mmio_base)) -#define I915_WRITE_TAIL(ring, val) I915_RING_WRITE(RING_TAIL((ring)->mmio_base), val) +#define I915_READ_START(ring) I915_READ(RING_START((ring)->mmio_base)) +#define I915_WRITE_START(ring, val) I915_WRITE(RING_START((ring)->mmio_base), val) -#define I915_READ_START(ring) I915_RING_READ(RING_START((ring)->mmio_base)) -#define I915_WRITE_START(ring, val) I915_RING_WRITE(RING_START((ring)->mmio_base), val) +#define I915_READ_HEAD(ring) I915_READ(RING_HEAD((ring)->mmio_base)) +#define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD((ring)->mmio_base), val) -#define I915_READ_HEAD(ring) I915_RING_READ(RING_HEAD((ring)->mmio_base)) -#define I915_WRITE_HEAD(ring, val) I915_RING_WRITE(RING_HEAD((ring)->mmio_base), val) +#define I915_READ_CTL(ring) I915_READ(RING_CTL((ring)->mmio_base)) +#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL((ring)->mmio_base), val) -#define I915_READ_CTL(ring) I915_RING_READ(RING_CTL((ring)->mmio_base)) -#define I915_WRITE_CTL(ring, val) I915_RING_WRITE(RING_CTL((ring)->mmio_base), val) +#define I915_READ_IMR(ring) I915_READ(RING_IMR((ring)->mmio_base)) +#define I915_WRITE_IMR(ring, val) I915_WRITE(RING_IMR((ring)->mmio_base), val) -#define I915_READ_IMR(ring) I915_RING_READ(RING_IMR((ring)->mmio_base)) -#define I915_WRITE_IMR(ring, val) I915_RING_WRITE(RING_IMR((ring)->mmio_base), val) - -#define I915_READ_NOPID(ring) I915_RING_READ(RING_NOPID((ring)->mmio_base)) -#define I915_READ_SYNC_0(ring) I915_RING_READ(RING_SYNC_0((ring)->mmio_base)) -#define I915_READ_SYNC_1(ring) I915_RING_READ(RING_SYNC_1((ring)->mmio_base)) +#define I915_READ_NOPID(ring) I915_READ(RING_NOPID((ring)->mmio_base)) +#define I915_READ_SYNC_0(ring) I915_READ(RING_SYNC_0((ring)->mmio_base)) +#define I915_READ_SYNC_1(ring) I915_READ(RING_SYNC_1((ring)->mmio_base)) struct intel_ring_buffer { const char *name; @@ -164,7 +161,13 @@ intel_read_status_page(struct intel_ring_buffer *ring, #define I915_BREADCRUMB_INDEX 0x21 void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring); + int __must_check intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n); +static inline int intel_wait_ring_idle(struct intel_ring_buffer *ring) +{ + return intel_wait_ring_buffer(ring, ring->space - 8); +} + int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n); static inline void intel_ring_emit(struct intel_ring_buffer *ring, diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 6b22c1d..113e4e7 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1361,15 +1361,14 @@ intel_tv_detect(struct drm_connector *connector, bool force) if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) { type = intel_tv_detect_type(intel_tv, connector); } else if (force) { - struct drm_crtc *crtc; - int dpms_mode; + struct intel_load_detect_pipe tmp; - crtc = intel_get_load_detect_pipe(&intel_tv->base, connector, - &mode, &dpms_mode); - if (crtc) { + if (intel_get_load_detect_pipe(&intel_tv->base, connector, + &mode, &tmp)) { type = intel_tv_detect_type(intel_tv, connector); - intel_release_load_detect_pipe(&intel_tv->base, connector, - dpms_mode); + intel_release_load_detect_pipe(&intel_tv->base, + connector, + &tmp); } else return connector_status_unknown; } else diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index e9bc135..c20eac3 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -862,9 +862,15 @@ int evergreen_pcie_gart_enable(struct radeon_device *rdev) SYSTEM_ACCESS_MODE_NOT_IN_SYS | SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU | EFFECTIVE_L1_TLB_SIZE(5) | EFFECTIVE_L1_QUEUE_SIZE(5); - WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp); - WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp); - WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp); + if (rdev->flags & RADEON_IS_IGP) { + WREG32(FUS_MC_VM_MD_L1_TLB0_CNTL, tmp); + WREG32(FUS_MC_VM_MD_L1_TLB1_CNTL, tmp); + WREG32(FUS_MC_VM_MD_L1_TLB2_CNTL, tmp); + } else { + WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp); + WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp); + WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp); + } WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); @@ -2923,11 +2929,6 @@ static int evergreen_startup(struct radeon_device *rdev) rdev->asic->copy = NULL; dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r); } - /* XXX: ontario has problems blitting to gart at the moment */ - if (rdev->family == CHIP_PALM) { - rdev->asic->copy = NULL; - radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); - } /* allocate wb buffer */ r = radeon_wb_init(rdev); diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 9aaa3f0..9453384 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -221,6 +221,11 @@ #define MC_VM_MD_L1_TLB0_CNTL 0x2654 #define MC_VM_MD_L1_TLB1_CNTL 0x2658 #define MC_VM_MD_L1_TLB2_CNTL 0x265C + +#define FUS_MC_VM_MD_L1_TLB0_CNTL 0x265C +#define FUS_MC_VM_MD_L1_TLB1_CNTL 0x2660 +#define FUS_MC_VM_MD_L1_TLB2_CNTL 0x2664 + #define MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x203C #define MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2038 #define MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2034 diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index f5d12fb..f116516 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1599,9 +1599,10 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0], fake_edid_record->ucFakeEDIDLength); - if (drm_edid_is_valid(edid)) + if (drm_edid_is_valid(edid)) { rdev->mode_info.bios_hardcoded_edid = edid; - else + rdev->mode_info.bios_hardcoded_edid_size = edid_size; + } else kfree(edid); } } diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 871df03..bd58af6 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -234,6 +234,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) return -EINVAL; } break; + case RADEON_INFO_FUSION_GART_WORKING: + value = 1; + break; default: DRM_DEBUG_KMS("Invalid request %d\n", info->request); return -EINVAL; diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 060ef63..50e40db 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -110,8 +110,7 @@ config SENSORS_ADM1021 help If you say yes here you get support for Analog Devices ADM1021 and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A, - Genesys Logic GL523SM, National Semiconductor LM84, TI THMC10, - and the XEON processor built-in sensor. + Genesys Logic GL523SM, National Semiconductor LM84 and TI THMC10. This driver can also be built as a module. If so, the module will be called adm1021. @@ -618,10 +617,10 @@ config SENSORS_LM90 depends on I2C help If you say yes here you get support for National Semiconductor LM90, - LM86, LM89 and LM99, Analog Devices ADM1032 and ADT7461, Maxim - MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659, - MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, and Winbond/Nuvoton - W83L771W/G/AWG/ASG sensor chips. + LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A, + Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659, + MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, ON Semiconductor NCT1008, + and Winbond/Nuvoton W83L771W/G/AWG/ASG sensor chips. This driver can also be built as a module. If so, the module will be called lm90. diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index 250d099..da72dc1 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -1094,6 +1094,7 @@ static struct attribute *lm85_attributes_minctl[] = { &sensor_dev_attr_pwm1_auto_pwm_minctl.dev_attr.attr, &sensor_dev_attr_pwm2_auto_pwm_minctl.dev_attr.attr, &sensor_dev_attr_pwm3_auto_pwm_minctl.dev_attr.attr, + NULL }; static const struct attribute_group lm85_group_minctl = { @@ -1104,6 +1105,7 @@ static struct attribute *lm85_attributes_temp_off[] = { &sensor_dev_attr_temp1_auto_temp_off.dev_attr.attr, &sensor_dev_attr_temp2_auto_temp_off.dev_attr.attr, &sensor_dev_attr_temp3_auto_temp_off.dev_attr.attr, + NULL }; static const struct attribute_group lm85_group_temp_off = { @@ -1329,11 +1331,11 @@ static int lm85_probe(struct i2c_client *client, if (data->type != emc6d103s) { err = sysfs_create_group(&client->dev.kobj, &lm85_group_minctl); if (err) - goto err_kfree; + goto err_remove_files; err = sysfs_create_group(&client->dev.kobj, &lm85_group_temp_off); if (err) - goto err_kfree; + goto err_remove_files; } /* The ADT7463/68 have an optional VRM 10 mode where pin 21 is used diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index c43b4e9..2f94f95 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -49,10 +49,10 @@ * chips, but support three temperature sensors instead of two. MAX6695 * and MAX6696 only differ in the pinout so they can be treated identically. * - * This driver also supports the ADT7461 chip from Analog Devices. - * It's supported in both compatibility and extended mode. It is mostly - * compatible with LM90 except for a data format difference for the - * temperature value registers. + * This driver also supports ADT7461 and ADT7461A from Analog Devices as well as + * NCT1008 from ON Semiconductor. The chips are supported in both compatibility + * and extended mode. They are mostly compatible with LM90 except for a data + * format difference for the temperature value registers. * * Since the LM90 was the first chipset supported by this driver, most * comments will refer to this chipset, but are actually general and @@ -88,9 +88,10 @@ * Addresses to scan * Address is fully defined internally and cannot be changed except for * MAX6659, MAX6680 and MAX6681. - * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6649, MAX6657, - * MAX6658 and W83L771 have address 0x4c. - * ADM1032-2, ADT7461-2, LM89-1, LM99-1 and MAX6646 have address 0x4d. + * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, ADT7461A, MAX6649, + * MAX6657, MAX6658, NCT1008 and W83L771 have address 0x4c. + * ADM1032-2, ADT7461-2, ADT7461A-2, LM89-1, LM99-1, MAX6646, and NCT1008D + * have address 0x4d. * MAX6647 has address 0x4e. * MAX6659 can have address 0x4c, 0x4d or 0x4e. * MAX6680 and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, @@ -174,6 +175,7 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680, static const struct i2c_device_id lm90_id[] = { { "adm1032", adm1032 }, { "adt7461", adt7461 }, + { "adt7461a", adt7461 }, { "lm90", lm90 }, { "lm86", lm86 }, { "lm89", lm86 }, @@ -188,6 +190,7 @@ static const struct i2c_device_id lm90_id[] = { { "max6681", max6680 }, { "max6695", max6696 }, { "max6696", max6696 }, + { "nct1008", adt7461 }, { "w83l771", w83l771 }, { } }; @@ -1153,6 +1156,11 @@ static int lm90_detect(struct i2c_client *new_client, && (reg_config1 & 0x1B) == 0x00 && reg_convrate <= 0x0A) { name = "adt7461"; + } else + if (chip_id == 0x57 /* ADT7461A, NCT1008 */ + && (reg_config1 & 0x1B) == 0x00 + && reg_convrate <= 0x0A) { + name = "adt7461a"; } } else if (man_id == 0x4D) { /* Maxim */ diff --git a/drivers/hwmon/twl4030-madc-hwmon.c b/drivers/hwmon/twl4030-madc-hwmon.c index de58191..5724074 100644 --- a/drivers/hwmon/twl4030-madc-hwmon.c +++ b/drivers/hwmon/twl4030-madc-hwmon.c @@ -98,7 +98,6 @@ static const struct attribute_group twl4030_madc_group = { static int __devinit twl4030_madc_hwmon_probe(struct platform_device *pdev) { int ret; - int status; struct device *hwmon; ret = sysfs_create_group(&pdev->dev.kobj, &twl4030_madc_group); @@ -107,7 +106,7 @@ static int __devinit twl4030_madc_hwmon_probe(struct platform_device *pdev) hwmon = hwmon_device_register(&pdev->dev); if (IS_ERR(hwmon)) { dev_err(&pdev->dev, "hwmon_device_register failed.\n"); - status = PTR_ERR(hwmon); + ret = PTR_ERR(hwmon); goto err_reg; } diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 72c0415f..455e909 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -134,10 +134,15 @@ SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \ SMBHSTSTS_INTR) +/* Older devices have their ID defined in <linux/pci_ids.h> */ +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22 +#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22 /* Patsburg also has three 'Integrated Device Function' SMBus controllers */ #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0 0x1d70 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1 0x1d71 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72 +#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 +#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 struct i801_priv { struct i2c_adapter adapter; diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 0eb1515..2dbba16 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------ * * i2c-parport.c I2C bus over parallel port * * ------------------------------------------------------------------------ * - Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org> + Copyright (C) 2003-2011 Jean Delvare <khali@linux-fr.org> Based on older i2c-philips-par.c driver Copyright (C) 1995-2000 Simon G. Vogl @@ -33,6 +33,8 @@ #include <linux/i2c-algo-bit.h> #include <linux/i2c-smbus.h> #include <linux/slab.h> +#include <linux/list.h> +#include <linux/mutex.h> #include "i2c-parport.h" /* ----- Device list ------------------------------------------------------ */ @@ -43,10 +45,11 @@ struct i2c_par { struct i2c_algo_bit_data algo_data; struct i2c_smbus_alert_setup alert_data; struct i2c_client *ara; - struct i2c_par *next; + struct list_head node; }; -static struct i2c_par *adapter_list; +static LIST_HEAD(adapter_list); +static DEFINE_MUTEX(adapter_list_lock); /* ----- Low-level parallel port access ----------------------------------- */ @@ -228,8 +231,9 @@ static void i2c_parport_attach (struct parport *port) } /* Add the new adapter to the list */ - adapter->next = adapter_list; - adapter_list = adapter; + mutex_lock(&adapter_list_lock); + list_add_tail(&adapter->node, &adapter_list); + mutex_unlock(&adapter_list_lock); return; ERROR1: @@ -241,11 +245,11 @@ ERROR0: static void i2c_parport_detach (struct parport *port) { - struct i2c_par *adapter, *prev; + struct i2c_par *adapter, *_n; /* Walk the list */ - for (prev = NULL, adapter = adapter_list; adapter; - prev = adapter, adapter = adapter->next) { + mutex_lock(&adapter_list_lock); + list_for_each_entry_safe(adapter, _n, &adapter_list, node) { if (adapter->pdev->port == port) { if (adapter->ara) { parport_disable_irq(port); @@ -259,14 +263,11 @@ static void i2c_parport_detach (struct parport *port) parport_release(adapter->pdev); parport_unregister_device(adapter->pdev); - if (prev) - prev->next = adapter->next; - else - adapter_list = adapter->next; + list_del(&adapter->node); kfree(adapter); - return; } } + mutex_unlock(&adapter_list_lock); } static struct parport_driver i2c_parport_driver = { diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c index 7de4b7e..d8ca0a0 100644 --- a/drivers/infiniband/hw/qib/qib_iba6120.c +++ b/drivers/infiniband/hw/qib/qib_iba6120.c @@ -1799,7 +1799,7 @@ static int qib_6120_setup_reset(struct qib_devdata *dd) /* * Keep chip from being accessed until we are ready. Use * writeq() directly, to allow the write even though QIB_PRESENT - * isn't' set. + * isn't set. */ dd->flags &= ~(QIB_INITTED | QIB_PRESENT); dd->int_counter = 0; /* so we check interrupts work again */ diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c index 74fe036..c765a2e 100644 --- a/drivers/infiniband/hw/qib/qib_iba7220.c +++ b/drivers/infiniband/hw/qib/qib_iba7220.c @@ -2111,7 +2111,7 @@ static int qib_setup_7220_reset(struct qib_devdata *dd) /* * Keep chip from being accessed until we are ready. Use * writeq() directly, to allow the write even though QIB_PRESENT - * isn't' set. + * isn't set. */ dd->flags &= ~(QIB_INITTED | QIB_PRESENT); dd->int_counter = 0; /* so we check interrupts work again */ diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 55de3cf..6bab3ea 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -3299,7 +3299,7 @@ static int qib_do_7322_reset(struct qib_devdata *dd) /* * Keep chip from being accessed until we are ready. Use * writeq() directly, to allow the write even though QIB_PRESENT - * isn't' set. + * isn't set. */ dd->flags &= ~(QIB_INITTED | QIB_PRESENT | QIB_BADINTR); dd->flags |= QIB_DOING_RESET; diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 6ae054f..9175d49 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -68,8 +68,23 @@ struct wm831x_ts { unsigned int pd_irq; bool pressure; bool pen_down; + struct work_struct pd_data_work; }; +static void wm831x_pd_data_work(struct work_struct *work) +{ + struct wm831x_ts *wm831x_ts = + container_of(work, struct wm831x_ts, pd_data_work); + + if (wm831x_ts->pen_down) { + enable_irq(wm831x_ts->data_irq); + dev_dbg(wm831x_ts->wm831x->dev, "IRQ PD->DATA done\n"); + } else { + enable_irq(wm831x_ts->pd_irq); + dev_dbg(wm831x_ts->wm831x->dev, "IRQ DATA->PD done\n"); + } +} + static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) { struct wm831x_ts *wm831x_ts = irq_data; @@ -110,6 +125,9 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) } if (!wm831x_ts->pen_down) { + /* Switch from data to pen down */ + dev_dbg(wm831x->dev, "IRQ DATA->PD\n"); + disable_irq_nosync(wm831x_ts->data_irq); /* Don't need data any more */ @@ -128,6 +146,10 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) ABS_PRESSURE, 0); input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 0); + + schedule_work(&wm831x_ts->pd_data_work); + } else { + input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1); } input_sync(wm831x_ts->input_dev); @@ -141,6 +163,11 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) struct wm831x *wm831x = wm831x_ts->wm831x; int ena = 0; + if (wm831x_ts->pen_down) + return IRQ_HANDLED; + + disable_irq_nosync(wm831x_ts->pd_irq); + /* Start collecting data */ if (wm831x_ts->pressure) ena |= WM831X_TCH_Z_ENA; @@ -149,14 +176,14 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | ena); - input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1); - input_sync(wm831x_ts->input_dev); - wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1, WM831X_TCHPD_EINT, WM831X_TCHPD_EINT); wm831x_ts->pen_down = true; - enable_irq(wm831x_ts->data_irq); + + /* Switch from pen down to data */ + dev_dbg(wm831x->dev, "IRQ PD->DATA\n"); + schedule_work(&wm831x_ts->pd_data_work); return IRQ_HANDLED; } @@ -182,13 +209,28 @@ static void wm831x_ts_input_close(struct input_dev *idev) struct wm831x_ts *wm831x_ts = input_get_drvdata(idev); struct wm831x *wm831x = wm831x_ts->wm831x; + /* Shut the controller down, disabling all other functionality too */ wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, - WM831X_TCH_ENA | WM831X_TCH_CVT_ENA | - WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | - WM831X_TCH_Z_ENA, 0); + WM831X_TCH_ENA | WM831X_TCH_X_ENA | + WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, 0); - if (wm831x_ts->pen_down) + /* Make sure any pending IRQs are done, the above will prevent + * new ones firing. + */ + synchronize_irq(wm831x_ts->data_irq); + synchronize_irq(wm831x_ts->pd_irq); + + /* Make sure the IRQ completion work is quiesced */ + flush_work_sync(&wm831x_ts->pd_data_work); + + /* If we ended up with the pen down then make sure we revert back + * to pen detection state for the next time we start up. + */ + if (wm831x_ts->pen_down) { disable_irq(wm831x_ts->data_irq); + enable_irq(wm831x_ts->pd_irq); + wm831x_ts->pen_down = false; + } } static __devinit int wm831x_ts_probe(struct platform_device *pdev) @@ -198,7 +240,7 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) struct wm831x_pdata *core_pdata = dev_get_platdata(pdev->dev.parent); struct wm831x_touch_pdata *pdata = NULL; struct input_dev *input_dev; - int error; + int error, irqf; if (core_pdata) pdata = core_pdata->touch; @@ -212,6 +254,7 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) wm831x_ts->wm831x = wm831x; wm831x_ts->input_dev = input_dev; + INIT_WORK(&wm831x_ts->pd_data_work, wm831x_pd_data_work); /* * If we have a direct IRQ use it, otherwise use the interrupt @@ -270,9 +313,14 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, WM831X_TCH_RATE_MASK, 6); + if (pdata && pdata->data_irqf) + irqf = pdata->data_irqf; + else + irqf = IRQF_TRIGGER_HIGH; + error = request_threaded_irq(wm831x_ts->data_irq, NULL, wm831x_ts_data_irq, - IRQF_ONESHOT, + irqf | IRQF_ONESHOT, "Touchscreen data", wm831x_ts); if (error) { dev_err(&pdev->dev, "Failed to request data IRQ %d: %d\n", @@ -281,9 +329,14 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) } disable_irq(wm831x_ts->data_irq); + if (pdata && pdata->pd_irqf) + irqf = pdata->pd_irqf; + else + irqf = IRQF_TRIGGER_HIGH; + error = request_threaded_irq(wm831x_ts->pd_irq, NULL, wm831x_ts_pen_down_irq, - IRQF_ONESHOT, + irqf | IRQF_ONESHOT, "Touchscreen pen down", wm831x_ts); if (error) { dev_err(&pdev->dev, "Failed to request pen down IRQ %d: %d\n", diff --git a/drivers/media/common/tuners/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c index 5466d47..aae40e5 100644 --- a/drivers/media/common/tuners/tda18271-common.c +++ b/drivers/media/common/tuners/tda18271-common.c @@ -533,16 +533,7 @@ int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) if (tda_fail(ret)) goto fail; - regs[R_MPD] = (0x77 & pd); - - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_MPD] &= ~0x08; - break; - case TDA18271_DIGITAL: - regs[R_MPD] |= 0x08; - break; - } + regs[R_MPD] = (0x7f & pd); div = ((d * (freq / 1000)) << 7) / 125; diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c index 9ad4454..d884f5e 100644 --- a/drivers/media/common/tuners/tda18271-fe.c +++ b/drivers/media/common/tuners/tda18271-fe.c @@ -579,8 +579,8 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) #define RF3 2 u32 rf_default[3]; u32 rf_freq[3]; - u8 prog_cal[3]; - u8 prog_tab[3]; + s32 prog_cal[3]; + s32 prog_tab[3]; i = tda18271_lookup_rf_band(fe, &freq, NULL); @@ -602,32 +602,33 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) return bcal; tda18271_calc_rf_cal(fe, &rf_freq[rf]); - prog_tab[rf] = regs[R_EB14]; + prog_tab[rf] = (s32)regs[R_EB14]; if (1 == bcal) - prog_cal[rf] = tda18271_calibrate_rf(fe, rf_freq[rf]); + prog_cal[rf] = + (s32)tda18271_calibrate_rf(fe, rf_freq[rf]); else prog_cal[rf] = prog_tab[rf]; switch (rf) { case RF1: map[i].rf_a1 = 0; - map[i].rf_b1 = (s32)(prog_cal[RF1] - prog_tab[RF1]); + map[i].rf_b1 = (prog_cal[RF1] - prog_tab[RF1]); map[i].rf1 = rf_freq[RF1] / 1000; break; case RF2: - dividend = (s32)(prog_cal[RF2] - prog_tab[RF2]) - - (s32)(prog_cal[RF1] + prog_tab[RF1]); + dividend = (prog_cal[RF2] - prog_tab[RF2] - + prog_cal[RF1] + prog_tab[RF1]); divisor = (s32)(rf_freq[RF2] - rf_freq[RF1]) / 1000; map[i].rf_a1 = (dividend / divisor); map[i].rf2 = rf_freq[RF2] / 1000; break; case RF3: - dividend = (s32)(prog_cal[RF3] - prog_tab[RF3]) - - (s32)(prog_cal[RF2] + prog_tab[RF2]); + dividend = (prog_cal[RF3] - prog_tab[RF3] - + prog_cal[RF2] + prog_tab[RF2]); divisor = (s32)(rf_freq[RF3] - rf_freq[RF2]) / 1000; map[i].rf_a2 = (dividend / divisor); - map[i].rf_b2 = (s32)(prog_cal[RF2] - prog_tab[RF2]); + map[i].rf_b2 = (prog_cal[RF2] - prog_tab[RF2]); map[i].rf3 = rf_freq[RF3] / 1000; break; default: diff --git a/drivers/media/common/tuners/tda18271-maps.c b/drivers/media/common/tuners/tda18271-maps.c index e7f84c7..3d5b6ab 100644 --- a/drivers/media/common/tuners/tda18271-maps.c +++ b/drivers/media/common/tuners/tda18271-maps.c @@ -229,8 +229,7 @@ static struct tda18271_map tda18271c2_km[] = { static struct tda18271_map tda18271_rf_band[] = { { .rfmax = 47900, .val = 0x00 }, { .rfmax = 61100, .val = 0x01 }, -/* { .rfmax = 152600, .val = 0x02 }, */ - { .rfmax = 121200, .val = 0x02 }, + { .rfmax = 152600, .val = 0x02 }, { .rfmax = 164700, .val = 0x03 }, { .rfmax = 203500, .val = 0x04 }, { .rfmax = 457800, .val = 0x05 }, @@ -448,7 +447,7 @@ static struct tda18271_map tda18271c2_rf_cal[] = { { .rfmax = 150000, .val = 0xb0 }, { .rfmax = 151000, .val = 0xb1 }, { .rfmax = 152000, .val = 0xb7 }, - { .rfmax = 153000, .val = 0xbd }, + { .rfmax = 152600, .val = 0xbd }, { .rfmax = 154000, .val = 0x20 }, { .rfmax = 155000, .val = 0x22 }, { .rfmax = 156000, .val = 0x24 }, @@ -459,7 +458,7 @@ static struct tda18271_map tda18271c2_rf_cal[] = { { .rfmax = 161000, .val = 0x2d }, { .rfmax = 163000, .val = 0x2e }, { .rfmax = 164000, .val = 0x2f }, - { .rfmax = 165000, .val = 0x30 }, + { .rfmax = 164700, .val = 0x30 }, { .rfmax = 166000, .val = 0x11 }, { .rfmax = 167000, .val = 0x12 }, { .rfmax = 168000, .val = 0x13 }, @@ -510,7 +509,8 @@ static struct tda18271_map tda18271c2_rf_cal[] = { { .rfmax = 236000, .val = 0x1b }, { .rfmax = 237000, .val = 0x1c }, { .rfmax = 240000, .val = 0x1d }, - { .rfmax = 242000, .val = 0x1f }, + { .rfmax = 242000, .val = 0x1e }, + { .rfmax = 244000, .val = 0x1f }, { .rfmax = 247000, .val = 0x20 }, { .rfmax = 249000, .val = 0x21 }, { .rfmax = 252000, .val = 0x22 }, @@ -624,7 +624,7 @@ static struct tda18271_map tda18271c2_rf_cal[] = { { .rfmax = 453000, .val = 0x93 }, { .rfmax = 454000, .val = 0x94 }, { .rfmax = 456000, .val = 0x96 }, - { .rfmax = 457000, .val = 0x98 }, + { .rfmax = 457800, .val = 0x98 }, { .rfmax = 461000, .val = 0x11 }, { .rfmax = 468000, .val = 0x12 }, { .rfmax = 472000, .val = 0x13 }, diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c index 9552540..03f96d6 100644 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/drivers/media/dvb/b2c2/flexcop-pci.c @@ -38,7 +38,7 @@ MODULE_PARM_DESC(debug, DEBSTATUS); #define DRIVER_VERSION "0.1" -#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver" +#define DRIVER_NAME "flexcop-pci" #define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>" struct flexcop_pci { diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index fe4f894..ccbd39a 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -362,7 +362,7 @@ config DVB_USB_LME2510 config DVB_USB_TECHNISAT_USB2 tristate "Technisat DVB-S/S2 USB2.0 support" depends on DVB_USB - select DVB_STB0899 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE + select DVB_STV090x if !DVB_FE_CUSTOMISE + select DVB_STV6110x if !DVB_FE_CUSTOMISE help Say Y here to support the Technisat USB2 DVB-S/S2 device diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 97af266..65214af 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -2162,7 +2162,7 @@ struct dibx000_agc_config dib7090_agc_config[2] = { .agc1_pt3 = 98, .agc1_slope1 = 0, .agc1_slope2 = 167, - .agc1_pt1 = 98, + .agc2_pt1 = 98, .agc2_pt2 = 255, .agc2_slope1 = 104, .agc2_slope2 = 0, @@ -2440,11 +2440,11 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) dib0700_set_i2c_speed(adap->dev, 340); adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]); - dib7090_slave_reset(adap->fe); - if (adap->fe == NULL) return -ENODEV; + dib7090_slave_reset(adap->fe); + return 0; } diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index 23640ed..056138f 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c @@ -378,7 +378,6 @@ EXPORT_SYMBOL_GPL(media_entity_create_link); static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) { - const u32 mask = MEDIA_LNK_FL_ENABLED; int ret; /* Notify both entities. */ @@ -395,7 +394,7 @@ static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) return ret; } - link->flags = (link->flags & ~mask) | (flags & mask); + link->flags = flags; link->reverse->flags = link->flags; return 0; @@ -417,6 +416,7 @@ static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) */ int __media_entity_setup_link(struct media_link *link, u32 flags) { + const u32 mask = MEDIA_LNK_FL_ENABLED; struct media_device *mdev; struct media_entity *source, *sink; int ret = -EBUSY; @@ -424,6 +424,10 @@ int __media_entity_setup_link(struct media_link *link, u32 flags) if (link == NULL) return -EINVAL; + /* The non-modifiable link flags must not be modified. */ + if ((link->flags & ~mask) != (flags & ~mask)) + return -EINVAL; + if (link->flags & MEDIA_LNK_FL_IMMUTABLE) return link->flags == flags ? 0 : -EINVAL; diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index dc3f04c..87bad76 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -170,7 +170,7 @@ static int fmr2_setfreq(struct fmr2 *dev) return 0; } -/* !!! not tested, in my card this does't work !!! */ +/* !!! not tested, in my card this doesn't work !!! */ static int fmr2_setvolume(struct fmr2 *dev) { int vol[16] = { 0x021, 0x084, 0x090, 0x104, diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 4498b94..00f51dd 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -875,7 +875,7 @@ config MX3_VIDEO config VIDEO_MX3 tristate "i.MX3x Camera Sensor Interface driver" depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA - select VIDEOBUF_DMA_CONTIG + select VIDEOBUF2_DMA_CONTIG select MX3_VIDEO ---help--- This is a v4l2 driver for the i.MX3x Camera Sensor Interface diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index c6e2ca3..6fbc356 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c @@ -350,9 +350,17 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister) /* No struct video_device, but can have buffers allocated */ if (type == CX18_ENC_STREAM_TYPE_IDX) { + /* If the module params didn't inhibit IDX ... */ if (cx->stream_buffers[type] != 0) { cx->stream_buffers[type] = 0; - cx18_stream_free(&cx->streams[type]); + /* + * Before calling cx18_stream_free(), + * check if the IDX stream was actually set up. + * Needed, since the cx18_probe() error path + * exits through here as well as normal clean up + */ + if (cx->streams[type].buffers != 0) + cx18_stream_free(&cx->streams[type]); } continue; } diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index 3b6e7f2..caab1bf 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -22,6 +22,7 @@ config VIDEO_CX23885 select DVB_CX24116 if !DVB_FE_CUSTOMISE select DVB_STV0900 if !DVB_FE_CUSTOMISE select DVB_DS3000 if !DVB_FE_CUSTOMISE + select DVB_STV0367 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c index 1a11691..0382ea7 100644 --- a/drivers/media/video/imx074.c +++ b/drivers/media/video/imx074.c @@ -298,7 +298,7 @@ static unsigned long imx074_query_bus_param(struct soc_camera_device *icd) static int imx074_set_bus_param(struct soc_camera_device *icd, unsigned long flags) { - return -1; + return -EINVAL; } static struct soc_camera_ops imx074_ops = { diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index 503bd79..472a693 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -215,20 +215,21 @@ static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel) } switch (xclksel) { - case 0: + case ISP_XCLK_A: isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, ISPTCTRL_CTRL_DIVA_MASK, divisor << ISPTCTRL_CTRL_DIVA_SHIFT); dev_dbg(isp->dev, "isp_set_xclk(): cam_xclka set to %d Hz\n", currentxclk); break; - case 1: + case ISP_XCLK_B: isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, ISPTCTRL_CTRL_DIVB_MASK, divisor << ISPTCTRL_CTRL_DIVB_SHIFT); dev_dbg(isp->dev, "isp_set_xclk(): cam_xclkb set to %d Hz\n", currentxclk); break; + case ISP_XCLK_NONE: default: omap3isp_put(isp); dev_dbg(isp->dev, "ISP_ERR: isp_set_xclk(): Invalid requested " @@ -237,13 +238,13 @@ static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel) } /* Do we go from stable whatever to clock? */ - if (divisor >= 2 && isp->xclk_divisor[xclksel] < 2) + if (divisor >= 2 && isp->xclk_divisor[xclksel - 1] < 2) omap3isp_get(isp); /* Stopping the clock. */ - else if (divisor < 2 && isp->xclk_divisor[xclksel] >= 2) + else if (divisor < 2 && isp->xclk_divisor[xclksel - 1] >= 2) omap3isp_put(isp); - isp->xclk_divisor[xclksel] = divisor; + isp->xclk_divisor[xclksel - 1] = divisor; omap3isp_put(isp); @@ -285,7 +286,8 @@ static void isp_power_settings(struct isp_device *isp, int idle) */ void omap3isp_configure_bridge(struct isp_device *isp, enum ccdc_input_entity input, - const struct isp_parallel_platform_data *pdata) + const struct isp_parallel_platform_data *pdata, + unsigned int shift) { u32 ispctrl_val; @@ -298,9 +300,9 @@ void omap3isp_configure_bridge(struct isp_device *isp, switch (input) { case CCDC_INPUT_PARALLEL: ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL; - ispctrl_val |= pdata->data_lane_shift << ISPCTRL_SHIFT_SHIFT; ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT; ispctrl_val |= pdata->bridge << ISPCTRL_PAR_BRIDGE_SHIFT; + shift += pdata->data_lane_shift * 2; break; case CCDC_INPUT_CSI2A: @@ -319,6 +321,8 @@ void omap3isp_configure_bridge(struct isp_device *isp, return; } + ispctrl_val |= ((shift/2) << ISPCTRL_SHIFT_SHIFT) & ISPCTRL_SHIFT_MASK; + ispctrl_val &= ~ISPCTRL_SYNC_DETECT_MASK; ispctrl_val |= ISPCTRL_SYNC_DETECT_VSRISE; @@ -658,6 +662,8 @@ int omap3isp_pipeline_pm_use(struct media_entity *entity, int use) /* Apply power change to connected non-nodes. */ ret = isp_pipeline_pm_power(entity, change); + if (ret < 0) + entity->use_count -= change; mutex_unlock(&entity->parent->graph_mutex); @@ -872,6 +878,9 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) } } + if (failure < 0) + isp->needs_reset = true; + return failure; } @@ -884,7 +893,8 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) * single-shot or continuous mode. * * Return 0 if successful, or the return value of the failed video::s_stream - * operation otherwise. + * operation otherwise. The pipeline state is not updated when the operation + * fails, except when stopping the pipeline. */ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, enum isp_pipeline_stream_state state) @@ -895,7 +905,9 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, ret = isp_pipeline_disable(pipe); else ret = isp_pipeline_enable(pipe, state); - pipe->stream_state = state; + + if (ret == 0 || state == ISP_PIPELINE_STREAM_STOPPED) + pipe->stream_state = state; return ret; } @@ -1481,6 +1493,10 @@ void omap3isp_put(struct isp_device *isp) if (--isp->ref_count == 0) { isp_disable_interrupts(isp); isp_save_ctx(isp); + if (isp->needs_reset) { + isp_reset(isp); + isp->needs_reset = false; + } isp_disable_clocks(isp); } mutex_unlock(&isp->isp_mutex); diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h index cf5214e..2620c40 100644 --- a/drivers/media/video/omap3isp/isp.h +++ b/drivers/media/video/omap3isp/isp.h @@ -132,7 +132,6 @@ struct isp_reg { /** * struct isp_parallel_platform_data - Parallel interface platform data - * @width: Parallel bus width in bits (8, 10, 11 or 12) * @data_lane_shift: Data lane shifter * 0 - CAMEXT[13:0] -> CAM[13:0] * 1 - CAMEXT[13:2] -> CAM[11:0] @@ -146,7 +145,6 @@ struct isp_reg { * ISPCTRL_PAR_BRIDGE_BENDIAN - Big endian */ struct isp_parallel_platform_data { - unsigned int width; unsigned int data_lane_shift:2; unsigned int clk_pol:1; unsigned int bridge:4; @@ -262,6 +260,7 @@ struct isp_device { /* ISP Obj */ spinlock_t stat_lock; /* common lock for statistic drivers */ struct mutex isp_mutex; /* For handling ref_count field */ + bool needs_reset; int has_context; int ref_count; unsigned int autoidle; @@ -311,11 +310,12 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, enum isp_pipeline_stream_state state); void omap3isp_configure_bridge(struct isp_device *isp, enum ccdc_input_entity input, - const struct isp_parallel_platform_data *pdata); + const struct isp_parallel_platform_data *pdata, + unsigned int shift); -#define ISP_XCLK_NONE -1 -#define ISP_XCLK_A 0 -#define ISP_XCLK_B 1 +#define ISP_XCLK_NONE 0 +#define ISP_XCLK_A 1 +#define ISP_XCLK_B 2 struct isp_device *omap3isp_get(struct isp_device *isp); void omap3isp_put(struct isp_device *isp); diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 5ff9d14..39d501b 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -43,6 +43,12 @@ __ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, static const unsigned int ccdc_fmts[] = { V4L2_MBUS_FMT_Y8_1X8, + V4L2_MBUS_FMT_Y10_1X10, + V4L2_MBUS_FMT_Y12_1X12, + V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10, @@ -1110,21 +1116,38 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) struct isp_parallel_platform_data *pdata = NULL; struct v4l2_subdev *sensor; struct v4l2_mbus_framefmt *format; + const struct isp_format_info *fmt_info; + struct v4l2_subdev_format fmt_src; + unsigned int depth_out; + unsigned int depth_in = 0; struct media_pad *pad; unsigned long flags; + unsigned int shift; u32 syn_mode; u32 ccdc_pattern; - if (ccdc->input == CCDC_INPUT_PARALLEL) { - pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]); - sensor = media_entity_to_v4l2_subdev(pad->entity); + pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]); + sensor = media_entity_to_v4l2_subdev(pad->entity); + if (ccdc->input == CCDC_INPUT_PARALLEL) pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv) ->bus.parallel; + + /* Compute shift value for lane shifter to configure the bridge. */ + fmt_src.pad = pad->index; + fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE; + if (!v4l2_subdev_call(sensor, pad, get_fmt, NULL, &fmt_src)) { + fmt_info = omap3isp_video_format_info(fmt_src.format.code); + depth_in = fmt_info->bpp; } - omap3isp_configure_bridge(isp, ccdc->input, pdata); + fmt_info = omap3isp_video_format_info + (isp->isp_ccdc.formats[CCDC_PAD_SINK].code); + depth_out = fmt_info->bpp; + + shift = depth_in - depth_out; + omap3isp_configure_bridge(isp, ccdc->input, pdata, shift); - ccdc->syncif.datsz = pdata ? pdata->width : 10; + ccdc->syncif.datsz = depth_out; ccdc_config_sync_if(ccdc, &ccdc->syncif); /* CCDC_PAD_SINK */ @@ -1338,7 +1361,7 @@ static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc, * @ccdc: Pointer to ISP CCDC device. * @event: Pointing which event trigger handler * - * Return 1 when the event and stopping request combination is satisfyied, + * Return 1 when the event and stopping request combination is satisfied, * zero otherwise. */ static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event) @@ -1618,7 +1641,7 @@ static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer) ccdc_set_outaddr(ccdc, buffer->isp_addr); - /* We now have a buffer queued on the output, restart the pipeline in + /* We now have a buffer queued on the output, restart the pipeline * on the next CCDC interrupt if running in continuous mode (or when * starting the stream). */ diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index 2b16988..aba537a 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -755,7 +755,7 @@ static struct preview_update update_attrs[] = { * @configs - pointer to update config structure. * @config - return pointer to appropriate structure field. * @bit - for which feature to return pointers. - * Return size of coresponding prev_params member + * Return size of corresponding prev_params member */ static u32 __preview_get_ptrs(struct prev_params *params, void **param, diff --git a/drivers/media/video/omap3isp/ispqueue.c b/drivers/media/video/omap3isp/ispqueue.c index 8fddc58..9c31714 100644 --- a/drivers/media/video/omap3isp/ispqueue.c +++ b/drivers/media/video/omap3isp/ispqueue.c @@ -339,7 +339,7 @@ static int isp_video_buffer_prepare_user(struct isp_video_buffer *buf) up_read(¤t->mm->mmap_sem); if (ret != buf->npages) { - buf->npages = ret; + buf->npages = ret < 0 ? 0 : ret; isp_video_buffer_cleanup(buf); return -EFAULT; } @@ -408,8 +408,8 @@ done: * isp_video_buffer_prepare_vm_flags - Get VMA flags for a userspace address * * This function locates the VMAs for the buffer's userspace address and checks - * that their flags match. The onlflag that we need to care for at the moment is - * VM_PFNMAP. + * that their flags match. The only flag that we need to care for at the moment + * is VM_PFNMAP. * * The buffer vm_flags field is set to the first VMA flags. * diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 653f88b..0bb0f8c 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -714,19 +714,50 @@ static void resizer_print_status(struct isp_res_device *res) * iw and ih are the input width and height after cropping. Those equations need * to be satisfied exactly for the resizer to work correctly. * - * Reverting the equations, we can compute the resizing ratios with + * The equations can't be easily reverted, as the >> 8 operation is not linear. + * In addition, not all input sizes can be achieved for a given output size. To + * get the highest input size lower than or equal to the requested input size, + * we need to compute the highest resizing ratio that satisfies the following + * inequality (taking the 4-tap mode width equation as an example) + * + * iw >= (32 * sph + (ow - 1) * hrsz + 16) >> 8 - 7 + * + * (where iw is the requested input width) which can be rewritten as + * + * iw - 7 >= (32 * sph + (ow - 1) * hrsz + 16) >> 8 + * (iw - 7) << 8 >= 32 * sph + (ow - 1) * hrsz + 16 - b + * ((iw - 7) << 8) + b >= 32 * sph + (ow - 1) * hrsz + 16 + * + * where b is the value of the 8 least significant bits of the right hand side + * expression of the last inequality. The highest resizing ratio value will be + * achieved when b is equal to its maximum value of 255. That resizing ratio + * value will still satisfy the original inequality, as b will disappear when + * the expression will be shifted right by 8. + * + * The reverted the equations thus become * * - 8-phase, 4-tap mode - * hrsz = ((iw - 7) * 256 - 16 - 32 * sph) / (ow - 1) - * vrsz = ((ih - 4) * 256 - 16 - 32 * spv) / (oh - 1) + * hrsz = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / (ow - 1) + * vrsz = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / (oh - 1) * - 4-phase, 7-tap mode - * hrsz = ((iw - 7) * 256 - 32 - 64 * sph) / (ow - 1) - * vrsz = ((ih - 7) * 256 - 32 - 64 * spv) / (oh - 1) + * hrsz = ((iw - 7) * 256 + 255 - 32 - 64 * sph) / (ow - 1) + * vrsz = ((ih - 7) * 256 + 255 - 32 - 64 * spv) / (oh - 1) * - * The ratios are integer values, and must be rounded down to ensure that the - * cropped input size is not bigger than the uncropped input size. As the ratio - * in 7-tap mode is always smaller than the ratio in 4-tap mode, we can use the - * 7-tap mode equations to compute a ratio approximation. + * The ratios are integer values, and are rounded down to ensure that the + * cropped input size is not bigger than the uncropped input size. + * + * As the number of phases/taps, used to select the correct equations to compute + * the ratio, depends on the ratio, we start with the 4-tap mode equations to + * compute an approximation of the ratio, and switch to the 7-tap mode equations + * if the approximation is higher than the ratio threshold. + * + * As the 7-tap mode equations will return a ratio smaller than or equal to the + * 4-tap mode equations, the resulting ratio could become lower than or equal to + * the ratio threshold. This 'equations loop' isn't an issue as long as the + * correct equations are used to compute the final input size. Starting with the + * 4-tap mode equations ensure that, in case of values resulting in a 'ratio + * loop', the smallest of the ratio values will be used, never exceeding the + * requested input size. * * We first clamp the output size according to the hardware capabilitie to avoid * auto-cropping the input more than required to satisfy the TRM equations. The @@ -775,6 +806,8 @@ static void resizer_calc_ratios(struct isp_res_device *res, unsigned int max_width; unsigned int max_height; unsigned int width_alignment; + unsigned int width; + unsigned int height; /* * Clamp the output height based on the hardware capabilities and @@ -786,19 +819,22 @@ static void resizer_calc_ratios(struct isp_res_device *res, max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT); output->height = clamp(output->height, min_height, max_height); - ratio->vert = ((input->height - 7) * 256 - 32 - 64 * spv) + ratio->vert = ((input->height - 4) * 256 + 255 - 16 - 32 * spv) / (output->height - 1); + if (ratio->vert > MID_RESIZE_VALUE) + ratio->vert = ((input->height - 7) * 256 + 255 - 32 - 64 * spv) + / (output->height - 1); ratio->vert = clamp_t(unsigned int, ratio->vert, MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); if (ratio->vert <= MID_RESIZE_VALUE) { upscaled_height = (output->height - 1) * ratio->vert + 32 * spv + 16; - input->height = (upscaled_height >> 8) + 4; + height = (upscaled_height >> 8) + 4; } else { upscaled_height = (output->height - 1) * ratio->vert + 64 * spv + 32; - input->height = (upscaled_height >> 8) + 7; + height = (upscaled_height >> 8) + 7; } /* @@ -854,20 +890,29 @@ static void resizer_calc_ratios(struct isp_res_device *res, max_width & ~(width_alignment - 1)); output->width = ALIGN(output->width, width_alignment); - ratio->horz = ((input->width - 7) * 256 - 32 - 64 * sph) + ratio->horz = ((input->width - 7) * 256 + 255 - 16 - 32 * sph) / (output->width - 1); + if (ratio->horz > MID_RESIZE_VALUE) + ratio->horz = ((input->width - 7) * 256 + 255 - 32 - 64 * sph) + / (output->width - 1); ratio->horz = clamp_t(unsigned int, ratio->horz, MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); if (ratio->horz <= MID_RESIZE_VALUE) { upscaled_width = (output->width - 1) * ratio->horz + 32 * sph + 16; - input->width = (upscaled_width >> 8) + 7; + width = (upscaled_width >> 8) + 7; } else { upscaled_width = (output->width - 1) * ratio->horz + 64 * sph + 32; - input->width = (upscaled_width >> 8) + 7; + width = (upscaled_width >> 8) + 7; } + + /* Center the new crop rectangle. */ + input->left += (input->width - width) / 2; + input->top += (input->height - height) / 2; + input->width = width; + input->height = height; } /* diff --git a/drivers/media/video/omap3isp/ispstat.h b/drivers/media/video/omap3isp/ispstat.h index 820950c..d86da94 100644 --- a/drivers/media/video/omap3isp/ispstat.h +++ b/drivers/media/video/omap3isp/ispstat.h @@ -131,9 +131,9 @@ struct ispstat { struct ispstat_generic_config { /* * Fields must be in the same order as in: - * - isph3a_aewb_config - * - isph3a_af_config - * - isphist_config + * - omap3isp_h3a_aewb_config + * - omap3isp_h3a_af_config + * - omap3isp_hist_config */ u32 buf_size; u16 config_counter; diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index 208a7ec..9cd8f1a 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -47,29 +47,59 @@ static struct isp_format_info formats[] = { { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8, - V4L2_MBUS_FMT_Y8_1X8, V4L2_PIX_FMT_GREY, 8, }, + V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8, + V4L2_PIX_FMT_GREY, 8, }, + { V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y10_1X10, + V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y8_1X8, + V4L2_PIX_FMT_Y10, 10, }, + { V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y10_1X10, + V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y8_1X8, + V4L2_PIX_FMT_Y12, 12, }, + { V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_PIX_FMT_SBGGR8, 8, }, + { V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8, + V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8, + V4L2_PIX_FMT_SGBRG8, 8, }, + { V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_PIX_FMT_SGRBG8, 8, }, + { V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_PIX_FMT_SRGGB8, 8, }, { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, - V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10DPCM8, 8, }, + V4L2_MBUS_FMT_SGRBG10_1X10, 0, + V4L2_PIX_FMT_SGRBG10DPCM8, 8, }, { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10, - V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10, 10, }, + V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_PIX_FMT_SBGGR10, 10, }, { V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10, - V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10, 10, }, + V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG8_1X8, + V4L2_PIX_FMT_SGBRG10, 10, }, { V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10, 10, }, + V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_PIX_FMT_SGRBG10, 10, }, { V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10, - V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10, 10, }, + V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_PIX_FMT_SRGGB10, 10, }, { V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10, - V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12, 12, }, + V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_PIX_FMT_SBGGR12, 12, }, { V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10, - V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12, 12, }, + V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG8_1X8, + V4L2_PIX_FMT_SGBRG12, 12, }, { V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12, 12, }, + V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_PIX_FMT_SGRBG12, 12, }, { V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10, - V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12, 12, }, + V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_PIX_FMT_SRGGB12, 12, }, { V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16, - V4L2_MBUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 16, }, + V4L2_MBUS_FMT_UYVY8_1X16, 0, + V4L2_PIX_FMT_UYVY, 16, }, { V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16, - V4L2_MBUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 16, }, + V4L2_MBUS_FMT_YUYV8_1X16, 0, + V4L2_PIX_FMT_YUYV, 16, }, }; const struct isp_format_info * @@ -86,6 +116,37 @@ omap3isp_video_format_info(enum v4l2_mbus_pixelcode code) } /* + * Decide whether desired output pixel code can be obtained with + * the lane shifter by shifting the input pixel code. + * @in: input pixelcode to shifter + * @out: output pixelcode from shifter + * @additional_shift: # of bits the sensor's LSB is offset from CAMEXT[0] + * + * return true if the combination is possible + * return false otherwise + */ +static bool isp_video_is_shiftable(enum v4l2_mbus_pixelcode in, + enum v4l2_mbus_pixelcode out, + unsigned int additional_shift) +{ + const struct isp_format_info *in_info, *out_info; + + if (in == out) + return true; + + in_info = omap3isp_video_format_info(in); + out_info = omap3isp_video_format_info(out); + + if ((in_info->flavor == 0) || (out_info->flavor == 0)) + return false; + + if (in_info->flavor != out_info->flavor) + return false; + + return in_info->bpp - out_info->bpp + additional_shift <= 6; +} + +/* * isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format * @video: ISP video instance * @mbus: v4l2_mbus_framefmt format (input) @@ -235,6 +296,7 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) return -EPIPE; while (1) { + unsigned int shifter_link; /* Retrieve the sink format */ pad = &subdev->entity.pads[0]; if (!(pad->flags & MEDIA_PAD_FL_SINK)) @@ -263,6 +325,10 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) return -ENOSPC; } + /* If sink pad is on CCDC, the link has the lane shifter + * in the middle of it. */ + shifter_link = subdev == &isp->isp_ccdc.subdev; + /* Retrieve the source format */ pad = media_entity_remote_source(pad); if (pad == NULL || @@ -278,10 +344,24 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) return -EPIPE; /* Check if the two ends match */ - if (fmt_source.format.code != fmt_sink.format.code || - fmt_source.format.width != fmt_sink.format.width || + if (fmt_source.format.width != fmt_sink.format.width || fmt_source.format.height != fmt_sink.format.height) return -EPIPE; + + if (shifter_link) { + unsigned int parallel_shift = 0; + if (isp->isp_ccdc.input == CCDC_INPUT_PARALLEL) { + struct isp_parallel_platform_data *pdata = + &((struct isp_v4l2_subdevs_group *) + subdev->host_priv)->bus.parallel; + parallel_shift = pdata->data_lane_shift * 2; + } + if (!isp_video_is_shiftable(fmt_source.format.code, + fmt_sink.format.code, + parallel_shift)) + return -EPIPE; + } else if (fmt_source.format.code != fmt_sink.format.code) + return -EPIPE; } return 0; diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h index 524a1acd..911bea6 100644 --- a/drivers/media/video/omap3isp/ispvideo.h +++ b/drivers/media/video/omap3isp/ispvideo.h @@ -49,6 +49,8 @@ struct v4l2_pix_format; * bits. Identical to @code if the format is 10 bits wide or less. * @uncompressed: V4L2 media bus format code for the corresponding uncompressed * format. Identical to @code if the format is not DPCM compressed. + * @flavor: V4L2 media bus format code for the same pixel layout but + * shifted to be 8 bits per pixel. =0 if format is not shiftable. * @pixelformat: V4L2 pixel format FCC identifier * @bpp: Bits per pixel */ @@ -56,6 +58,7 @@ struct isp_format_info { enum v4l2_mbus_pixelcode code; enum v4l2_mbus_pixelcode truncated; enum v4l2_mbus_pixelcode uncompressed; + enum v4l2_mbus_pixelcode flavor; u32 pixelformat; unsigned int bpp; }; diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 95f8b4e1..d142b40 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -527,7 +527,7 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, if (ret) return ret; - if (vb2_is_streaming(&fimc->vid_cap.vbq) || fimc_capture_active(fimc)) + if (vb2_is_busy(&fimc->vid_cap.vbq) || fimc_capture_active(fimc)) return -EBUSY; frame = &ctx->d_frame; @@ -539,8 +539,10 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, return -EINVAL; } - for (i = 0; i < frame->fmt->colplanes; i++) - frame->payload[i] = pix->plane_fmt[i].bytesperline * pix->height; + for (i = 0; i < frame->fmt->colplanes; i++) { + frame->payload[i] = + (pix->width * pix->height * frame->fmt->depth[i]) >> 3; + } /* Output DMA frame pixel size and offsets. */ frame->f_width = pix->plane_fmt[0].bytesperline * 8 diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 6c919b3..dc91a85 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -361,10 +361,20 @@ static void fimc_capture_irq_handler(struct fimc_dev *fimc) { struct fimc_vid_cap *cap = &fimc->vid_cap; struct fimc_vid_buffer *v_buf; + struct timeval *tv; + struct timespec ts; if (!list_empty(&cap->active_buf_q) && test_bit(ST_CAPT_RUN, &fimc->state)) { + ktime_get_real_ts(&ts); + v_buf = active_queue_pop(cap); + + tv = &v_buf->vb.v4l2_buf.timestamp; + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; + v_buf->vb.v4l2_buf.sequence = cap->frame_count++; + vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE); } @@ -758,7 +768,7 @@ static void fimc_unlock(struct vb2_queue *vq) mutex_unlock(&ctx->fimc_dev->lock); } -struct vb2_ops fimc_qops = { +static struct vb2_ops fimc_qops = { .queue_setup = fimc_queue_setup, .buf_prepare = fimc_buf_prepare, .buf_queue = fimc_buf_queue, @@ -927,23 +937,23 @@ int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, pix->num_planes = fmt->memplanes; pix->colorspace = V4L2_COLORSPACE_JPEG; - for (i = 0; i < pix->num_planes; ++i) { - int bpl = pix->plane_fmt[i].bytesperline; - dbg("[%d] bpl: %d, depth: %d, w: %d, h: %d", - i, bpl, fmt->depth[i], pix->width, pix->height); + for (i = 0; i < pix->num_planes; ++i) { + u32 bpl = pix->plane_fmt[i].bytesperline; + u32 *sizeimage = &pix->plane_fmt[i].sizeimage; - if (!bpl || (bpl * 8 / fmt->depth[i]) > pix->width) - bpl = (pix->width * fmt->depth[0]) >> 3; + if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width)) + bpl = pix->width; /* Planar */ - if (!pix->plane_fmt[i].sizeimage) - pix->plane_fmt[i].sizeimage = pix->height * bpl; + if (fmt->colplanes == 1 && /* Packed */ + (bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width)) + bpl = (pix->width * fmt->depth[0]) / 8; - pix->plane_fmt[i].bytesperline = bpl; + if (i == 0) /* Same bytesperline for each plane. */ + mod_x = bpl; - dbg("[%d]: bpl: %d, sizeimage: %d", - i, pix->plane_fmt[i].bytesperline, - pix->plane_fmt[i].sizeimage); + pix->plane_fmt[i].bytesperline = mod_x; + *sizeimage = (pix->width * pix->height * fmt->depth[i]) / 8; } return 0; @@ -965,7 +975,7 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); - if (vb2_is_streaming(vq)) { + if (vb2_is_busy(vq)) { v4l2_err(&fimc->m2m.v4l2_dev, "queue (%d) busy\n", f->type); return -EBUSY; } @@ -985,8 +995,10 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, if (!frame->fmt) return -EINVAL; - for (i = 0; i < frame->fmt->colplanes; i++) - frame->payload[i] = pix->plane_fmt[i].bytesperline * pix->height; + for (i = 0; i < frame->fmt->colplanes; i++) { + frame->payload[i] = + (pix->width * pix->height * frame->fmt->depth[i]) / 8; + } frame->f_width = pix->plane_fmt[0].bytesperline * 8 / frame->fmt->depth[0]; @@ -1750,7 +1762,7 @@ static int __devexit fimc_remove(struct platform_device *pdev) } /* Image pixel limits, similar across several FIMC HW revisions. */ -static struct fimc_pix_limit s5p_pix_limit[3] = { +static struct fimc_pix_limit s5p_pix_limit[4] = { [0] = { .scaler_en_w = 3264, .scaler_dis_w = 8192, @@ -1775,6 +1787,14 @@ static struct fimc_pix_limit s5p_pix_limit[3] = { .out_rot_en_w = 1280, .out_rot_dis_w = 1920, }, + [3] = { + .scaler_en_w = 1920, + .scaler_dis_w = 8192, + .in_rot_en_h = 1366, + .in_rot_dis_w = 8192, + .out_rot_en_w = 1366, + .out_rot_dis_w = 1920, + }, }; static struct samsung_fimc_variant fimc0_variant_s5p = { @@ -1827,7 +1847,7 @@ static struct samsung_fimc_variant fimc2_variant_s5pv210 = { .pix_limit = &s5p_pix_limit[2], }; -static struct samsung_fimc_variant fimc0_variant_s5pv310 = { +static struct samsung_fimc_variant fimc0_variant_exynos4 = { .pix_hoff = 1, .has_inp_rot = 1, .has_out_rot = 1, @@ -1840,7 +1860,7 @@ static struct samsung_fimc_variant fimc0_variant_s5pv310 = { .pix_limit = &s5p_pix_limit[1], }; -static struct samsung_fimc_variant fimc2_variant_s5pv310 = { +static struct samsung_fimc_variant fimc2_variant_exynos4 = { .pix_hoff = 1, .has_cistatus2 = 1, .has_mainscaler_ext = 1, @@ -1848,7 +1868,7 @@ static struct samsung_fimc_variant fimc2_variant_s5pv310 = { .min_out_pixsize = 16, .hor_offs_align = 1, .out_buf_count = 32, - .pix_limit = &s5p_pix_limit[2], + .pix_limit = &s5p_pix_limit[3], }; /* S5PC100 */ @@ -1874,12 +1894,12 @@ static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = { }; /* S5PV310, S5PC210 */ -static struct samsung_fimc_driverdata fimc_drvdata_s5pv310 = { +static struct samsung_fimc_driverdata fimc_drvdata_exynos4 = { .variant = { - [0] = &fimc0_variant_s5pv310, - [1] = &fimc0_variant_s5pv310, - [2] = &fimc0_variant_s5pv310, - [3] = &fimc2_variant_s5pv310, + [0] = &fimc0_variant_exynos4, + [1] = &fimc0_variant_exynos4, + [2] = &fimc0_variant_exynos4, + [3] = &fimc2_variant_exynos4, }, .num_entities = 4, .lclk_frequency = 166000000UL, @@ -1893,8 +1913,8 @@ static struct platform_device_id fimc_driver_ids[] = { .name = "s5pv210-fimc", .driver_data = (unsigned long)&fimc_drvdata_s5pv210, }, { - .name = "s5pv310-fimc", - .driver_data = (unsigned long)&fimc_drvdata_s5pv310, + .name = "exynos4-fimc", + .driver_data = (unsigned long)&fimc_drvdata_exynos4, }, {}, }; diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 3fe54bf..134e86b 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -922,7 +922,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int /* Try 2560x1920, 1280x960, 640x480, 320x240 */ mf.width = 2560 >> shift; mf.height = 1920 >> shift; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, s_mbus_fmt, &mf); if (ret < 0) return ret; @@ -1224,7 +1224,7 @@ static int client_s_fmt(struct soc_camera_device *icd, struct v4l2_cropcap cap; int ret; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, s_mbus_fmt, mf); if (ret < 0) return ret; @@ -1254,7 +1254,7 @@ static int client_s_fmt(struct soc_camera_device *icd, tmp_h = min(2 * tmp_h, max_height); mf->width = tmp_w; mf->height = tmp_h; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, s_mbus_fmt, mf); dev_geo(dev, "Camera scaled to %ux%u\n", mf->width, mf->height); @@ -1658,7 +1658,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, mf.code = xlate->code; mf.colorspace = pix->colorspace; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, try_mbus_fmt, &mf); + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, try_mbus_fmt, &mf); if (ret < 0) return ret; @@ -1682,7 +1682,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, */ mf.width = 2560; mf.height = 1920; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, try_mbus_fmt, &mf); if (ret < 0) { /* Shouldn't actually happen... */ diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index dd1b81b..98b8748 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c @@ -38,6 +38,8 @@ struct sh_csi2 { void __iomem *base; struct platform_device *pdev; struct sh_csi2_client_config *client; + unsigned long (*query_bus_param)(struct soc_camera_device *); + int (*set_bus_param)(struct soc_camera_device *, unsigned long); }; static int sh_csi2_try_fmt(struct v4l2_subdev *sd, @@ -208,6 +210,7 @@ static int sh_csi2_notify(struct notifier_block *nb, case BUS_NOTIFY_BOUND_DRIVER: snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s%s", dev_name(v4l2_dev->dev), ".mipi-csi"); + priv->subdev.grp_id = (long)icd; ret = v4l2_device_register_subdev(v4l2_dev, &priv->subdev); dev_dbg(dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret); if (ret < 0) @@ -215,6 +218,8 @@ static int sh_csi2_notify(struct notifier_block *nb, priv->client = pdata->clients + i; + priv->set_bus_param = icd->ops->set_bus_param; + priv->query_bus_param = icd->ops->query_bus_param; icd->ops->set_bus_param = sh_csi2_set_bus_param; icd->ops->query_bus_param = sh_csi2_query_bus_param; @@ -226,8 +231,10 @@ static int sh_csi2_notify(struct notifier_block *nb, priv->client = NULL; /* Driver is about to be unbound */ - icd->ops->set_bus_param = NULL; - icd->ops->query_bus_param = NULL; + icd->ops->set_bus_param = priv->set_bus_param; + icd->ops->query_bus_param = priv->query_bus_param; + priv->set_bus_param = NULL; + priv->query_bus_param = NULL; v4l2_device_unregister_subdev(&priv->subdev); diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 4628448..3973f9a 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -996,10 +996,11 @@ static void soc_camera_free_i2c(struct soc_camera_device *icd) { struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct i2c_adapter *adap = client->adapter; dev_set_drvdata(&icd->dev, NULL); v4l2_device_unregister_subdev(i2c_get_clientdata(client)); i2c_unregister_device(client); - i2c_put_adapter(client->adapter); + i2c_put_adapter(adap); } #else #define soc_camera_init_i2c(icd, icl) (-ENODEV) @@ -1071,6 +1072,9 @@ static int soc_camera_probe(struct device *dev) } } + sd = soc_camera_to_subdev(icd); + sd->grp_id = (long)icd; + /* At this point client .probe() should have run already */ ret = soc_camera_init_user_formats(icd); if (ret < 0) @@ -1092,7 +1096,6 @@ static int soc_camera_probe(struct device *dev) goto evidstart; /* Try to improve our guess of a reasonable window format */ - sd = soc_camera_to_subdev(icd); if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { icd->user_width = mf.width; icd->user_height = mf.height; diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 498e674..6dc7196 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -389,7 +389,8 @@ static int v4l2_open(struct inode *inode, struct file *filp) video_get(vdev); mutex_unlock(&videodev_lock); #if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) { + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) { entity = media_entity_get(&vdev->entity); if (!entity) { ret = -EBUSY; @@ -415,7 +416,8 @@ err: /* decrease the refcount in case of an error */ if (ret) { #if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) media_entity_put(entity); #endif video_put(vdev); @@ -437,7 +439,8 @@ static int v4l2_release(struct inode *inode, struct file *filp) mutex_unlock(vdev->lock); } #if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) media_entity_put(&vdev->entity); #endif /* decrease the refcount unconditionally since the release() @@ -686,7 +689,8 @@ int __video_register_device(struct video_device *vdev, int type, int nr, #if defined(CONFIG_MEDIA_CONTROLLER) /* Part 5: Register the entity. */ - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) { + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) { vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; vdev->entity.name = vdev->name; vdev->entity.v4l.major = VIDEO_MAJOR; @@ -733,7 +737,8 @@ void video_unregister_device(struct video_device *vdev) return; #if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) media_device_unregister_entity(&vdev->entity); #endif diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 6698c77..6ba1461 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -37,6 +37,9 @@ module_param(debug, int, 0644); #define call_qop(q, op, args...) \ (((q)->ops->op) ? ((q)->ops->op(args)) : 0) +#define V4L2_BUFFER_STATE_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \ + V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR) + /** * __vb2_buf_mem_alloc() - allocate video memory for the given buffer */ @@ -51,7 +54,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb, for (plane = 0; plane < vb->num_planes; ++plane) { mem_priv = call_memop(q, plane, alloc, q->alloc_ctx[plane], plane_sizes[plane]); - if (!mem_priv) + if (IS_ERR_OR_NULL(mem_priv)) goto free; /* Associate allocator private data with this plane */ @@ -284,7 +287,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) struct vb2_queue *q = vb->vb2_queue; int ret = 0; - /* Copy back data such as timestamp, input, etc. */ + /* Copy back data such as timestamp, flags, input, etc. */ memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m)); b->input = vb->v4l2_buf.input; b->reserved = vb->v4l2_buf.reserved; @@ -313,7 +316,10 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) b->m.userptr = vb->v4l2_planes[0].m.userptr; } - b->flags = 0; + /* + * Clear any buffer state related flags. + */ + b->flags &= ~V4L2_BUFFER_STATE_FLAGS; switch (vb->state) { case VB2_BUF_STATE_QUEUED: @@ -519,6 +525,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME); memset(plane_sizes, 0, sizeof(plane_sizes)); memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); + q->memory = req->memory; /* * Ask the driver how many buffers and planes per buffer it requires. @@ -560,8 +567,6 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) ret = num_buffers; } - q->memory = req->memory; - /* * Return the number of successfully allocated buffers * to the userspace. @@ -715,6 +720,8 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b, vb->v4l2_buf.field = b->field; vb->v4l2_buf.timestamp = b->timestamp; + vb->v4l2_buf.input = b->input; + vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS; return 0; } diff --git a/drivers/media/video/videobuf2-dma-contig.c b/drivers/media/video/videobuf2-dma-contig.c index 58205d5..a790a5f 100644 --- a/drivers/media/video/videobuf2-dma-contig.c +++ b/drivers/media/video/videobuf2-dma-contig.c @@ -46,7 +46,7 @@ static void *vb2_dma_contig_alloc(void *alloc_ctx, unsigned long size) GFP_KERNEL); if (!buf->vaddr) { dev_err(conf->dev, "dma_alloc_coherent of size %ld failed\n", - buf->size); + size); kfree(buf); return ERR_PTR(-ENOMEM); } diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 63667a8..d6d62fd 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -284,6 +284,7 @@ int mmc_add_card(struct mmc_card *card) type = "SD-combo"; if (mmc_card_blockaddr(card)) type = "SDHC-combo"; + break; default: type = "?"; break; diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 461e6a1..2b200c1 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -94,7 +94,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host) spin_unlock_irqrestore(&host->clk_lock, flags); return; } - mutex_lock(&host->clk_gate_mutex); + mmc_claim_host(host); spin_lock_irqsave(&host->clk_lock, flags); if (!host->clk_requests) { spin_unlock_irqrestore(&host->clk_lock, flags); @@ -104,7 +104,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host) pr_debug("%s: gated MCI clock\n", mmc_hostname(host)); } spin_unlock_irqrestore(&host->clk_lock, flags); - mutex_unlock(&host->clk_gate_mutex); + mmc_release_host(host); } /* @@ -130,7 +130,7 @@ void mmc_host_clk_ungate(struct mmc_host *host) { unsigned long flags; - mutex_lock(&host->clk_gate_mutex); + mmc_claim_host(host); spin_lock_irqsave(&host->clk_lock, flags); if (host->clk_gated) { spin_unlock_irqrestore(&host->clk_lock, flags); @@ -140,7 +140,7 @@ void mmc_host_clk_ungate(struct mmc_host *host) } host->clk_requests++; spin_unlock_irqrestore(&host->clk_lock, flags); - mutex_unlock(&host->clk_gate_mutex); + mmc_release_host(host); } /** @@ -215,7 +215,6 @@ static inline void mmc_host_clk_init(struct mmc_host *host) host->clk_gated = false; INIT_WORK(&host->clk_gate_work, mmc_host_clk_gate_work); spin_lock_init(&host->clk_lock); - mutex_init(&host->clk_gate_mutex); } /** diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 2e032f0..a6c3290 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -832,7 +832,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) return IRQ_HANDLED; } - if (end_command) + if (end_command && host->cmd) mmc_omap_cmd_done(host, host->cmd); if (host->data != NULL) { if (transfer_error) diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index a136be7..f8b5f37 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -957,6 +957,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( host->ioaddr = pci_ioremap_bar(pdev, bar); if (!host->ioaddr) { dev_err(&pdev->dev, "failed to remap registers\n"); + ret = -ENOMEM; goto release; } diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 9e15f41..5d20661 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1334,6 +1334,13 @@ static void sdhci_tasklet_finish(unsigned long param) host = (struct sdhci_host*)param; + /* + * If this tasklet gets rescheduled while running, it will + * be run again afterwards but without any active request. + */ + if (!host->mrq) + return; + spin_lock_irqsave(&host->lock, flags); del_timer(&host->timer); @@ -1345,7 +1352,7 @@ static void sdhci_tasklet_finish(unsigned long param) * upon error conditions. */ if (!(host->flags & SDHCI_DEVICE_DEAD) && - (mrq->cmd->error || + ((mrq->cmd && mrq->cmd->error) || (mrq->data && (mrq->data->error || (mrq->data->stop && mrq->data->stop->error))) || (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) { diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 62d37de..710339a 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -728,15 +728,15 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) tmio_mmc_set_clock(host, ios->clock); /* Power sequence - OFF -> UP -> ON */ - if (ios->power_mode == MMC_POWER_OFF || !ios->clock) { + if (ios->power_mode == MMC_POWER_UP) { + /* power up SD bus */ + if (host->set_pwr) + host->set_pwr(host->pdev, 1); + } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) { /* power down SD bus */ if (ios->power_mode == MMC_POWER_OFF && host->set_pwr) host->set_pwr(host->pdev, 0); tmio_mmc_clk_stop(host); - } else if (ios->power_mode == MMC_POWER_UP) { - /* power up SD bus */ - if (host->set_pwr) - host->set_pwr(host->pdev, 1); } else { /* start bus clock */ tmio_mmc_clk_start(host); diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 96c0b34..657b9f4 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -400,7 +400,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE); doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - /* We can't' use dev_ready here, but at least we wait for the + /* We can't use dev_ready here, but at least we wait for the * command to complete */ udelay(50); diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 88495c4..241b185 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -106,7 +106,7 @@ MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version "M MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, amd8111e_pci_tbl); module_param_array(speed_duplex, int, NULL, 0); -MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotitate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex"); +MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotiate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex"); module_param_array(coalesce, bool, NULL, 0); MODULE_PARM_DESC(coalesce, "Enable or Disable interrupt coalescing, 1: Enable, 0: Disable"); module_param_array(dynamic_ipg, bool, NULL, 0); diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h index 7cb375e..925929d 100644 --- a/drivers/net/atl1c/atl1c.h +++ b/drivers/net/atl1c/atl1c.h @@ -566,9 +566,9 @@ struct atl1c_adapter { #define __AT_TESTING 0x0001 #define __AT_RESETTING 0x0002 #define __AT_DOWN 0x0003 - u8 work_event; -#define ATL1C_WORK_EVENT_RESET 0x01 -#define ATL1C_WORK_EVENT_LINK_CHANGE 0x02 + unsigned long work_event; +#define ATL1C_WORK_EVENT_RESET 0 +#define ATL1C_WORK_EVENT_LINK_CHANGE 1 u32 msg_enable; bool have_msi; diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index 7d9d506..a6e1c36 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -325,7 +325,7 @@ static void atl1c_link_chg_event(struct atl1c_adapter *adapter) } } - adapter->work_event |= ATL1C_WORK_EVENT_LINK_CHANGE; + set_bit(ATL1C_WORK_EVENT_LINK_CHANGE, &adapter->work_event); schedule_work(&adapter->common_task); } @@ -337,20 +337,16 @@ static void atl1c_common_task(struct work_struct *work) adapter = container_of(work, struct atl1c_adapter, common_task); netdev = adapter->netdev; - if (adapter->work_event & ATL1C_WORK_EVENT_RESET) { - adapter->work_event &= ~ATL1C_WORK_EVENT_RESET; + if (test_and_clear_bit(ATL1C_WORK_EVENT_RESET, &adapter->work_event)) { netif_device_detach(netdev); atl1c_down(adapter); atl1c_up(adapter); netif_device_attach(netdev); - return; } - if (adapter->work_event & ATL1C_WORK_EVENT_LINK_CHANGE) { - adapter->work_event &= ~ATL1C_WORK_EVENT_LINK_CHANGE; + if (test_and_clear_bit(ATL1C_WORK_EVENT_LINK_CHANGE, + &adapter->work_event)) atl1c_check_link_status(adapter); - } - return; } @@ -369,7 +365,7 @@ static void atl1c_tx_timeout(struct net_device *netdev) struct atl1c_adapter *adapter = netdev_priv(netdev); /* Do the reset outside of interrupt context */ - adapter->work_event |= ATL1C_WORK_EVENT_RESET; + set_bit(ATL1C_WORK_EVENT_RESET, &adapter->work_event); schedule_work(&adapter->common_task); } diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 7cb5a11..02a0443 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1873,6 +1873,7 @@ static void be_worker(struct work_struct *work) be_detect_dump_ue(adapter); reschedule: + adapter->work_counter++; schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); } diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 8e6d618..d8383a9 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -8413,6 +8413,8 @@ bnx2_remove_one(struct pci_dev *pdev) unregister_netdev(dev); + del_timer_sync(&bp->timer); + if (bp->mips_firmware) release_firmware(bp->mips_firmware); if (bp->rv2p_firmware) diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index e83ac6d..16581df 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -2019,15 +2019,23 @@ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb, static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb, u32 *parsing_data, u32 xmit_type) { - *parsing_data |= ((tcp_hdrlen(skb)/4) << - ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) & - ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW; + *parsing_data |= + ((((u8 *)skb_transport_header(skb) - skb->data) >> 1) << + ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) & + ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W; - *parsing_data |= ((((u8 *)tcp_hdr(skb) - skb->data) / 2) << - ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) & - ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W; + if (xmit_type & XMIT_CSUM_TCP) { + *parsing_data |= ((tcp_hdrlen(skb) / 4) << + ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) & + ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW; - return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data; + return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data; + } else + /* We support checksum offload for TCP and UDP only. + * No need to pass the UDP header length - it's a constant. + */ + return skb_transport_header(skb) + + sizeof(struct udphdr) - skb->data; } /** @@ -2043,7 +2051,7 @@ static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb, struct eth_tx_parse_bd_e1x *pbd, u32 xmit_type) { - u8 hlen = (skb_network_header(skb) - skb->data) / 2; + u8 hlen = (skb_network_header(skb) - skb->data) >> 1; /* for now NS flag is not used in Linux */ pbd->global_data = @@ -2051,9 +2059,15 @@ static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb, ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN_SHIFT)); pbd->ip_hlen_w = (skb_transport_header(skb) - - skb_network_header(skb)) / 2; + skb_network_header(skb)) >> 1; - hlen += pbd->ip_hlen_w + tcp_hdrlen(skb) / 2; + hlen += pbd->ip_hlen_w; + + /* We support checksum offload for TCP and UDP only */ + if (xmit_type & XMIT_CSUM_TCP) + hlen += tcp_hdrlen(skb) / 2; + else + hlen += sizeof(struct udphdr) / 2; pbd->total_hlen_w = cpu_to_le16(hlen); hlen = hlen*2; diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 494bf96..31912f1 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -1482,8 +1482,11 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best, static int agg_device_up(const struct aggregator *agg) { - return (netif_running(agg->slave->dev) && - netif_carrier_ok(agg->slave->dev)); + struct port *port = agg->lag_ports; + if (!port) + return 0; + return (netif_running(port->slave->dev) && + netif_carrier_ok(port->slave->dev)); } /** diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index f75d314..53c0f04 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -3040,11 +3040,14 @@ static void ehea_rereg_mrs(void) if (dev->flags & IFF_UP) { mutex_lock(&port->port_lock); - port_napi_enable(port); ret = ehea_restart_qps(dev); - check_sqs(port); - if (!ret) + if (!ret) { + check_sqs(port); + port_napi_enable(port); netif_wake_queue(dev); + } else { + netdev_err(dev, "Unable to restart QPS\n"); + } mutex_unlock(&port->port_lock); } } diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index 61035fc..b9fbc83 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -226,8 +226,8 @@ static void set_multicast_finish(struct net_device *dev) } FC(fecp, r_cntrl, FEC_RCNTRL_PROM); - FW(fecp, hash_table_high, fep->fec.hthi); - FW(fecp, hash_table_low, fep->fec.htlo); + FW(fecp, grp_hash_table_high, fep->fec.hthi); + FW(fecp, grp_hash_table_low, fep->fec.htlo); } static void set_multicast_list(struct net_device *dev) @@ -273,8 +273,8 @@ static void restart(struct net_device *dev) /* * Reset all multicast. */ - FW(fecp, hash_table_high, fep->fec.hthi); - FW(fecp, hash_table_low, fep->fec.htlo); + FW(fecp, grp_hash_table_high, fep->fec.hthi); + FW(fecp, grp_hash_table_low, fep->fec.htlo); /* * Set maximum receive buffer size. diff --git a/drivers/net/ftmac100.c b/drivers/net/ftmac100.c index a316619..9bd7746 100644 --- a/drivers/net/ftmac100.c +++ b/drivers/net/ftmac100.c @@ -139,11 +139,11 @@ static int ftmac100_reset(struct ftmac100 *priv) * that hardware reset completed (what the f*ck). * We still need to wait for a while. */ - usleep_range(500, 1000); + udelay(500); return 0; } - usleep_range(1000, 10000); + udelay(1000); } netdev_err(netdev, "software reset failed\n"); @@ -772,7 +772,7 @@ static int ftmac100_mdio_read(struct net_device *netdev, int phy_id, int reg) if ((phycr & FTMAC100_PHYCR_MIIRD) == 0) return phycr & FTMAC100_PHYCR_MIIRDATA; - usleep_range(100, 1000); + udelay(100); } netdev_err(netdev, "mdio read timed out\n"); @@ -801,7 +801,7 @@ static void ftmac100_mdio_write(struct net_device *netdev, int phy_id, int reg, if ((phycr & FTMAC100_PHYCR_MIIWR) == 0) return; - usleep_range(100, 1000); + udelay(100); } netdev_err(netdev, "mdio write timed out\n"); diff --git a/drivers/net/mii.c b/drivers/net/mii.c index 0a6c6a2..d4fc00b 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -49,6 +49,10 @@ static u32 mii_get_an(struct mii_if_info *mii, u16 addr) result |= ADVERTISED_100baseT_Half; if (advert & ADVERTISE_100FULL) result |= ADVERTISED_100baseT_Full; + if (advert & ADVERTISE_PAUSE_CAP) + result |= ADVERTISED_Pause; + if (advert & ADVERTISE_PAUSE_ASYM) + result |= ADVERTISED_Asym_Pause; return result; } diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index dfb67eb..eb41e44 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -671,6 +671,7 @@ static int netconsole_netdev_event(struct notifier_block *this, goto done; spin_lock_irqsave(&target_list_lock, flags); +restart: list_for_each_entry(nt, &target_list, list) { netconsole_target_get(nt); if (nt->np.dev == dev) { @@ -683,9 +684,16 @@ static int netconsole_netdev_event(struct notifier_block *this, * rtnl_lock already held */ if (nt->np.dev) { + spin_unlock_irqrestore( + &target_list_lock, + flags); __netpoll_cleanup(&nt->np); + spin_lock_irqsave(&target_list_lock, + flags); dev_put(nt->np.dev); nt->np.dev = NULL; + netconsole_target_put(nt); + goto restart; } /* Fall through */ case NETDEV_GOING_DOWN: diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 493b0de..397c368 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -170,6 +170,16 @@ static const struct { }; #undef _R +static const struct rtl_firmware_info { + int mac_version; + const char *fw_name; +} rtl_firmware_infos[] = { + { .mac_version = RTL_GIGA_MAC_VER_25, .fw_name = FIRMWARE_8168D_1 }, + { .mac_version = RTL_GIGA_MAC_VER_26, .fw_name = FIRMWARE_8168D_2 }, + { .mac_version = RTL_GIGA_MAC_VER_29, .fw_name = FIRMWARE_8105E_1 }, + { .mac_version = RTL_GIGA_MAC_VER_30, .fw_name = FIRMWARE_8105E_1 } +}; + enum cfg_version { RTL_CFG_0 = 0x00, RTL_CFG_1, @@ -565,6 +575,7 @@ struct rtl8169_private { u32 saved_wolopts; const struct firmware *fw; +#define RTL_FIRMWARE_UNKNOWN ERR_PTR(-EAGAIN); }; MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>"); @@ -1789,25 +1800,26 @@ rtl_phy_write_fw(struct rtl8169_private *tp, const struct firmware *fw) static void rtl_release_firmware(struct rtl8169_private *tp) { - release_firmware(tp->fw); - tp->fw = NULL; + if (!IS_ERR_OR_NULL(tp->fw)) + release_firmware(tp->fw); + tp->fw = RTL_FIRMWARE_UNKNOWN; } -static int rtl_apply_firmware(struct rtl8169_private *tp, const char *fw_name) +static void rtl_apply_firmware(struct rtl8169_private *tp) { - const struct firmware **fw = &tp->fw; - int rc = !*fw; - - if (rc) { - rc = request_firmware(fw, fw_name, &tp->pci_dev->dev); - if (rc < 0) - goto out; - } + const struct firmware *fw = tp->fw; /* TODO: release firmware once rtl_phy_write_fw signals failures. */ - rtl_phy_write_fw(tp, *fw); -out: - return rc; + if (!IS_ERR_OR_NULL(fw)) + rtl_phy_write_fw(tp, fw); +} + +static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val) +{ + if (rtl_readphy(tp, reg) != val) + netif_warn(tp, hw, tp->dev, "chipset not ready for firmware\n"); + else + rtl_apply_firmware(tp); } static void rtl8169s_hw_phy_config(struct rtl8169_private *tp) @@ -2246,10 +2258,8 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x001b); - if ((rtl_readphy(tp, 0x06) != 0xbf00) || - (rtl_apply_firmware(tp, FIRMWARE_8168D_1) < 0)) { - netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n"); - } + + rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xbf00); rtl_writephy(tp, 0x1f, 0x0000); } @@ -2351,10 +2361,8 @@ static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x001b); - if ((rtl_readphy(tp, 0x06) != 0xb300) || - (rtl_apply_firmware(tp, FIRMWARE_8168D_2) < 0)) { - netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n"); - } + + rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xb300); rtl_writephy(tp, 0x1f, 0x0000); } @@ -2474,8 +2482,7 @@ static void rtl8105e_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x18, 0x0310); msleep(100); - if (rtl_apply_firmware(tp, FIRMWARE_8105E_1) < 0) - netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n"); + rtl_apply_firmware(tp); rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } @@ -3237,6 +3244,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->timer.data = (unsigned long) dev; tp->timer.function = rtl8169_phy_timer; + tp->fw = RTL_FIRMWARE_UNKNOWN; + rc = register_netdev(dev); if (rc < 0) goto err_out_msi_4; @@ -3288,10 +3297,10 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) cancel_delayed_work_sync(&tp->task); - rtl_release_firmware(tp); - unregister_netdev(dev); + rtl_release_firmware(tp); + if (pci_dev_run_wake(pdev)) pm_runtime_get_noresume(&pdev->dev); @@ -3303,6 +3312,37 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } +static void rtl_request_firmware(struct rtl8169_private *tp) +{ + int i; + + /* Return early if the firmware is already loaded / cached. */ + if (!IS_ERR(tp->fw)) + goto out; + + for (i = 0; i < ARRAY_SIZE(rtl_firmware_infos); i++) { + const struct rtl_firmware_info *info = rtl_firmware_infos + i; + + if (info->mac_version == tp->mac_version) { + const char *name = info->fw_name; + int rc; + + rc = request_firmware(&tp->fw, name, &tp->pci_dev->dev); + if (rc < 0) { + netif_warn(tp, ifup, tp->dev, "unable to load " + "firmware patch %s (%d)\n", name, rc); + goto out_disable_request_firmware; + } + goto out; + } + } + +out_disable_request_firmware: + tp->fw = NULL; +out: + return; +} + static int rtl8169_open(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); @@ -3334,11 +3374,13 @@ static int rtl8169_open(struct net_device *dev) smp_mb(); + rtl_request_firmware(tp); + retval = request_irq(dev->irq, rtl8169_interrupt, (tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED, dev->name, dev); if (retval < 0) - goto err_release_ring_2; + goto err_release_fw_2; napi_enable(&tp->napi); @@ -3359,7 +3401,8 @@ static int rtl8169_open(struct net_device *dev) out: return retval; -err_release_ring_2: +err_release_fw_2: + rtl_release_firmware(tp); rtl8169_rx_clear(tp); err_free_rx_1: dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray, diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b8c5f35..7a5daef 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -12327,8 +12327,10 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (val & VCPU_CFGSHDW_ASPM_DBNC) tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND; if ((val & VCPU_CFGSHDW_WOL_ENABLE) && - (val & VCPU_CFGSHDW_WOL_MAGPKT)) + (val & VCPU_CFGSHDW_WOL_MAGPKT)) { tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; + device_set_wakeup_enable(&tp->pdev->dev, true); + } goto done; } @@ -12461,8 +12463,10 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->tg3_flags &= ~TG3_FLAG_WOL_CAP; if ((tp->tg3_flags & TG3_FLAG_WOL_CAP) && - (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE)) + (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE)) { tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; + device_set_wakeup_enable(&tp->pdev->dev, true); + } if (cfg2 & (1 << 17)) tp->phy_flags |= TG3_PHYFLG_CAPACITIVE_COUPLING; diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 341f705..a301479 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -460,7 +460,7 @@ static const struct driver_info cdc_info = { .manage_power = cdc_manage_power, }; -static const struct driver_info mbm_info = { +static const struct driver_info wwan_info = { .description = "Mobile Broadband Network Device", .flags = FLAG_WWAN, .bind = usbnet_cdc_bind, @@ -471,6 +471,7 @@ static const struct driver_info mbm_info = { /*-------------------------------------------------------------------------*/ +#define HUAWEI_VENDOR_ID 0x12D1 static const struct usb_device_id products [] = { /* @@ -587,8 +588,17 @@ static const struct usb_device_id products [] = { }, { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), - .driver_info = (unsigned long)&mbm_info, + .driver_info = (unsigned long)&wwan_info, +}, { + /* Various Huawei modems with a network port like the UMG1831 */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = HUAWEI_VENDOR_ID, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = 255, + .driver_info = (unsigned long)&wwan_info, }, { }, // END }; diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 967371f..1033ef6 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -54,13 +54,13 @@ #include <linux/usb/usbnet.h> #include <linux/usb/cdc.h> -#define DRIVER_VERSION "7-Feb-2011" +#define DRIVER_VERSION "23-Apr-2011" /* CDC NCM subclass 3.2.1 */ #define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10 /* Maximum NTB length */ -#define CDC_NCM_NTB_MAX_SIZE_TX 16384 /* bytes */ +#define CDC_NCM_NTB_MAX_SIZE_TX (16384 + 4) /* bytes, must be short terminated */ #define CDC_NCM_NTB_MAX_SIZE_RX 16384 /* bytes */ /* Minimum value for MaxDatagramSize, ch. 6.2.9 */ diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 47a6c87..48d4efd 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -730,7 +730,7 @@ static int smsc95xx_phy_initialize(struct usbnet *dev) msleep(10); bmcr = smsc95xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR); timeout++; - } while ((bmcr & MII_BMCR) && (timeout < 100)); + } while ((bmcr & BMCR_RESET) && (timeout < 100)); if (timeout >= 100) { netdev_warn(dev->net, "timeout on PHY Reset"); diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 069c1cf..009bba3 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -736,6 +736,7 @@ int usbnet_open (struct net_device *net) } } + set_bit(EVENT_DEV_OPEN, &dev->flags); netif_start_queue (net); netif_info(dev, ifup, dev->net, "open: enable queueing (rx %d, tx %d) mtu %d %s framing\n", @@ -1259,6 +1260,9 @@ void usbnet_disconnect (struct usb_interface *intf) if (dev->driver_info->unbind) dev->driver_info->unbind (dev, intf); + usb_kill_urb(dev->interrupt); + usb_free_urb(dev->interrupt); + free_netdev(net); usb_put_dev (xdev); } @@ -1498,6 +1502,10 @@ int usbnet_resume (struct usb_interface *intf) int retval; if (!--dev->suspend_count) { + /* resume interrupt URBs */ + if (dev->interrupt && test_bit(EVENT_DEV_OPEN, &dev->flags)) + usb_submit_urb(dev->interrupt, GFP_NOIO); + spin_lock_irq(&dev->txq.lock); while ((res = usb_get_from_anchor(&dev->deferred))) { diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 2de9b90..3b99f64 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -403,6 +403,17 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, if (tb[IFLA_ADDRESS] == NULL) random_ether_addr(dev->dev_addr); + if (tb[IFLA_IFNAME]) + nla_strlcpy(dev->name, tb[IFLA_IFNAME], IFNAMSIZ); + else + snprintf(dev->name, IFNAMSIZ, DRV_NAME "%%d"); + + if (strchr(dev->name, '%')) { + err = dev_alloc_name(dev, dev->name); + if (err < 0) + goto err_alloc_name; + } + err = register_netdevice(dev); if (err < 0) goto err_register_dev; @@ -422,6 +433,7 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, err_register_dev: /* nothing to do */ +err_alloc_name: err_configure_peer: unregister_netdevice(peer); return err; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index dcd19bc..b29c80d 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -506,7 +506,7 @@ bool ath_stoprecv(struct ath_softc *sc) "confusing the DMA engine when we start RX up\n"); ATH_DBG_WARN_ON_ONCE(!stopped); } - return stopped || reset; + return stopped && !reset; } void ath_flushrecv(struct ath_softc *sc) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index d59b016..5af40d9 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -72,6 +72,7 @@ MODULE_FIRMWARE("b43/ucode11.fw"); MODULE_FIRMWARE("b43/ucode13.fw"); MODULE_FIRMWARE("b43/ucode14.fw"); MODULE_FIRMWARE("b43/ucode15.fw"); +MODULE_FIRMWARE("b43/ucode16_mimo.fw"); MODULE_FIRMWARE("b43/ucode5.fw"); MODULE_FIRMWARE("b43/ucode9.fw"); diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c index 5c40502f..79ac081 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c @@ -316,12 +316,18 @@ int iwl4965_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr_len = ieee80211_hdrlen(fc); - /* Find index into station table for destination station */ - sta_id = iwl_legacy_sta_id_or_broadcast(priv, ctx, info->control.sta); - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", - hdr->addr1); - goto drop_unlock; + /* For management frames use broadcast id to do not break aggregation */ + if (!ieee80211_is_data(fc)) + sta_id = ctx->bcast_sta_id; + else { + /* Find index into station table for destination station */ + sta_id = iwl_legacy_sta_id_or_broadcast(priv, ctx, info->control.sta); + + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", + hdr->addr1); + goto drop_unlock; + } } IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); @@ -1127,12 +1133,16 @@ int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd)) { tx_info = &txq->txb[txq->q.read_ptr]; - iwl4965_tx_status(priv, tx_info, - txq_id >= IWL4965_FIRST_AMPDU_QUEUE); + + if (WARN_ON_ONCE(tx_info->skb == NULL)) + continue; hdr = (struct ieee80211_hdr *)tx_info->skb->data; - if (hdr && ieee80211_is_data_qos(hdr->frame_control)) + if (ieee80211_is_data_qos(hdr->frame_control)) nfreed++; + + iwl4965_tx_status(priv, tx_info, + txq_id >= IWL4965_FIRST_AMPDU_QUEUE); tx_info->skb = NULL; priv->cfg->ops->lib->txq_free_tfd(priv, txq); diff --git a/drivers/net/wireless/iwlegacy/iwl-led.c b/drivers/net/wireless/iwlegacy/iwl-led.c index 15eb8b7..bda0d61 100644 --- a/drivers/net/wireless/iwlegacy/iwl-led.c +++ b/drivers/net/wireless/iwlegacy/iwl-led.c @@ -48,8 +48,21 @@ module_param(led_mode, int, S_IRUGO); MODULE_PARM_DESC(led_mode, "0=system default, " "1=On(RF On)/Off(RF Off), 2=blinking"); +/* Throughput OFF time(ms) ON time (ms) + * >300 25 25 + * >200 to 300 40 40 + * >100 to 200 55 55 + * >70 to 100 65 65 + * >50 to 70 75 75 + * >20 to 50 85 85 + * >10 to 20 95 95 + * >5 to 10 110 110 + * >1 to 5 130 130 + * >0 to 1 167 167 + * <=0 SOLID ON + */ static const struct ieee80211_tpt_blink iwl_blink[] = { - { .throughput = 0 * 1024 - 1, .blink_time = 334 }, + { .throughput = 0, .blink_time = 334 }, { .throughput = 1 * 1024 - 1, .blink_time = 260 }, { .throughput = 5 * 1024 - 1, .blink_time = 220 }, { .throughput = 10 * 1024 - 1, .blink_time = 190 }, @@ -101,6 +114,11 @@ static int iwl_legacy_led_cmd(struct iwl_priv *priv, if (priv->blink_on == on && priv->blink_off == off) return 0; + if (off == 0) { + /* led is SOLID_ON */ + on = IWL_LED_SOLID; + } + IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n", priv->cfg->base_params->led_compensation); led_cmd.on = iwl_legacy_blink_compensation(priv, on, diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c index d484c36..a62fe24 100644 --- a/drivers/net/wireless/iwlegacy/iwl4965-base.c +++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c @@ -2984,15 +2984,15 @@ static void iwl4965_bg_txpower_work(struct work_struct *work) struct iwl_priv *priv = container_of(work, struct iwl_priv, txpower_work); + mutex_lock(&priv->mutex); + /* If a scan happened to start before we got here * then just return; the statistics notification will * kick off another scheduled work to compensate for * any temperature delta we missed here. */ if (test_bit(STATUS_EXIT_PENDING, &priv->status) || test_bit(STATUS_SCANNING, &priv->status)) - return; - - mutex_lock(&priv->mutex); + goto out; /* Regardless of if we are associated, we must reconfigure the * TX power since frames can be sent on non-radar channels while @@ -3002,7 +3002,7 @@ static void iwl4965_bg_txpower_work(struct work_struct *work) /* Update last_temperature to keep is_calib_needed from running * when it isn't needed... */ priv->last_temperature = priv->temperature; - +out: mutex_unlock(&priv->mutex); } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index dfdbea6..fbbde071 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -335,7 +335,6 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) struct ieee80211_channel *channel = conf->channel; const struct iwl_channel_info *ch_info; int ret = 0; - bool ht_changed[NUM_IWL_RXON_CTX] = {}; IWL_DEBUG_MAC80211(priv, "changed %#x", changed); @@ -383,10 +382,8 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) for_each_context(priv, ctx) { /* Configure HT40 channels */ - if (ctx->ht.enabled != conf_is_ht(conf)) { + if (ctx->ht.enabled != conf_is_ht(conf)) ctx->ht.enabled = conf_is_ht(conf); - ht_changed[ctx->ctxid] = true; - } if (ctx->ht.enabled) { if (conf_is_ht40_minus(conf)) { @@ -455,8 +452,6 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) if (!memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) continue; iwlagn_commit_rxon(priv, ctx); - if (ht_changed[ctx->ctxid]) - iwlagn_update_qos(priv, ctx); } out: mutex_unlock(&priv->mutex); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index a709d05..0712b672 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -568,12 +568,17 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr_len = ieee80211_hdrlen(fc); - /* Find index into station table for destination station */ - sta_id = iwl_sta_id_or_broadcast(priv, ctx, info->control.sta); - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", - hdr->addr1); - goto drop_unlock; + /* For management frames use broadcast id to do not break aggregation */ + if (!ieee80211_is_data(fc)) + sta_id = ctx->bcast_sta_id; + else { + /* Find index into station table for destination station */ + sta_id = iwl_sta_id_or_broadcast(priv, ctx, info->control.sta); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", + hdr->addr1); + goto drop_unlock; + } } IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); @@ -1224,12 +1229,16 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { tx_info = &txq->txb[txq->q.read_ptr]; - iwlagn_tx_status(priv, tx_info, - txq_id >= IWLAGN_FIRST_AMPDU_QUEUE); + + if (WARN_ON_ONCE(tx_info->skb == NULL)) + continue; hdr = (struct ieee80211_hdr *)tx_info->skb->data; - if (hdr && ieee80211_is_data_qos(hdr->frame_control)) + if (ieee80211_is_data_qos(hdr->frame_control)) nfreed++; + + iwlagn_tx_status(priv, tx_info, + txq_id >= IWLAGN_FIRST_AMPDU_QUEUE); tx_info->skb = NULL; if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl) diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index fe77e82..e8c19de 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -173,7 +173,7 @@ static int pcmcia_access_config(struct pcmcia_device *p_dev, c = p_dev->function_config; if (!(c->state & CONFIG_LOCKED)) { - dev_dbg(&p_dev->dev, "Configuration isn't't locked\n"); + dev_dbg(&p_dev->dev, "Configuration isn't locked\n"); mutex_unlock(&s->ops_mutex); return -EACCES; } diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c index 174036d..20494b5 100644 --- a/drivers/rtc/rtc-max8925.c +++ b/drivers/rtc/rtc-max8925.c @@ -257,6 +257,8 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev) goto out_irq; } + dev_set_drvdata(&pdev->dev, info); + info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev, &max8925_rtc_ops, THIS_MODULE); ret = PTR_ERR(info->rtc_dev); @@ -265,7 +267,6 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev) goto out_rtc; } - dev_set_drvdata(&pdev->dev, info); platform_set_drvdata(pdev, info); return 0; diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 29143ed..85dddb1 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -239,7 +239,6 @@ static void dasd_ext_handler(unsigned int ext_int_code, addr_t ip; int rc; - kstat_cpu(smp_processor_id()).irqs[EXTINT_DSD]++; switch (ext_int_code >> 24) { case DASD_DIAG_CODE_31BIT: ip = (addr_t) param32; @@ -250,6 +249,7 @@ static void dasd_ext_handler(unsigned int ext_int_code, default: return; } + kstat_cpu(smp_processor_id()).irqs[EXTINT_DSD]++; if (!ip) { /* no intparm: unsolicited interrupt */ DBF_EVENT(DBF_NOTICE, "%s", "caught unsolicited " "interrupt"); diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 414427d..607998f 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -381,10 +381,10 @@ static void kvm_extint_handler(unsigned int ext_int_code, u16 subcode; u32 param; - kstat_cpu(smp_processor_id()).irqs[EXTINT_VRT]++; subcode = ext_int_code >> 16; if ((subcode & 0xff00) != VIRTIO_SUBCODE_64) return; + kstat_cpu(smp_processor_id()).irqs[EXTINT_VRT]++; /* The LSB might be overloaded, we have to mask it */ vq = (struct virtqueue *)(param64 & ~1UL); diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index 564e6ec..0119b81 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c @@ -394,12 +394,14 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) unsigned long flags; struct scsi_device *sdev; struct scsi_device_handler *scsi_dh = NULL; + struct device *dev = NULL; spin_lock_irqsave(q->queue_lock, flags); sdev = q->queuedata; if (sdev && sdev->scsi_dh_data) scsi_dh = sdev->scsi_dh_data->scsi_dh; - if (!scsi_dh || !get_device(&sdev->sdev_gendev) || + dev = get_device(&sdev->sdev_gendev); + if (!scsi_dh || !dev || sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL) err = SCSI_DH_NOSYS; @@ -410,12 +412,13 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) if (err) { if (fn) fn(data, err); - return err; + goto out; } if (scsi_dh->activate) err = scsi_dh->activate(sdev, fn, data); - put_device(&sdev->sdev_gendev); +out: + put_device(dev); return err; } EXPORT_SYMBOL_GPL(scsi_dh_activate); diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 1c6d2b4..d72f1f2 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -688,6 +688,13 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, goto out; } + /* Check for overflow and wraparound */ + if (karg.data_sge_offset * 4 > ioc->request_sz || + karg.data_sge_offset > (UINT_MAX / 4)) { + ret = -EINVAL; + goto out; + } + /* copy in request message frame from user */ if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) { printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__, @@ -1963,7 +1970,7 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) Mpi2DiagBufferPostReply_t *mpi_reply; int rc, i; u8 buffer_type; - unsigned long timeleft; + unsigned long timeleft, request_size, copy_size; u16 smid; u16 ioc_status; u8 issue_reset = 0; @@ -1999,6 +2006,8 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) return -ENOMEM; } + request_size = ioc->diag_buffer_sz[buffer_type]; + if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) { printk(MPT2SAS_ERR_FMT "%s: either the starting_offset " "or bytes_to_read are not 4 byte aligned\n", ioc->name, @@ -2006,13 +2015,23 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) return -EINVAL; } + if (karg.starting_offset > request_size) + return -EINVAL; + diag_data = (void *)(request_data + karg.starting_offset); dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(%p), " "offset(%d), sz(%d)\n", ioc->name, __func__, diag_data, karg.starting_offset, karg.bytes_to_read)); + /* Truncate data on requests that are too large */ + if ((diag_data + karg.bytes_to_read < diag_data) || + (diag_data + karg.bytes_to_read > request_data + request_size)) + copy_size = request_size - karg.starting_offset; + else + copy_size = karg.bytes_to_read; + if (copy_to_user((void __user *)uarg->diagnostic_data, - diag_data, karg.bytes_to_read)) { + diag_data, copy_size)) { printk(MPT2SAS_ERR_FMT "%s: Unable to write " "mpt_diag_read_buffer_t data @ %p\n", ioc->name, __func__, diag_data); diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 96d5ad0..7f636b1 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -3814,6 +3814,9 @@ static long pmcraid_ioctl_passthrough( rc = -EFAULT; goto out_free_buffer; } + } else if (request_size < 0) { + rc = -EINVAL; + goto out_free_buffer; } /* check if we have any additional command parameters */ diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index e44ff64..e639125 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -322,14 +322,8 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work) kfree(evt); } - if (sdev->request_queue) { - sdev->request_queue->queuedata = NULL; - /* user context needed to free queue */ - scsi_free_queue(sdev->request_queue); - /* temporary expedient, try to catch use of queue lock - * after free of sdev */ - sdev->request_queue = NULL; - } + /* NULL queue means the device can't be used */ + sdev->request_queue = NULL; scsi_target_reap(scsi_target(sdev)); @@ -937,6 +931,12 @@ void __scsi_remove_device(struct scsi_device *sdev) if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); transport_destroy_device(dev); + + /* cause the request function to reject all I/O requests */ + sdev->request_queue->queuedata = NULL; + + /* Freeing the queue signals to block that we're done */ + scsi_free_queue(sdev->request_queue); put_device(dev); } diff --git a/drivers/staging/rt2860/common/cmm_data_pci.c b/drivers/staging/rt2860/common/cmm_data_pci.c index bef0bbd..f01a51c 100644 --- a/drivers/staging/rt2860/common/cmm_data_pci.c +++ b/drivers/staging/rt2860/common/cmm_data_pci.c @@ -444,7 +444,7 @@ int RTMPCheckRxError(struct rt_rtmp_adapter *pAd, return (NDIS_STATUS_FAILURE); } } - /* Drop not U2M frames, can't's drop here because we will drop beacon in this case */ + /* Drop not U2M frames, can't drop here because we will drop beacon in this case */ /* I am kind of doubting the U2M bit operation */ /* if (pRxD->U2M == 0) */ /* return(NDIS_STATUS_FAILURE); */ diff --git a/drivers/staging/rt2860/common/cmm_data_usb.c b/drivers/staging/rt2860/common/cmm_data_usb.c index 5637857..83a62fa 100644 --- a/drivers/staging/rt2860/common/cmm_data_usb.c +++ b/drivers/staging/rt2860/common/cmm_data_usb.c @@ -860,7 +860,7 @@ int RTMPCheckRxError(struct rt_rtmp_adapter *pAd, DBGPRINT_RAW(RT_DEBUG_ERROR, ("received packet too long\n")); return NDIS_STATUS_FAILURE; } - /* Drop not U2M frames, can't's drop here because we will drop beacon in this case */ + /* Drop not U2M frames, can't drop here because we will drop beacon in this case */ /* I am kind of doubting the U2M bit operation */ /* if (pRxD->U2M == 0) */ /* return(NDIS_STATUS_FAILURE); */ diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c index 20dae73..506547b 100644 --- a/drivers/staging/spectra/ffsport.c +++ b/drivers/staging/spectra/ffsport.c @@ -653,7 +653,7 @@ static int SBD_setup_device(struct spectra_nand_dev *dev, int which) } dev->queue->queuedata = dev; - /* As Linux block layer does't support >4KB hardware sector, */ + /* As Linux block layer doesn't support >4KB hardware sector, */ /* Here we force report 512 byte hardware sector size to Kernel */ blk_queue_logical_block_size(dev->queue, 512); diff --git a/drivers/staging/tidspbridge/dynload/cload.c b/drivers/staging/tidspbridge/dynload/cload.c index 5cecd237..fe1ef0a 100644 --- a/drivers/staging/tidspbridge/dynload/cload.c +++ b/drivers/staging/tidspbridge/dynload/cload.c @@ -718,7 +718,7 @@ static void dload_symbols(struct dload_state *dlthis) * as a temporary for .dllview record construction. * Allocate storage for the whole table. Add 1 to the section count * in case a trampoline section is auto-generated as well as the - * size of the trampoline section name so DLLView does't get lost. + * size of the trampoline section name so DLLView doesn't get lost. */ siz = sym_count * sizeof(struct local_symbol); diff --git a/drivers/staging/tty/specialix.c b/drivers/staging/tty/specialix.c index cb24c6d..5c3598e 100644 --- a/drivers/staging/tty/specialix.c +++ b/drivers/staging/tty/specialix.c @@ -978,7 +978,7 @@ static void sx_change_speed(struct specialix_board *bp, spin_lock_irqsave(&bp->lock, flags); sx_out(bp, CD186x_CAR, port_No(port)); - /* The Specialix board does't implement the RTS lines. + /* The Specialix board doesn't implement the RTS lines. They are used to set the IRQ level. Don't touch them. */ if (sx_crtscts(tty)) port->MSVR = MSVR_DTR | (sx_in(bp, CD186x_MSVR) & MSVR_RTS); |