Merge tag 'drm-intel-next-2012-04-23' of git://people.freedesktop.org/~danvet/drm...
authorDave Airlie <airlied@redhat.com>
Wed, 2 May 2012 08:21:50 +0000 (09:21 +0100)
committerDave Airlie <airlied@redhat.com>
Wed, 2 May 2012 08:22:29 +0000 (09:22 +0100)
Daniel Vetter writes:

A new drm-intel-next pull. Highlights:
- More gmbus patches from Daniel Kurtz, I think gmbus is now ready, all
 known issues fixed.
- Fencing cleanup and pipelined fencing removal from Chris.
- rc6 residency interface from Ben, useful for powertop.
- Cleanups and code reorg around the ringbuffer code (Ben&me).
- Use hw semaphores in the pageflip code from Ben.
- More vlv stuff from Jesse, unfortunately his vlv cpu is doa, so less
 merged than I've hoped for - we still have the unused function warning :(
- More hsw patches from Eugeni, again, not yet enabled fully.
- intel_pm.c refactoring from Eugeni.
- Ironlake sprite support from Chris.
- And various smaller improvements/fixes all over the place.

Note that this pull request also contains a backmerge of -rc3 to sort out
a few things in -next. I've also had to frob the shortlog a bit to exclude
anything that -rc3 brings in with this pull.

Regression wise we have a few strange bugs going on, but for all of them
closer inspection revealed that they've been pre-existing, just now
slightly more likely to be hit. And for most of them we have a patch
already. Otherwise QA has not reported any regressions, and I'm also not
aware of anything bad happening in 3.4.

* tag 'drm-intel-next-2012-04-23' of git://people.freedesktop.org/~danvet/drm-intel: (420 commits)
  drm/i915: rc6 residency (fix the fix)
  drm/i915/tv: fix open-coded ARRAY_SIZE.
  drm/i915: invalidate render cache on gen2
  drm/i915: Silence the change of LVDS sync polarity
  drm/i915: add generic power management initialization
  drm/i915: move clock gating functionality into intel_pm module
  drm/i915: move emon functionality into intel_pm module
  drm/i915: move drps, rps and rc6-related functions to intel_pm
  drm/i915: fix line breaks in intel_pm
  drm/i915: move watermarks settings into intel_pm module
  drm/i915: move fbc-related functionality into intel_pm module
  drm/i915: Refactor get_fence() to use the common fence writing routine
  drm/i915: Refactor fence clearing to use the common fence writing routine
  drm/i915: Refactor put_fence() to use the common fence writing routine
  drm/i915: Prepare to consolidate fence writing
  drm/i915: Remove the unsightly "optimisation" from flush_fence()
  drm/i915: Simplify fence finding
  drm/i915: Discard the unused obj->last_fenced_ring
  drm/i915: Remove unused ring->setup_seqno
  drm/i915: Remove fence pipelining
  ...

64 files changed:
arch/x86/include/asm/vga.h
arch/x86/video/fbdev.c
drivers/char/agp/generic.c
drivers/char/agp/sgi-agp.c
drivers/gpu/drm/drm_context.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_edid_load.c
drivers/gpu/drm/drm_edid_modes.h
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/gma500/cdv_device.c
drivers/gpu/drm/gma500/cdv_intel_crt.c
drivers/gpu/drm/gma500/cdv_intel_display.c
drivers/gpu/drm/gma500/cdv_intel_hdmi.c
drivers/gpu/drm/gma500/cdv_intel_lvds.c
drivers/gpu/drm/gma500/framebuffer.c
drivers/gpu/drm/gma500/gem.c
drivers/gpu/drm/gma500/gtt.c
drivers/gpu/drm/gma500/intel_bios.c
drivers/gpu/drm/gma500/intel_bios.h
drivers/gpu/drm/gma500/intel_opregion.c
drivers/gpu/drm/gma500/mdfld_device.c
drivers/gpu/drm/gma500/oaktrail_device.c
drivers/gpu/drm/gma500/oaktrail_hdmi.c
drivers/gpu/drm/gma500/psb_device.c
drivers/gpu/drm/gma500/psb_drv.c
drivers/gpu/drm/gma500/psb_drv.h
drivers/gpu/drm/gma500/psb_intel_drv.h
drivers/gpu/drm/gma500/psb_intel_reg.h
drivers/gpu/drm/gma500/psb_intel_sdvo.c
drivers/gpu/drm/gma500/psb_irq.c
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_reg.h
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_audio.c
drivers/gpu/drm/radeon/r600_hdmi.c
drivers/gpu/drm/radeon/r600_reg.h
drivers/gpu/drm/radeon/r600d.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_irq_kms.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/rs600d.h
drivers/gpu/drm/radeon/rv770d.h
drivers/gpu/vga/Kconfig
drivers/gpu/vga/vga_switcheroo.c
drivers/gpu/vga/vgaarb.c
drivers/pci/pci-sysfs.c
drivers/video/efifb.c
include/drm/drm_crtc.h
include/drm/drm_crtc_helper.h
include/drm/drm_edid.h
include/drm/drm_fixed.h
include/linux/pagemap.h
include/linux/vgaarb.h

index c4b9dc2..44282fb 100644 (file)
 #define vga_readb(x) (*(x))
 #define vga_writeb(x, y) (*(y) = (x))
 
+#ifdef CONFIG_FB_EFI
+#define __ARCH_HAS_VGA_DEFAULT_DEVICE
+extern struct pci_dev *vga_default_device(void);
+extern void vga_set_default_device(struct pci_dev *pdev);
+#endif
+
 #endif /* _ASM_X86_VGA_H */
index c5ffb6a..d5644bb 100644 (file)
@@ -9,24 +9,34 @@
 #include <linux/fb.h>
 #include <linux/pci.h>
 #include <linux/module.h>
+#include <linux/vgaarb.h>
 
 int fb_is_primary_device(struct fb_info *info)
 {
        struct device *device = info->device;
        struct pci_dev *pci_dev = NULL;
+       struct pci_dev *default_device = vga_default_device();
        struct resource *res = NULL;
-       int retval = 0;
 
        if (device)
                pci_dev = to_pci_dev(device);
 
-       if (pci_dev)
-               res = &pci_dev->resource[PCI_ROM_RESOURCE];
+       if (!pci_dev)
+               return 0;
+
+       if (default_device) {
+               if (pci_dev == default_device)
+                       return 1;
+               else
+                       return 0;
+       }
+
+       res = &pci_dev->resource[PCI_ROM_RESOURCE];
 
        if (res && res->flags & IORESOURCE_ROM_SHADOW)
-               retval = 1;
+               return 1;
 
-       return retval;
+       return 0;
 }
 EXPORT_SYMBOL(fb_is_primary_device);
 MODULE_LICENSE("GPL");
index 17e05d1..a0df182 100644 (file)
@@ -958,7 +958,7 @@ int agp_generic_create_gatt_table(struct agp_bridge_data *bridge)
        if (set_memory_uc((unsigned long)table, 1 << page_order))
                printk(KERN_WARNING "Could not set GATT table memory to UC!\n");
 
-       bridge->gatt_table = (void *)table;
+       bridge->gatt_table = (u32 __iomem *)table;
 #else
        bridge->gatt_table = ioremap_nocache(virt_to_phys(table),
                                        (PAGE_SIZE * (1 << page_order)));
@@ -1010,7 +1010,6 @@ int agp_generic_free_gatt_table(struct agp_bridge_data *bridge)
        case LVL2_APER_SIZE:
                /* The generic routines can't deal with 2 level gatt's */
                return -EINVAL;
-               break;
        default:
                page_order = 0;
                break;
@@ -1077,7 +1076,6 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
        case LVL2_APER_SIZE:
                /* The generic routines can't deal with 2 level gatt's */
                return -EINVAL;
-               break;
        default:
                num_entries = 0;
                break;
index ffa888c..1920003 100644 (file)
@@ -158,7 +158,6 @@ static int sgi_tioca_insert_memory(struct agp_memory *mem, off_t pg_start,
                break;
        case LVL2_APER_SIZE:
                return -EINVAL;
-               break;
        default:
                num_entries = 0;
                break;
index 325365f..affa629 100644 (file)
@@ -85,11 +85,12 @@ again:
        mutex_lock(&dev->struct_mutex);
        ret = idr_get_new_above(&dev->ctx_idr, NULL,
                                DRM_RESERVED_CONTEXTS, &new_id);
-       if (ret == -EAGAIN) {
-               mutex_unlock(&dev->struct_mutex);
-               goto again;
-       }
        mutex_unlock(&dev->struct_mutex);
+       if (ret == -EAGAIN)
+               goto again;
+       else if (ret)
+               return ret;
+
        return new_id;
 }
 
index d3aaeb6..a9ca1b8 100644 (file)
@@ -227,7 +227,7 @@ static int drm_mode_object_get(struct drm_device *dev,
 again:
        if (idr_pre_get(&dev->mode_config.crtc_idr, GFP_KERNEL) == 0) {
                DRM_ERROR("Ran out memory getting a mode number\n");
-               return -EINVAL;
+               return -ENOMEM;
        }
 
        mutex_lock(&dev->mode_config.idr_mutex);
@@ -235,6 +235,8 @@ again:
        mutex_unlock(&dev->mode_config.idr_mutex);
        if (ret == -EAGAIN)
                goto again;
+       else if (ret)
+               return ret;
 
        obj->id = new_id;
        obj->type = obj_type;
@@ -2185,6 +2187,47 @@ static int format_check(struct drm_mode_fb_cmd2 *r)
        }
 }
 
+static int framebuffer_check(struct drm_mode_fb_cmd2 *r)
+{
+       int ret, hsub, vsub, num_planes, i;
+
+       ret = format_check(r);
+       if (ret) {
+               DRM_ERROR("bad framebuffer format 0x%08x\n", r->pixel_format);
+               return ret;
+       }
+
+       hsub = drm_format_horz_chroma_subsampling(r->pixel_format);
+       vsub = drm_format_vert_chroma_subsampling(r->pixel_format);
+       num_planes = drm_format_num_planes(r->pixel_format);
+
+       if (r->width == 0 || r->width % hsub) {
+               DRM_ERROR("bad framebuffer width %u\n", r->height);
+               return -EINVAL;
+       }
+
+       if (r->height == 0 || r->height % vsub) {
+               DRM_ERROR("bad framebuffer height %u\n", r->height);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < num_planes; i++) {
+               unsigned int width = r->width / (i != 0 ? hsub : 1);
+
+               if (!r->handles[i]) {
+                       DRM_ERROR("no buffer object handle for plane %d\n", i);
+                       return -EINVAL;
+               }
+
+               if (r->pitches[i] < drm_format_plane_cpp(r->pixel_format, i) * width) {
+                       DRM_ERROR("bad pitch %u for plane %d\n", r->pitches[i], i);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 /**
  * drm_mode_addfb2 - add an FB to the graphics configuration
  * @inode: inode from the ioctl
@@ -2224,11 +2267,9 @@ int drm_mode_addfb2(struct drm_device *dev,
                return -EINVAL;
        }
 
-       ret = format_check(r);
-       if (ret) {
-               DRM_ERROR("bad framebuffer format 0x%08x\n", r->pixel_format);
+       ret = framebuffer_check(r);
+       if (ret)
                return ret;
-       }
 
        mutex_lock(&dev->mode_config.mutex);
 
@@ -3466,3 +3507,140 @@ void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
        }
 }
 EXPORT_SYMBOL(drm_fb_get_bpp_depth);
+
+/**
+ * drm_format_num_planes - get the number of planes for format
+ * @format: pixel format (DRM_FORMAT_*)
+ *
+ * RETURNS:
+ * The number of planes used by the specified pixel format.
+ */
+int drm_format_num_planes(uint32_t format)
+{
+       switch (format) {
+       case DRM_FORMAT_YUV410:
+       case DRM_FORMAT_YVU410:
+       case DRM_FORMAT_YUV411:
+       case DRM_FORMAT_YVU411:
+       case DRM_FORMAT_YUV420:
+       case DRM_FORMAT_YVU420:
+       case DRM_FORMAT_YUV422:
+       case DRM_FORMAT_YVU422:
+       case DRM_FORMAT_YUV444:
+       case DRM_FORMAT_YVU444:
+               return 3;
+       case DRM_FORMAT_NV12:
+       case DRM_FORMAT_NV21:
+       case DRM_FORMAT_NV16:
+       case DRM_FORMAT_NV61:
+               return 2;
+       default:
+               return 1;
+       }
+}
+EXPORT_SYMBOL(drm_format_num_planes);
+
+/**
+ * drm_format_plane_cpp - determine the bytes per pixel value
+ * @format: pixel format (DRM_FORMAT_*)
+ * @plane: plane index
+ *
+ * RETURNS:
+ * The bytes per pixel value for the specified plane.
+ */
+int drm_format_plane_cpp(uint32_t format, int plane)
+{
+       unsigned int depth;
+       int bpp;
+
+       if (plane >= drm_format_num_planes(format))
+               return 0;
+
+       switch (format) {
+       case DRM_FORMAT_YUYV:
+       case DRM_FORMAT_YVYU:
+       case DRM_FORMAT_UYVY:
+       case DRM_FORMAT_VYUY:
+               return 2;
+       case DRM_FORMAT_NV12:
+       case DRM_FORMAT_NV21:
+       case DRM_FORMAT_NV16:
+       case DRM_FORMAT_NV61:
+               return plane ? 2 : 1;
+       case DRM_FORMAT_YUV410:
+       case DRM_FORMAT_YVU410:
+       case DRM_FORMAT_YUV411:
+       case DRM_FORMAT_YVU411:
+       case DRM_FORMAT_YUV420:
+       case DRM_FORMAT_YVU420:
+       case DRM_FORMAT_YUV422:
+       case DRM_FORMAT_YVU422:
+       case DRM_FORMAT_YUV444:
+       case DRM_FORMAT_YVU444:
+               return 1;
+       default:
+               drm_fb_get_bpp_depth(format, &depth, &bpp);
+               return bpp >> 3;
+       }
+}
+EXPORT_SYMBOL(drm_format_plane_cpp);
+
+/**
+ * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor
+ * @format: pixel format (DRM_FORMAT_*)
+ *
+ * RETURNS:
+ * The horizontal chroma subsampling factor for the
+ * specified pixel format.
+ */
+int drm_format_horz_chroma_subsampling(uint32_t format)
+{
+       switch (format) {
+       case DRM_FORMAT_YUV411:
+       case DRM_FORMAT_YVU411:
+       case DRM_FORMAT_YUV410:
+       case DRM_FORMAT_YVU410:
+               return 4;
+       case DRM_FORMAT_YUYV:
+       case DRM_FORMAT_YVYU:
+       case DRM_FORMAT_UYVY:
+       case DRM_FORMAT_VYUY:
+       case DRM_FORMAT_NV12:
+       case DRM_FORMAT_NV21:
+       case DRM_FORMAT_NV16:
+       case DRM_FORMAT_NV61:
+       case DRM_FORMAT_YUV422:
+       case DRM_FORMAT_YVU422:
+       case DRM_FORMAT_YUV420:
+       case DRM_FORMAT_YVU420:
+               return 2;
+       default:
+               return 1;
+       }
+}
+EXPORT_SYMBOL(drm_format_horz_chroma_subsampling);
+
+/**
+ * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor
+ * @format: pixel format (DRM_FORMAT_*)
+ *
+ * RETURNS:
+ * The vertical chroma subsampling factor for the
+ * specified pixel format.
+ */
+int drm_format_vert_chroma_subsampling(uint32_t format)
+{
+       switch (format) {
+       case DRM_FORMAT_YUV410:
+       case DRM_FORMAT_YVU410:
+               return 4;
+       case DRM_FORMAT_YUV420:
+       case DRM_FORMAT_YVU420:
+       case DRM_FORMAT_NV12:
+       case DRM_FORMAT_NV21:
+               return 2;
+       default:
+               return 1;
+       }
+}
+EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
index 8111889..974196a 100644 (file)
@@ -1023,36 +1023,3 @@ void drm_helper_hpd_irq_event(struct drm_device *dev)
                queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, 0);
 }
 EXPORT_SYMBOL(drm_helper_hpd_irq_event);
-
-
-/**
- * drm_format_num_planes - get the number of planes for format
- * @format: pixel format (DRM_FORMAT_*)
- *
- * RETURNS:
- * The number of planes used by the specified pixel format.
- */
-int drm_format_num_planes(uint32_t format)
-{
-       switch (format) {
-       case DRM_FORMAT_YUV410:
-       case DRM_FORMAT_YVU410:
-       case DRM_FORMAT_YUV411:
-       case DRM_FORMAT_YVU411:
-       case DRM_FORMAT_YUV420:
-       case DRM_FORMAT_YVU420:
-       case DRM_FORMAT_YUV422:
-       case DRM_FORMAT_YVU422:
-       case DRM_FORMAT_YUV444:
-       case DRM_FORMAT_YVU444:
-               return 3;
-       case DRM_FORMAT_NV12:
-       case DRM_FORMAT_NV21:
-       case DRM_FORMAT_NV16:
-       case DRM_FORMAT_NV61:
-               return 2;
-       default:
-               return 1;
-       }
-}
-EXPORT_SYMBOL(drm_format_num_planes);
index 5a18b0d..608bddf 100644 (file)
@@ -81,7 +81,7 @@ struct detailed_mode_closure {
 #define LEVEL_CVT      3
 
 static struct edid_quirk {
-       char *vendor;
+       char vendor[4];
        int product_id;
        u32 quirks;
 } edid_quirk_list[] = {
@@ -149,13 +149,13 @@ EXPORT_SYMBOL(drm_edid_header_is_valid);
  * Sanity check the EDID block (base or extension).  Return 0 if the block
  * doesn't check out, or 1 if it's valid.
  */
-bool drm_edid_block_valid(u8 *raw_edid)
+bool drm_edid_block_valid(u8 *raw_edid, int block)
 {
        int i;
        u8 csum = 0;
        struct edid *edid = (struct edid *)raw_edid;
 
-       if (raw_edid[0] == 0x00) {
+       if (block == 0) {
                int score = drm_edid_header_is_valid(raw_edid);
                if (score == 8) ;
                else if (score >= 6) {
@@ -219,7 +219,7 @@ bool drm_edid_is_valid(struct edid *edid)
                return false;
 
        for (i = 0; i <= edid->extensions; i++)
-               if (!drm_edid_block_valid(raw + i * EDID_LENGTH))
+               if (!drm_edid_block_valid(raw + i * EDID_LENGTH, i))
                        return false;
 
        return true;
@@ -299,7 +299,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
        for (i = 0; i < 4; i++) {
                if (drm_do_probe_ddc_edid(adapter, block, 0, EDID_LENGTH))
                        goto out;
-               if (drm_edid_block_valid(block))
+               if (drm_edid_block_valid(block, 0))
                        break;
                if (i == 0 && drm_edid_is_zero(block, EDID_LENGTH)) {
                        connector->null_edid_counter++;
@@ -324,7 +324,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
                                  block + (valid_extensions + 1) * EDID_LENGTH,
                                  j, EDID_LENGTH))
                                goto out;
-                       if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH)) {
+                       if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH, j)) {
                                valid_extensions++;
                                break;
                        }
@@ -486,23 +486,47 @@ static void edid_fixup_preferred(struct drm_connector *connector,
        preferred_mode->type |= DRM_MODE_TYPE_PREFERRED;
 }
 
+static bool
+mode_is_rb(const struct drm_display_mode *mode)
+{
+       return (mode->htotal - mode->hdisplay == 160) &&
+              (mode->hsync_end - mode->hdisplay == 80) &&
+              (mode->hsync_end - mode->hsync_start == 32) &&
+              (mode->vsync_start - mode->vdisplay == 3);
+}
+
+/*
+ * drm_mode_find_dmt - Create a copy of a mode if present in DMT
+ * @dev: Device to duplicate against
+ * @hsize: Mode width
+ * @vsize: Mode height
+ * @fresh: Mode refresh rate
+ * @rb: Mode reduced-blanking-ness
+ *
+ * Walk the DMT mode list looking for a match for the given parameters.
+ * Return a newly allocated copy of the mode, or NULL if not found.
+ */
 struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
-                                          int hsize, int vsize, int fresh)
+                                          int hsize, int vsize, int fresh,
+                                          bool rb)
 {
-       struct drm_display_mode *mode = NULL;
        int i;
 
        for (i = 0; i < drm_num_dmt_modes; i++) {
                const struct drm_display_mode *ptr = &drm_dmt_modes[i];
-               if (hsize == ptr->hdisplay &&
-                       vsize == ptr->vdisplay &&
-                       fresh == drm_mode_vrefresh(ptr)) {
-                       /* get the expected default mode */
-                       mode = drm_mode_duplicate(dev, ptr);
-                       break;
-               }
+               if (hsize != ptr->hdisplay)
+                       continue;
+               if (vsize != ptr->vdisplay)
+                       continue;
+               if (fresh != drm_mode_vrefresh(ptr))
+                       continue;
+               if (rb != mode_is_rb(ptr))
+                       continue;
+
+               return drm_mode_duplicate(dev, ptr);
        }
-       return mode;
+
+       return NULL;
 }
 EXPORT_SYMBOL(drm_mode_find_dmt);
 
@@ -731,10 +755,17 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid,
        }
 
        /* check whether it can be found in default mode table */
-       mode = drm_mode_find_dmt(dev, hsize, vsize, vrefresh_rate);
+       if (drm_monitor_supports_rb(edid)) {
+               mode = drm_mode_find_dmt(dev, hsize, vsize, vrefresh_rate,
+                                        true);
+               if (mode)
+                       return mode;
+       }
+       mode = drm_mode_find_dmt(dev, hsize, vsize, vrefresh_rate, false);
        if (mode)
                return mode;
 
+       /* okay, generate it */
        switch (timing_level) {
        case LEVEL_DMT:
                break;
@@ -748,6 +779,8 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid,
                 * secondary GTF curve.  Please don't do that.
                 */
                mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
+               if (!mode)
+                       return NULL;
                if (drm_mode_hsync(mode) > drm_gtf2_hbreak(edid)) {
                        drm_mode_destroy(dev, mode);
                        mode = drm_gtf_mode_complex(dev, hsize, vsize,
@@ -908,15 +941,6 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
        return mode;
 }
 
-static bool
-mode_is_rb(const struct drm_display_mode *mode)
-{
-       return (mode->htotal - mode->hdisplay == 160) &&
-              (mode->hsync_end - mode->hdisplay == 80) &&
-              (mode->hsync_end - mode->hsync_start == 32) &&
-              (mode->vsync_start - mode->vdisplay == 3);
-}
-
 static bool
 mode_in_hsync_range(const struct drm_display_mode *mode,
                    struct edid *edid, u8 *t)
@@ -994,12 +1018,8 @@ mode_in_range(const struct drm_display_mode *mode, struct edid *edid,
        return true;
 }
 
-/*
- * XXX If drm_dmt_modes ever regrows the CVT-R modes (and it will) this will
- * need to account for them.
- */
 static int
-drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid,
+drm_dmt_modes_for_range(struct drm_connector *connector, struct edid *edid,
                        struct detailed_timing *timing)
 {
        int i, modes = 0;
@@ -1019,17 +1039,110 @@ drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid,
        return modes;
 }
 
+/* fix up 1366x768 mode from 1368x768;
+ * GFT/CVT can't express 1366 width which isn't dividable by 8
+ */
+static void fixup_mode_1366x768(struct drm_display_mode *mode)
+{
+       if (mode->hdisplay == 1368 && mode->vdisplay == 768) {
+               mode->hdisplay = 1366;
+               mode->hsync_start--;
+               mode->hsync_end--;
+               drm_mode_set_name(mode);
+       }
+}
+
+static int
+drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid,
+                       struct detailed_timing *timing)
+{
+       int i, modes = 0;
+       struct drm_display_mode *newmode;
+       struct drm_device *dev = connector->dev;
+
+       for (i = 0; i < num_extra_modes; i++) {
+               const struct minimode *m = &extra_modes[i];
+               newmode = drm_gtf_mode(dev, m->w, m->h, m->r, 0, 0);
+               if (!newmode)
+                       return modes;
+
+               fixup_mode_1366x768(newmode);
+               if (!mode_in_range(newmode, edid, timing)) {
+                       drm_mode_destroy(dev, newmode);
+                       continue;
+               }
+
+               drm_mode_probed_add(connector, newmode);
+               modes++;
+       }
+
+       return modes;
+}
+
+static int
+drm_cvt_modes_for_range(struct drm_connector *connector, struct edid *edid,
+                       struct detailed_timing *timing)
+{
+       int i, modes = 0;
+       struct drm_display_mode *newmode;
+       struct drm_device *dev = connector->dev;
+       bool rb = drm_monitor_supports_rb(edid);
+
+       for (i = 0; i < num_extra_modes; i++) {
+               const struct minimode *m = &extra_modes[i];
+               newmode = drm_cvt_mode(dev, m->w, m->h, m->r, rb, 0, 0);
+               if (!newmode)
+                       return modes;
+
+               fixup_mode_1366x768(newmode);
+               if (!mode_in_range(newmode, edid, timing)) {
+                       drm_mode_destroy(dev, newmode);
+                       continue;
+               }
+
+               drm_mode_probed_add(connector, newmode);
+               modes++;
+       }
+
+       return modes;
+}
+
 static void
 do_inferred_modes(struct detailed_timing *timing, void *c)
 {
        struct detailed_mode_closure *closure = c;
        struct detailed_non_pixel *data = &timing->data.other_data;
-       int gtf = (closure->edid->features & DRM_EDID_FEATURE_DEFAULT_GTF);
+       struct detailed_data_monitor_range *range = &data->data.range;
+
+       if (data->type != EDID_DETAIL_MONITOR_RANGE)
+               return;
 
-       if (gtf && data->type == EDID_DETAIL_MONITOR_RANGE)
+       closure->modes += drm_dmt_modes_for_range(closure->connector,
+                                                 closure->edid,
+                                                 timing);
+       
+       if (!version_greater(closure->edid, 1, 1))
+               return; /* GTF not defined yet */
+
+       switch (range->flags) {
+       case 0x02: /* secondary gtf, XXX could do more */
+       case 0x00: /* default gtf */
                closure->modes += drm_gtf_modes_for_range(closure->connector,
                                                          closure->edid,
                                                          timing);
+               break;
+       case 0x04: /* cvt, only in 1.4+ */
+               if (!version_greater(closure->edid, 1, 3))
+                       break;
+
+               closure->modes += drm_cvt_modes_for_range(closure->connector,
+                                                         closure->edid,
+                                                         timing);
+               break;
+       case 0x01: /* just the ranges, no formula */
+       default:
+               break;
+       }
 }
 
 static int
@@ -1062,8 +1175,8 @@ drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing)
                                mode = drm_mode_find_dmt(connector->dev,
                                                         est3_modes[m].w,
                                                         est3_modes[m].h,
-                                                        est3_modes[m].r
-                                                        /*, est3_modes[m].rb */);
+                                                        est3_modes[m].r,
+                                                        est3_modes[m].rb);
                                if (mode) {
                                        drm_mode_probed_add(connector, mode);
                                        modes++;
@@ -1312,6 +1425,8 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
 #define VENDOR_BLOCK    0x03
 #define SPEAKER_BLOCK  0x04
 #define EDID_BASIC_AUDIO       (1 << 6)
+#define EDID_CEA_YCRCB444      (1 << 5)
+#define EDID_CEA_YCRCB422      (1 << 4)
 
 /**
  * Search EDID for CEA extension block.
@@ -1666,13 +1781,29 @@ static void drm_add_display_info(struct edid *edid,
        info->bpc = 0;
        info->color_formats = 0;
 
-       /* Only defined for 1.4 with digital displays */
-       if (edid->revision < 4)
+       if (edid->revision < 3)
                return;
 
        if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
                return;
 
+       /* Get data from CEA blocks if present */
+       edid_ext = drm_find_cea_extension(edid);
+       if (edid_ext) {
+               info->cea_rev = edid_ext[1];
+
+               /* The existence of a CEA block should imply RGB support */
+               info->color_formats = DRM_COLOR_FORMAT_RGB444;
+               if (edid_ext[3] & EDID_CEA_YCRCB444)
+                       info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
+               if (edid_ext[3] & EDID_CEA_YCRCB422)
+                       info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
+       }
+
+       /* Only defined for 1.4 with digital displays */
+       if (edid->revision < 4)
+               return;
+
        switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
        case DRM_EDID_DIGITAL_DEPTH_6:
                info->bpc = 6;
@@ -1698,18 +1829,11 @@ static void drm_add_display_info(struct edid *edid,
                break;
        }
 
-       info->color_formats = DRM_COLOR_FORMAT_RGB444;
-       if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB444)
-               info->color_formats = DRM_COLOR_FORMAT_YCRCB444;
-       if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB422)
-               info->color_formats = DRM_COLOR_FORMAT_YCRCB422;
-
-       /* Get data from CEA blocks if present */
-       edid_ext = drm_find_cea_extension(edid);
-       if (!edid_ext)
-               return;
-
-       info->cea_rev = edid_ext[1];
+       info->color_formats |= DRM_COLOR_FORMAT_RGB444;
+       if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444)
+               info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
+       if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
+               info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
 }
 
 /**
index da9acba..48c927c 100644 (file)
@@ -173,7 +173,7 @@ static int edid_load(struct drm_connector *connector, char *name,
        }
        memcpy(edid, fwdata, fwsize);
 
-       if (!drm_edid_block_valid(edid)) {
+       if (!drm_edid_block_valid(edid, 0)) {
                DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
                    name);
                kfree(edid);
@@ -185,7 +185,7 @@ static int edid_load(struct drm_connector *connector, char *name,
                if (i != valid_extensions + 1)
                        memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
                            edid + i * EDID_LENGTH, EDID_LENGTH);
-               if (drm_edid_block_valid(edid + i * EDID_LENGTH))
+               if (drm_edid_block_valid(edid + i * EDID_LENGTH, i))
                        valid_extensions++;
        }
 
index a91ffb1..ff98a7e 100644 (file)
@@ -30,7 +30,6 @@
 /*
  * Autogenerated from the DMT spec.
  * This table is copied from xfree86/modes/xf86EdidModes.c.
- * But the mode with Reduced blank feature is deleted.
  */
 static const struct drm_display_mode drm_dmt_modes[] = {
        /* 640x350@85Hz */
@@ -81,6 +80,10 @@ static const struct drm_display_mode drm_dmt_modes[] = {
        { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 56250, 800, 832,
                   896, 1048, 0, 600, 601, 604, 631, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 800x600@120Hz RB */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 73250, 800, 848,
+                  880, 960, 0, 600, 603, 607, 636, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 848x480@60Hz */
        { DRM_MODE("848x480", DRM_MODE_TYPE_DRIVER, 33750, 848, 864,
                   976, 1088, 0, 480, 486, 494, 517, 0,
@@ -106,10 +109,18 @@ static const struct drm_display_mode drm_dmt_modes[] = {
        { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 94500, 1024, 1072,
                   1168, 1376, 0, 768, 769, 772, 808, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1024x768@120Hz RB */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 115500, 1024, 1072,
+                  1104, 1184, 0, 768, 771, 775, 813, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 1152x864@75Hz */
        { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
                   1344, 1600, 0, 864, 865, 868, 900, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1280x768@60Hz RB */
+       { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 68250, 1280, 1328,
+                  1360, 1440, 0, 768, 771, 778, 790, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 1280x768@60Hz */
        { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 79500, 1280, 1344,
                   1472, 1664, 0, 768, 771, 778, 798, 0,
@@ -122,6 +133,14 @@ static const struct drm_display_mode drm_dmt_modes[] = {
        { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 117500, 1280, 1360,
                   1496, 1712, 0, 768, 771, 778, 809, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1280x768@120Hz RB */
+       { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 140250, 1280, 1328,
+                  1360, 1440, 0, 768, 771, 778, 813, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 1280x800@60Hz RB */
+       { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 71000, 1280, 1328,
+                  1360, 1440, 0, 800, 803, 809, 823, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 1280x800@60Hz */
        { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 83500, 1280, 1352,
                   1480, 1680, 0, 800, 803, 809, 831, 0,
@@ -134,6 +153,10 @@ static const struct drm_display_mode drm_dmt_modes[] = {
        { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 122500, 1280, 1360,
                   1496, 1712, 0, 800, 803, 809, 843, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1280x800@120Hz RB */
+       { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 146250, 1280, 1328,
+                  1360, 1440, 0, 800, 803, 809, 847, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 1280x960@60Hz */
        { DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1376,
                   1488, 1800, 0, 960, 961, 964, 1000, 0,
@@ -142,6 +165,10 @@ static const struct drm_display_mode drm_dmt_modes[] = {
        { DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1344,
                   1504, 1728, 0, 960, 961, 964, 1011, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1280x960@120Hz RB */
+       { DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 175500, 1280, 1328,
+                  1360, 1440, 0, 960, 963, 967, 1017, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 1280x1024@60Hz */
        { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1328,
                   1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
@@ -154,22 +181,42 @@ static const struct drm_display_mode drm_dmt_modes[] = {
        { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 157500, 1280, 1344,
                   1504, 1728, 0, 1024, 1025, 1028, 1072, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1280x1024@120Hz RB */
+       { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 187250, 1280, 1328,
+                  1360, 1440, 0, 1024, 1027, 1034, 1084, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 1360x768@60Hz */
        { DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 85500, 1360, 1424,
                   1536, 1792, 0, 768, 771, 777, 795, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1440x1050@60Hz */
+       /* 1360x768@120Hz RB */
+       { DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 148250, 1360, 1408,
+                  1440, 1520, 0, 768, 771, 776, 813, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 1400x1050@60Hz RB */
+       { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 101000, 1400, 1448,
+                  1480, 1560, 0, 1050, 1053, 1057, 1080, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 1400x1050@60Hz */
        { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 121750, 1400, 1488,
                   1632, 1864, 0, 1050, 1053, 1057, 1089, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1440x1050@75Hz */
+       /* 1400x1050@75Hz */
        { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 156000, 1400, 1504,
                   1648, 1896, 0, 1050, 1053, 1057, 1099, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1440x1050@85Hz */
+       /* 1400x1050@85Hz */
        { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 179500, 1400, 1504,
                   1656, 1912, 0, 1050, 1053, 1057, 1105, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1400x1050@120Hz RB */
+       { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 208000, 1400, 1448,
+                  1480, 1560, 0, 1050, 1053, 1057, 1112, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 1440x900@60Hz RB */
+       { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 88750, 1440, 1488,
+                  1520, 1600, 0, 900, 903, 909, 926, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 1440x900@60Hz */
        { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440, 1520,
                   1672, 1904, 0, 900, 903, 909, 934, 0,
@@ -182,6 +229,10 @@ static const struct drm_display_mode drm_dmt_modes[] = {
        { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 157000, 1440, 1544,
                   1696, 1952, 0, 900, 903, 909, 948, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1440x900@120Hz RB */
+       { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 182750, 1440, 1488,
+                  1520, 1600, 0, 900, 903, 909, 953, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 1600x1200@60Hz */
        { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, 1664,
                   1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
@@ -202,6 +253,14 @@ static const struct drm_display_mode drm_dmt_modes[] = {
        { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 229500, 1600, 1664,
                   1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1600x1200@120Hz RB */
+       { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 268250, 1600, 1648,
+                  1680, 1760, 0, 1200, 1203, 1207, 1271, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 1680x1050@60Hz RB */
+       { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 119000, 1680, 1728,
+                  1760, 1840, 0, 1050, 1053, 1059, 1080, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 1680x1050@60Hz */
        { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 146250, 1680, 1784,
                   1960, 2240, 0, 1050, 1053, 1059, 1089, 0,
@@ -214,15 +273,23 @@ static const struct drm_display_mode drm_dmt_modes[] = {
        { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 214750, 1680, 1808,
                   1984, 2288, 0, 1050, 1053, 1059, 1105, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1680x1050@120Hz RB */
+       { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 245500, 1680, 1728,
+                  1760, 1840, 0, 1050, 1053, 1059, 1112, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 1792x1344@60Hz */
        { DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 204750, 1792, 1920,
                   2120, 2448, 0, 1344, 1345, 1348, 1394, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1729x1344@75Hz */
+       /* 1792x1344@75Hz */
        { DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 261000, 1792, 1888,
                   2104, 2456, 0, 1344, 1345, 1348, 1417, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1853x1392@60Hz */
+       /* 1792x1344@120Hz RB */
+       { DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 333250, 1792, 1840,
+                  1872, 1952, 0, 1344, 1347, 1351, 1423, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 1856x1392@60Hz */
        { DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 218250, 1856, 1952,
                   2176, 2528, 0, 1392, 1393, 1396, 1439, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
@@ -230,6 +297,14 @@ static const struct drm_display_mode drm_dmt_modes[] = {
        { DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 288000, 1856, 1984,
                   2208, 2560, 0, 1392, 1395, 1399, 1500, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1856x1392@120Hz RB */
+       { DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 356500, 1856, 1904,
+                  1936, 2016, 0, 1392, 1395, 1399, 1474, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 1920x1200@60Hz RB */
+       { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 154000, 1920, 1968,
+                  2000, 2080, 0, 1200, 1203, 1209, 1235, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 1920x1200@60Hz */
        { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920, 2056,
                   2256, 2592, 0, 1200, 1203, 1209, 1245, 0,
@@ -242,6 +317,10 @@ static const struct drm_display_mode drm_dmt_modes[] = {
        { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 281250, 1920, 2064,
                   2272, 2624, 0, 1200, 1203, 1209, 1262, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1920x1200@120Hz RB */
+       { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 317000, 1920, 1968,
+                  2000, 2080, 0, 1200, 1203, 1209, 1271, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 1920x1440@60Hz */
        { DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 234000, 1920, 2048,
                   2256, 2600, 0, 1440, 1441, 1444, 1500, 0,
@@ -250,6 +329,14 @@ static const struct drm_display_mode drm_dmt_modes[] = {
        { DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2064,
                   2288, 2640, 0, 1440, 1441, 1444, 1500, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 1920x1440@120Hz RB */
+       { DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 380500, 1920, 1968,
+                  2000, 2080, 0, 1440, 1443, 1447, 1525, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+       /* 2560x1600@60Hz RB */
+       { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 268500, 2560, 2608,
+                  2640, 2720, 0, 1600, 1603, 1609, 1646, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 2560x1600@60Hz */
        { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 348500, 2560, 2752,
                   3032, 3504, 0, 1600, 1603, 1609, 1658, 0,
@@ -262,6 +349,11 @@ static const struct drm_display_mode drm_dmt_modes[] = {
        { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 505250, 2560, 2768,
                   3048, 3536, 0, 1600, 1603, 1609, 1682, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+       /* 2560x1600@120Hz RB */
+       { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 552750, 2560, 2608,
+                  2640, 2720, 0, 1600, 1603, 1609, 1694, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+
 };
 static const int drm_num_dmt_modes =
        sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
@@ -320,12 +412,14 @@ static const struct drm_display_mode edid_est_modes[] = {
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */
 };
 
-static const struct {
+struct minimode {
        short w;
        short h;
        short r;
        short rb;
-} est3_modes[] = {
+};
+
+static const struct minimode est3_modes[] = {
        /* byte 6 */
        { 640, 350, 85, 0 },
        { 640, 400, 85, 0 },
@@ -377,288 +471,304 @@ static const struct {
        { 1920, 1440, 60, 0 },
        { 1920, 1440, 75, 0 },
 };
-static const int num_est3_modes = sizeof(est3_modes) / sizeof(est3_modes[0]);
+static const int num_est3_modes = ARRAY_SIZE(est3_modes);
+
+static const struct minimode extra_modes[] = {
+       { 1024, 576,  60, 0 },
+       { 1366, 768,  60, 0 },
+       { 1600, 900,  60, 0 },
+       { 1680, 945,  60, 0 },
+       { 1920, 1080, 60, 0 },
+       { 2048, 1152, 60, 0 },
+       { 2048, 1536, 60, 0 },
+};
+static const int num_extra_modes = ARRAY_SIZE(extra_modes);
 
 /*
  * Probably taken from CEA-861 spec.
  * This table is converted from xorg's hw/xfree86/modes/xf86EdidModes.c.
  */
 static const struct drm_display_mode edid_cea_modes[] = {
-       /* 640x480@60Hz */
+       /* 1 - 640x480@60Hz */
        { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
                   752, 800, 0, 480, 490, 492, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 720x480@60Hz */
+       /* 2 - 720x480@60Hz */
        { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
                   798, 858, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 720x480@60Hz */
+       /* 3 - 720x480@60Hz */
        { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
                   798, 858, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1280x720@60Hz */
+       /* 4 - 1280x720@60Hz */
        { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
                   1430, 1650, 0, 720, 725, 730, 750, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1920x1080i@60Hz */
+       /* 5 - 1920x1080i@60Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
                   2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
-       /* 1440x480i@60Hz */
+       /* 6 - 1440x480i@60Hz */
        { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
                   1602, 1716, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
-                       DRM_MODE_FLAG_INTERLACE) },
-       /* 1440x480i@60Hz */
+                       DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+       /* 7 - 1440x480i@60Hz */
        { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
                   1602, 1716, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
-                       DRM_MODE_FLAG_INTERLACE) },
-       /* 1440x240@60Hz */
+                       DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+       /* 8 - 1440x240@60Hz */
        { DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
                   1602, 1716, 0, 240, 244, 247, 262, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1440x240@60Hz */
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
+                       DRM_MODE_FLAG_DBLCLK) },
+       /* 9 - 1440x240@60Hz */
        { DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
                   1602, 1716, 0, 240, 244, 247, 262, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 2880x480i@60Hz */
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
+                       DRM_MODE_FLAG_DBLCLK) },
+       /* 10 - 2880x480i@60Hz */
        { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
                   3204, 3432, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
-       /* 2880x480i@60Hz */
+       /* 11 - 2880x480i@60Hz */
        { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
                   3204, 3432, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
-       /* 2880x240@60Hz */
+       /* 12 - 2880x240@60Hz */
        { DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
                   3204, 3432, 0, 240, 244, 247, 262, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 2880x240@60Hz */
+       /* 13 - 2880x240@60Hz */
        { DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
                   3204, 3432, 0, 240, 244, 247, 262, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1440x480@60Hz */
+       /* 14 - 1440x480@60Hz */
        { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472,
                   1596, 1716, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1440x480@60Hz */
+       /* 15 - 1440x480@60Hz */
        { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472,
                   1596, 1716, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1920x1080@60Hz */
+       /* 16 - 1920x1080@60Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
                   2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 720x576@50Hz */
+       /* 17 - 720x576@50Hz */
        { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
                   796, 864, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 720x576@50Hz */
+       /* 18 - 720x576@50Hz */
        { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
                   796, 864, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1280x720@50Hz */
+       /* 19 - 1280x720@50Hz */
        { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720,
                   1760, 1980, 0, 720, 725, 730, 750, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1920x1080i@50Hz */
+       /* 20 - 1920x1080i@50Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
                   2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
-       /* 1440x576i@50Hz */
+       /* 21 - 1440x576i@50Hz */
        { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
                   1590, 1728, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
-                       DRM_MODE_FLAG_INTERLACE) },
-       /* 1440x576i@50Hz */
+                       DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+       /* 22 - 1440x576i@50Hz */
        { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
                   1590, 1728, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
-                       DRM_MODE_FLAG_INTERLACE) },
-       /* 1440x288@50Hz */
+                       DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+       /* 23 - 1440x288@50Hz */
        { DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
                   1590, 1728, 0, 288, 290, 293, 312, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1440x288@50Hz */
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
+                       DRM_MODE_FLAG_DBLCLK) },
+       /* 24 - 1440x288@50Hz */
        { DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
                   1590, 1728, 0, 288, 290, 293, 312, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 2880x576i@50Hz */
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
+                       DRM_MODE_FLAG_DBLCLK) },
+       /* 25 - 2880x576i@50Hz */
        { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
                   3180, 3456, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
-       /* 2880x576i@50Hz */
+       /* 26 - 2880x576i@50Hz */
        { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
                   3180, 3456, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
-       /* 2880x288@50Hz */
+       /* 27 - 2880x288@50Hz */
        { DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
                   3180, 3456, 0, 288, 290, 293, 312, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 2880x288@50Hz */
+       /* 28 - 2880x288@50Hz */
        { DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
                   3180, 3456, 0, 288, 290, 293, 312, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1440x576@50Hz */
+       /* 29 - 1440x576@50Hz */
        { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
                   1592, 1728, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1440x576@50Hz */
+       /* 30 - 1440x576@50Hz */
        { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
                   1592, 1728, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1920x1080@50Hz */
+       /* 31 - 1920x1080@50Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
                   2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1920x1080@24Hz */
+       /* 32 - 1920x1080@24Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558,
                   2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1920x1080@25Hz */
+       /* 33 - 1920x1080@25Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
                   2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1920x1080@30Hz */
+       /* 34 - 1920x1080@30Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
                   2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 2880x480@60Hz */
+       /* 35 - 2880x480@60Hz */
        { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944,
                   3192, 3432, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 2880x480@60Hz */
+       /* 36 - 2880x480@60Hz */
        { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944,
                   3192, 3432, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 2880x576@50Hz */
+       /* 37 - 2880x576@50Hz */
        { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928,
                   3184, 3456, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 2880x576@50Hz */
+       /* 38 - 2880x576@50Hz */
        { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928,
                   3184, 3456, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1920x1080i@50Hz */
+       /* 39 - 1920x1080i@50Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952,
                   2120, 2304, 0, 1080, 1126, 1136, 1250, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
-       /* 1920x1080i@100Hz */
+       /* 40 - 1920x1080i@100Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
                   2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
-       /* 1280x720@100Hz */
+       /* 41 - 1280x720@100Hz */
        { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720,
                   1760, 1980, 0, 720, 725, 730, 750, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 720x576@100Hz */
+       /* 42 - 720x576@100Hz */
        { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732,
                   796, 864, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 720x576@100Hz */
+       /* 43 - 720x576@100Hz */
        { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732,
                   796, 864, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1440x576i@100Hz */
+       /* 44 - 1440x576i@100Hz */
        { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
                   1590, 1728, 0, 576, 580, 586, 625, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1440x576i@100Hz */
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
+                       DRM_MODE_FLAG_DBLCLK) },
+       /* 45 - 1440x576i@100Hz */
        { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
                   1590, 1728, 0, 576, 580, 586, 625, 0,
-                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1920x1080i@120Hz */
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
+                       DRM_MODE_FLAG_DBLCLK) },
+       /* 46 - 1920x1080i@120Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
                   2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
-       /* 1280x720@120Hz */
+       /* 47 - 1280x720@120Hz */
        { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390,
                   1430, 1650, 0, 720, 725, 730, 750, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 720x480@120Hz */
+       /* 48 - 720x480@120Hz */
        { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736,
                   798, 858, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 720x480@120Hz */
+       /* 49 - 720x480@120Hz */
        { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736,
                   798, 858, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1440x480i@120Hz */
+       /* 50 - 1440x480i@120Hz */
        { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
                   1602, 1716, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
-                       DRM_MODE_FLAG_INTERLACE) },
-       /* 1440x480i@120Hz */
+                       DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+       /* 51 - 1440x480i@120Hz */
        { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
                   1602, 1716, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
-                       DRM_MODE_FLAG_INTERLACE) },
-       /* 720x576@200Hz */
+                       DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+       /* 52 - 720x576@200Hz */
        { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732,
                   796, 864, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 720x576@200Hz */
+       /* 53 - 720x576@200Hz */
        { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732,
                   796, 864, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1440x576i@200Hz */
+       /* 54 - 1440x576i@200Hz */
        { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
                   1590, 1728, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
-                       DRM_MODE_FLAG_INTERLACE) },
-       /* 1440x576i@200Hz */
+                       DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+       /* 55 - 1440x576i@200Hz */
        { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
                   1590, 1728, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
-                       DRM_MODE_FLAG_INTERLACE) },
-       /* 720x480@240Hz */
+                       DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+       /* 56 - 720x480@240Hz */
        { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736,
                   798, 858, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 720x480@240Hz */
+       /* 57 - 720x480@240Hz */
        { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736,
                   798, 858, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-       /* 1440x480i@240 */
+       /* 58 - 1440x480i@240 */
        { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
                   1602, 1716, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
-                       DRM_MODE_FLAG_INTERLACE) },
-       /* 1440x480i@240 */
+                       DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+       /* 59 - 1440x480i@240 */
        { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
                   1602, 1716, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
-                       DRM_MODE_FLAG_INTERLACE) },
-       /* 1280x720@24Hz */
+                       DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+       /* 60 - 1280x720@24Hz */
        { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 59400, 1280, 3040,
                   3080, 3300, 0, 720, 725, 730, 750, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1280x720@25Hz */
+       /* 61 - 1280x720@25Hz */
        { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3700,
                   3740, 3960, 0, 720, 725, 730, 750, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1280x720@30Hz */
+       /* 62 - 1280x720@30Hz */
        { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040,
                   3080, 3300, 0, 720, 725, 730, 750, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1920x1080@120Hz */
+       /* 63 - 1920x1080@120Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008,
                   2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-       /* 1920x1080@100Hz */
+       /* 64 - 1920x1080@100Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448,
                   2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
 };
-static const int drm_num_cea_modes =
-       sizeof (edid_cea_modes) / sizeof (edid_cea_modes[0]);
+static const int drm_num_cea_modes = ARRAY_SIZE(edid_cea_modes);
index a0d6e89..6e19dd1 100644 (file)
@@ -1083,7 +1083,7 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
 
        /* try and find a 1024x768 mode on each connector */
        can_clone = true;
-       dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60);
+       dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60, false);
 
        for (i = 0; i < fb_helper->connector_count; i++) {
 
index 83114b5..fc6ded8 100644 (file)
@@ -272,8 +272,7 @@ again:
        spin_unlock(&file_priv->table_lock);
        if (ret == -EAGAIN)
                goto again;
-
-       if (ret != 0)
+       else if (ret)
                return ret;
 
        drm_gem_object_handle_reference(obj);
@@ -456,8 +455,7 @@ again:
 
                if (ret == -EAGAIN)
                        goto again;
-
-               if (ret != 0)
+               else if (ret)
                        goto err;
 
                /* Allocate a reference for the name table.  */
index aa454f8..ae1ccf1 100644 (file)
@@ -122,11 +122,10 @@ again:
        ret = idr_get_new_above(&drm_minors_idr, NULL,
                                base, &new_id);
        mutex_unlock(&dev->struct_mutex);
-       if (ret == -EAGAIN) {
+       if (ret == -EAGAIN)
                goto again;
-       } else if (ret) {
+       else if (ret)
                return ret;
-       }
 
        if (new_id >= limit) {
                idr_remove(&drm_minors_idr, new_id);
index a54cc73..62f9b73 100644 (file)
@@ -49,6 +49,9 @@ static void cdv_disable_vga(struct drm_device *dev)
 static int cdv_output_init(struct drm_device *dev)
 {
        struct drm_psb_private *dev_priv = dev->dev_private;
+
+       drm_mode_create_scaling_mode_property(dev);
+
        cdv_disable_vga(dev);
 
        cdv_intel_crt_init(dev, &dev_priv->mode_dev);
@@ -238,6 +241,18 @@ static void cdv_init_pm(struct drm_device *dev)
        dev_err(dev->dev, "GPU: power management timed out.\n");
 }
 
+static void cdv_errata(struct drm_device *dev)
+{
+       /* Disable bonus launch.
+        *      CPU and GPU competes for memory and display misses updates and flickers.
+        *      Worst with dual core, dual displays.
+        *
+        *      Fixes were done to Win 7 gfx driver to disable a feature called Bonus
+        *      Launch to work around the issue, by degrading performance.
+        */
+        CDV_MSG_WRITE32(3, 0x30, 0x08027108);
+}
+
 /**
  *     cdv_save_display_registers      -       save registers lost on suspend
  *     @dev: our DRM device
@@ -355,7 +370,7 @@ static int cdv_restore_display_registers(struct drm_device *dev)
        REG_WRITE(PSB_INT_MASK_R, regs->cdv.saveIMR);
 
        /* Fix arbitration bug */
-       CDV_MSG_WRITE32(3, 0x30, 0x08027108);
+       cdv_errata(dev);
 
        drm_mode_config_reset(dev);
 
@@ -447,13 +462,48 @@ static void cdv_get_core_freq(struct drm_device *dev)
        }
 }
 
+static void cdv_hotplug_work_func(struct work_struct *work)
+{
+        struct drm_psb_private *dev_priv = container_of(work, struct drm_psb_private,
+                                                       hotplug_work);                 
+        struct drm_device *dev = dev_priv->dev;
+
+        /* Just fire off a uevent and let userspace tell us what to do */
+        drm_helper_hpd_irq_event(dev);
+}                       
+
+/* The core driver has received a hotplug IRQ. We are in IRQ context
+   so extract the needed information and kick off queued processing */
+   
+static int cdv_hotplug_event(struct drm_device *dev)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       schedule_work(&dev_priv->hotplug_work);
+       REG_WRITE(PORT_HOTPLUG_STAT, REG_READ(PORT_HOTPLUG_STAT));
+       return 1;
+}
+
+static void cdv_hotplug_enable(struct drm_device *dev, bool on)
+{
+       if (on) {
+               u32 hotplug = REG_READ(PORT_HOTPLUG_EN);
+               hotplug |= HDMIB_HOTPLUG_INT_EN | HDMIC_HOTPLUG_INT_EN |
+                          HDMID_HOTPLUG_INT_EN | CRT_HOTPLUG_INT_EN;
+               REG_WRITE(PORT_HOTPLUG_EN, hotplug);
+       }  else {
+               REG_WRITE(PORT_HOTPLUG_EN, 0);
+               REG_WRITE(PORT_HOTPLUG_STAT, REG_READ(PORT_HOTPLUG_STAT));
+       }       
+}
+
 static int cdv_chip_setup(struct drm_device *dev)
 {
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       INIT_WORK(&dev_priv->hotplug_work, cdv_hotplug_work_func);
        cdv_get_core_freq(dev);
        gma_intel_opregion_init(dev);
        psb_intel_init_bios(dev);
-       REG_WRITE(PORT_HOTPLUG_EN, 0);
-       REG_WRITE(PORT_HOTPLUG_STAT, REG_READ(PORT_HOTPLUG_STAT));
+       cdv_hotplug_enable(dev, false);
        return 0;
 }
 
@@ -464,13 +514,18 @@ const struct psb_ops cdv_chip_ops = {
        .accel_2d = 0,
        .pipes = 2,
        .crtcs = 2,
+       .hdmi_mask = (1 << 0) | (1 << 1),
+       .lvds_mask = (1 << 1),
        .sgx_offset = MRST_SGX_OFFSET,
        .chip_setup = cdv_chip_setup,
+       .errata = cdv_errata,
 
        .crtc_helper = &cdv_intel_helper_funcs,
        .crtc_funcs = &cdv_intel_crtc_funcs,
 
        .output_init = cdv_output_init,
+       .hotplug = cdv_hotplug_event,
+       .hotplug_enable = cdv_hotplug_enable,
 
 #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
        .backlight_init = cdv_backlight_init,
index a71a6cd..1874220 100644 (file)
@@ -67,8 +67,6 @@ static void cdv_intel_crt_dpms(struct drm_encoder *encoder, int mode)
 static int cdv_intel_crt_mode_valid(struct drm_connector *connector,
                                struct drm_display_mode *mode)
 {
-       struct drm_psb_private *dev_priv = connector->dev->dev_private;
-       int max_clock = 0;
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
                return MODE_NO_DBLESCAN;
 
@@ -77,18 +75,9 @@ static int cdv_intel_crt_mode_valid(struct drm_connector *connector,
                return MODE_CLOCK_LOW;
 
        /* The max clock for CDV is 355 instead of 400 */
-       max_clock = 355000;
-       if (mode->clock > max_clock)
+       if (mode->clock > 355000)
                return MODE_CLOCK_HIGH;
 
-       if (mode->hdisplay > 1680 || mode->vdisplay > 1050)
-               return MODE_PANEL;
-
-       /* We assume worst case scenario of 32 bpp here, since we don't know */
-       if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) >
-           dev_priv->vram_stolen_size)
-               return MODE_MEM;
-
        return MODE_OK;
 }
 
@@ -156,13 +145,7 @@ static bool cdv_intel_crt_detect_hotplug(struct drm_connector *connector,
        struct drm_device *dev = connector->dev;
        u32 hotplug_en;
        int i, tries = 0, ret = false;
-       u32 adpa_orig;
-
-       /* disable the DAC when doing the hotplug detection */
-
-       adpa_orig = REG_READ(ADPA);
-
-       REG_WRITE(ADPA, adpa_orig & ~(ADPA_DAC_ENABLE));
+       u32 orig;
 
        /*
         * On a CDV thep, CRT detect sequence need to be done twice
@@ -170,7 +153,7 @@ static bool cdv_intel_crt_detect_hotplug(struct drm_connector *connector,
         */
        tries = 2;
 
-       hotplug_en = REG_READ(PORT_HOTPLUG_EN);
+       orig = hotplug_en = REG_READ(PORT_HOTPLUG_EN);
        hotplug_en &= ~(CRT_HOTPLUG_DETECT_MASK);
        hotplug_en |= CRT_HOTPLUG_FORCE_DETECT;
 
@@ -195,8 +178,11 @@ static bool cdv_intel_crt_detect_hotplug(struct drm_connector *connector,
            CRT_HOTPLUG_MONITOR_NONE)
                ret = true;
 
-       /* Restore the saved ADPA */
-       REG_WRITE(ADPA, adpa_orig);
+        /* clear the interrupt we just generated, if any */
+       REG_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS);
+
+       /* and put the bits back */
+       REG_WRITE(PORT_HOTPLUG_EN, orig);
        return ret;
 }
 
index be84559..2fab778 100644 (file)
@@ -216,7 +216,7 @@ static void cdv_sb_reset(struct drm_device *dev)
  */
 static int
 cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
-                              struct cdv_intel_clock_t *clock)
+                              struct cdv_intel_clock_t *clock, bool is_lvds)
 {
        struct psb_intel_crtc *psb_crtc =
                                to_psb_intel_crtc(crtc);
@@ -224,14 +224,15 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
        u32 m, n_vco, p;
        int ret = 0;
        int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
+       int ref_sfr = (pipe == 0) ? SB_REF_DPLLA : SB_REF_DPLLB;
        u32 ref_value;
+       u32 lane_reg, lane_value;
 
        cdv_sb_reset(dev);
 
-       if ((REG_READ(dpll_reg) & DPLL_SYNCLOCK_ENABLE) == 0) {
-               DRM_ERROR("Attempting to set DPLL with refclk disabled\n");
-               return -EBUSY;
-       }
+       REG_WRITE(dpll_reg, DPLL_SYNCLOCK_ENABLE | DPLL_VGA_MODE_DIS);
+
+       udelay(100);
 
        /* Follow the BIOS and write the REF/SFR Register. Hardcoded value */
        ref_value = 0x68A701;
@@ -241,6 +242,35 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
        /* We don't know what the other fields of these regs are, so
         * leave them in place.
         */
+       /* 
+        * The BIT 14:13 of 0x8010/0x8030 is used to select the ref clk
+        * for the pipe A/B. Display spec 1.06 has wrong definition.
+        * Correct definition is like below:
+        *
+        * refclka mean use clock from same PLL
+        *
+        * if DPLLA sets 01 and DPLLB sets 01, they use clock from their pll
+        *
+        * if DPLLA sets 01 and DPLLB sets 02, both use clk from DPLLA
+        *
+        */  
+       ret = cdv_sb_read(dev, ref_sfr, &ref_value);
+       if (ret)
+               return ret;
+       ref_value &= ~(REF_CLK_MASK);
+
+       /* use DPLL_A for pipeB on CRT/HDMI */
+       if (pipe == 1 && !is_lvds) {
+               DRM_DEBUG_KMS("use DPLLA for pipe B\n");
+               ref_value |= REF_CLK_DPLLA;
+       } else {
+               DRM_DEBUG_KMS("use their DPLL for pipe A/B\n");
+               ref_value |= REF_CLK_DPLL;
+       }
+       ret = cdv_sb_write(dev, ref_sfr, ref_value);
+       if (ret)
+               return ret;
+
        ret = cdv_sb_read(dev, SB_M(pipe), &m);
        if (ret)
                return ret;
@@ -307,36 +337,29 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
        if (ret)
                return ret;
 
-       /* always Program the Lane Register for the Pipe A*/
-       if (pipe == 0) {
-               /* Program the Lane0/1 for HDMI B */
-               u32 lane_reg, lane_value;
-
-               lane_reg = PSB_LANE0;
-               cdv_sb_read(dev, lane_reg, &lane_value);
-               lane_value &= ~(LANE_PLL_MASK);
-               lane_value |= LANE_PLL_ENABLE;
-               cdv_sb_write(dev, lane_reg, lane_value);
-
-               lane_reg = PSB_LANE1;
-               cdv_sb_read(dev, lane_reg, &lane_value);
-               lane_value &= ~(LANE_PLL_MASK);
-               lane_value |= LANE_PLL_ENABLE;
-               cdv_sb_write(dev, lane_reg, lane_value);
-
-               /* Program the Lane2/3 for HDMI C */
-               lane_reg = PSB_LANE2;
-               cdv_sb_read(dev, lane_reg, &lane_value);
-               lane_value &= ~(LANE_PLL_MASK);
-               lane_value |= LANE_PLL_ENABLE;
-               cdv_sb_write(dev, lane_reg, lane_value);
-
-               lane_reg = PSB_LANE3;
-               cdv_sb_read(dev, lane_reg, &lane_value);
-               lane_value &= ~(LANE_PLL_MASK);
-               lane_value |= LANE_PLL_ENABLE;
-               cdv_sb_write(dev, lane_reg, lane_value);
-       }
+       lane_reg = PSB_LANE0;
+       cdv_sb_read(dev, lane_reg, &lane_value);
+       lane_value &= ~(LANE_PLL_MASK);
+       lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
+       cdv_sb_write(dev, lane_reg, lane_value);
+
+       lane_reg = PSB_LANE1;
+       cdv_sb_read(dev, lane_reg, &lane_value);
+       lane_value &= ~(LANE_PLL_MASK);
+       lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
+       cdv_sb_write(dev, lane_reg, lane_value);
+
+       lane_reg = PSB_LANE2;
+       cdv_sb_read(dev, lane_reg, &lane_value);
+       lane_value &= ~(LANE_PLL_MASK);
+       lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
+       cdv_sb_write(dev, lane_reg, lane_value);
+
+       lane_reg = PSB_LANE3;
+       cdv_sb_read(dev, lane_reg, &lane_value);
+       lane_value &= ~(LANE_PLL_MASK);
+       lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
+       cdv_sb_write(dev, lane_reg, lane_value);
 
        return 0;
 }
@@ -553,6 +576,200 @@ psb_intel_pipe_set_base_exit:
        return ret;
 }
 
+#define                FIFO_PIPEA              (1 << 0)
+#define                FIFO_PIPEB              (1 << 1)
+
+static bool cdv_intel_pipe_enabled(struct drm_device *dev, int pipe)
+{
+       struct drm_crtc *crtc;
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       struct psb_intel_crtc *psb_intel_crtc = NULL;
+
+       crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+       psb_intel_crtc = to_psb_intel_crtc(crtc);
+
+       if (crtc->fb == NULL || !psb_intel_crtc->active)
+               return false;
+       return true;
+}
+
+static bool cdv_intel_single_pipe_active (struct drm_device *dev)
+{
+       uint32_t pipe_enabled = 0;
+
+       if (cdv_intel_pipe_enabled(dev, 0))
+               pipe_enabled |= FIFO_PIPEA;
+
+       if (cdv_intel_pipe_enabled(dev, 1))
+               pipe_enabled |= FIFO_PIPEB;
+
+
+       DRM_DEBUG_KMS("pipe enabled %x\n", pipe_enabled);
+
+       if (pipe_enabled == FIFO_PIPEA || pipe_enabled == FIFO_PIPEB)
+               return true;
+       else
+               return false;
+}
+
+static bool is_pipeb_lvds(struct drm_device *dev, struct drm_crtc *crtc)
+{
+       struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct drm_connector *connector;
+
+       if (psb_intel_crtc->pipe != 1)
+               return false;
+
+       list_for_each_entry(connector, &mode_config->connector_list, head) {
+               struct psb_intel_encoder *psb_intel_encoder =
+                                       psb_intel_attached_encoder(connector);
+
+               if (!connector->encoder
+                   || connector->encoder->crtc != crtc)
+                       continue;
+
+               if (psb_intel_encoder->type == INTEL_OUTPUT_LVDS)
+                       return true;
+       }
+
+       return false;
+}
+
+static void cdv_intel_disable_self_refresh (struct drm_device *dev)
+{
+       if (REG_READ(FW_BLC_SELF) & FW_BLC_SELF_EN) {
+
+               /* Disable self-refresh before adjust WM */
+               REG_WRITE(FW_BLC_SELF, (REG_READ(FW_BLC_SELF) & ~FW_BLC_SELF_EN));
+               REG_READ(FW_BLC_SELF);
+
+               cdv_intel_wait_for_vblank(dev);
+
+               /* Cedarview workaround to write ovelay plane, which force to leave
+                * MAX_FIFO state.
+                */
+               REG_WRITE(OV_OVADD, 0/*dev_priv->ovl_offset*/);
+               REG_READ(OV_OVADD);
+
+               cdv_intel_wait_for_vblank(dev);
+       }
+
+}
+
+static void cdv_intel_update_watermark (struct drm_device *dev, struct drm_crtc *crtc)
+{
+
+       if (cdv_intel_single_pipe_active(dev)) {
+               u32 fw;
+
+               fw = REG_READ(DSPFW1);
+               fw &= ~DSP_FIFO_SR_WM_MASK;
+               fw |= (0x7e << DSP_FIFO_SR_WM_SHIFT);
+               fw &= ~CURSOR_B_FIFO_WM_MASK;
+               fw |= (0x4 << CURSOR_B_FIFO_WM_SHIFT);
+               REG_WRITE(DSPFW1, fw);
+
+               fw = REG_READ(DSPFW2);
+               fw &= ~CURSOR_A_FIFO_WM_MASK;
+               fw |= (0x6 << CURSOR_A_FIFO_WM_SHIFT);
+               fw &= ~DSP_PLANE_C_FIFO_WM_MASK;
+               fw |= (0x8 << DSP_PLANE_C_FIFO_WM_SHIFT);
+               REG_WRITE(DSPFW2, fw);
+
+               REG_WRITE(DSPFW3, 0x36000000);
+
+               /* ignore FW4 */
+
+               if (is_pipeb_lvds(dev, crtc)) {
+                       REG_WRITE(DSPFW5, 0x00040330);
+               } else {
+                       fw = (3 << DSP_PLANE_B_FIFO_WM1_SHIFT) |
+                            (4 << DSP_PLANE_A_FIFO_WM1_SHIFT) |
+                            (3 << CURSOR_B_FIFO_WM1_SHIFT) |
+                            (4 << CURSOR_FIFO_SR_WM1_SHIFT);
+                       REG_WRITE(DSPFW5, fw);
+               }
+
+               REG_WRITE(DSPFW6, 0x10);
+
+               cdv_intel_wait_for_vblank(dev);
+
+               /* enable self-refresh for single pipe active */
+               REG_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
+               REG_READ(FW_BLC_SELF);
+               cdv_intel_wait_for_vblank(dev);
+
+       } else {
+
+               /* HW team suggested values... */
+               REG_WRITE(DSPFW1, 0x3f880808);
+               REG_WRITE(DSPFW2, 0x0b020202);
+               REG_WRITE(DSPFW3, 0x24000000);
+               REG_WRITE(DSPFW4, 0x08030202);
+               REG_WRITE(DSPFW5, 0x01010101);
+               REG_WRITE(DSPFW6, 0x1d0);
+
+               cdv_intel_wait_for_vblank(dev);
+
+               cdv_intel_disable_self_refresh(dev);
+       
+       }
+}
+
+/** Loads the palette/gamma unit for the CRTC with the prepared values */
+static void cdv_intel_crtc_load_lut(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_psb_private *dev_priv =
+                               (struct drm_psb_private *)dev->dev_private;
+       struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
+       int palreg = PALETTE_A;
+       int i;
+
+       /* The clocks have to be on to load the palette. */
+       if (!crtc->enabled)
+               return;
+
+       switch (psb_intel_crtc->pipe) {
+       case 0:
+               break;
+       case 1:
+               palreg = PALETTE_B;
+               break;
+       case 2:
+               palreg = PALETTE_C;
+               break;
+       default:
+               dev_err(dev->dev, "Illegal Pipe Number.\n");
+               return;
+       }
+
+       if (gma_power_begin(dev, false)) {
+               for (i = 0; i < 256; i++) {
+                       REG_WRITE(palreg + 4 * i,
+                                 ((psb_intel_crtc->lut_r[i] +
+                                 psb_intel_crtc->lut_adj[i]) << 16) |
+                                 ((psb_intel_crtc->lut_g[i] +
+                                 psb_intel_crtc->lut_adj[i]) << 8) |
+                                 (psb_intel_crtc->lut_b[i] +
+                                 psb_intel_crtc->lut_adj[i]));
+               }
+               gma_power_end(dev);
+       } else {
+               for (i = 0; i < 256; i++) {
+                       dev_priv->regs.psb.save_palette_a[i] =
+                                 ((psb_intel_crtc->lut_r[i] +
+                                 psb_intel_crtc->lut_adj[i]) << 16) |
+                                 ((psb_intel_crtc->lut_g[i] +
+                                 psb_intel_crtc->lut_adj[i]) << 8) |
+                                 (psb_intel_crtc->lut_b[i] +
+                                 psb_intel_crtc->lut_adj[i]);
+               }
+
+       }
+}
+
 /**
  * Sets the power management mode of the pipe and plane.
  *
@@ -568,15 +785,23 @@ static void cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
        int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
        int dspbase_reg = (pipe == 0) ? DSPABASE : DSPBBASE;
        int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
+       int pipestat_reg = (pipe == 0) ? PIPEASTAT : PIPEBSTAT;
        u32 temp;
 
        /* XXX: When our outputs are all unaware of DPMS modes other than off
         * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
         */
+       cdv_intel_disable_self_refresh(dev);
+
        switch (mode) {
        case DRM_MODE_DPMS_ON:
        case DRM_MODE_DPMS_STANDBY:
        case DRM_MODE_DPMS_SUSPEND:
+               if (psb_intel_crtc->active)
+                       return;
+
+               psb_intel_crtc->active = true;
+
                /* Enable the DPLL */
                temp = REG_READ(dpll_reg);
                if ((temp & DPLL_VCO_ENABLE) == 0) {
@@ -611,13 +836,26 @@ static void cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
                if ((temp & PIPEACONF_ENABLE) == 0)
                        REG_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
 
-               psb_intel_crtc_load_lut(crtc);
+               temp = REG_READ(pipestat_reg);
+               temp &= ~(0xFFFF);
+               temp |= PIPE_FIFO_UNDERRUN;
+               REG_WRITE(pipestat_reg, temp);
+               REG_READ(pipestat_reg);
+
+               cdv_intel_update_watermark(dev, crtc);
+               cdv_intel_crtc_load_lut(crtc);
 
                /* Give the overlay scaler a chance to enable
                 * if it's on this pipe */
                /* psb_intel_crtc_dpms_video(crtc, true); TODO */
+               psb_intel_crtc->crtc_enable = true;
                break;
        case DRM_MODE_DPMS_OFF:
+               if (!psb_intel_crtc->active)
+                       return;
+
+               psb_intel_crtc->active = false;
+
                /* Give the overlay scaler a chance to disable
                 * if it's on this pipe */
                /* psb_intel_crtc_dpms_video(crtc, FALSE); TODO */
@@ -627,6 +865,7 @@ static void cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
 
                /* Jim Bish - changed pipe/plane here as well. */
 
+               drm_vblank_off(dev, pipe);
                /* Wait for vblank for the disable to take effect */
                cdv_intel_wait_for_vblank(dev);
 
@@ -660,6 +899,8 @@ static void cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
 
                /* Wait for the clocks to turn off. */
                udelay(150);
+               cdv_intel_update_watermark(dev, crtc);
+               psb_intel_crtc->crtc_enable = false;
                break;
        }
        /*Set FIFO Watermarks*/
@@ -709,6 +950,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
                               struct drm_framebuffer *old_fb)
 {
        struct drm_device *dev = crtc->dev;
+       struct drm_psb_private *dev_priv = dev->dev_private;
        struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
        int pipe = psb_intel_crtc->pipe;
        int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
@@ -757,13 +999,18 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
                }
        }
 
-       refclk = 96000;
-
-       /* Hack selection about ref clk for CRT */
-       /* Select 27MHz as the reference clk for HDMI */
-       if (is_crt || is_hdmi)
+       if (dev_priv->dplla_96mhz)
+               /* low-end sku, 96/100 mhz */
+               refclk = 96000;
+       else
+               /* high-end sku, 27/100 mhz */
                refclk = 27000;
 
+       if (is_lvds && dev_priv->lvds_use_ssc) {
+               refclk = dev_priv->lvds_ssc_freq * 1000;
+               DRM_DEBUG_KMS("Use SSC reference clock %d Mhz\n", dev_priv->lvds_ssc_freq);
+       }
+
        drm_mode_debug_printmodeline(adjusted_mode);
 
        ok = cdv_intel_find_best_PLL(crtc, adjusted_mode->clock, refclk,
@@ -779,14 +1026,13 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
 /*     dpll |= PLL_REF_INPUT_TVCLKINBC; */
                dpll |= 3;
        }
-               dpll |= PLL_REF_INPUT_DREFCLK;
+/*             dpll |= PLL_REF_INPUT_DREFCLK; */
 
        dpll |= DPLL_SYNCLOCK_ENABLE;
-       dpll |= DPLL_VGA_MODE_DIS;
-       if (is_lvds)
+/*     if (is_lvds)
                dpll |= DPLLB_MODE_LVDS;
        else
-               dpll |= DPLLB_MODE_DAC_SERIAL;
+               dpll |= DPLLB_MODE_DAC_SERIAL; */
        /* dpll |= (2 << 11); */
 
        /* setup pipeconf */
@@ -806,7 +1052,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
        REG_WRITE(dpll_reg, dpll | DPLL_VGA_MODE_DIS | DPLL_SYNCLOCK_ENABLE);
        REG_READ(dpll_reg);
 
-       cdv_dpll_set_clock_cdv(dev, crtc, &clock);
+       cdv_dpll_set_clock_cdv(dev, crtc, &clock, is_lvds);
 
        udelay(150);
 
@@ -903,58 +1149,6 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
        return 0;
 }
 
-/** Loads the palette/gamma unit for the CRTC with the prepared values */
-static void cdv_intel_crtc_load_lut(struct drm_crtc *crtc)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_psb_private *dev_priv =
-                               (struct drm_psb_private *)dev->dev_private;
-       struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
-       int palreg = PALETTE_A;
-       int i;
-
-       /* The clocks have to be on to load the palette. */
-       if (!crtc->enabled)
-               return;
-
-       switch (psb_intel_crtc->pipe) {
-       case 0:
-               break;
-       case 1:
-               palreg = PALETTE_B;
-               break;
-       case 2:
-               palreg = PALETTE_C;
-               break;
-       default:
-               dev_err(dev->dev, "Illegal Pipe Number.\n");
-               return;
-       }
-
-       if (gma_power_begin(dev, false)) {
-               for (i = 0; i < 256; i++) {
-                       REG_WRITE(palreg + 4 * i,
-                                 ((psb_intel_crtc->lut_r[i] +
-                                 psb_intel_crtc->lut_adj[i]) << 16) |
-                                 ((psb_intel_crtc->lut_g[i] +
-                                 psb_intel_crtc->lut_adj[i]) << 8) |
-                                 (psb_intel_crtc->lut_b[i] +
-                                 psb_intel_crtc->lut_adj[i]));
-               }
-               gma_power_end(dev);
-       } else {
-               for (i = 0; i < 256; i++) {
-                       dev_priv->regs.psb.save_palette_a[i] =
-                                 ((psb_intel_crtc->lut_r[i] +
-                                 psb_intel_crtc->lut_adj[i]) << 16) |
-                                 ((psb_intel_crtc->lut_g[i] +
-                                 psb_intel_crtc->lut_adj[i]) << 8) |
-                                 (psb_intel_crtc->lut_b[i] +
-                                 psb_intel_crtc->lut_adj[i]);
-               }
-
-       }
-}
 
 /**
  * Save HW states of giving crtc
index 8d52695..88b59d4 100644 (file)
@@ -242,8 +242,6 @@ static int cdv_hdmi_get_modes(struct drm_connector *connector)
 static int cdv_hdmi_mode_valid(struct drm_connector *connector,
                                 struct drm_display_mode *mode)
 {
-       struct drm_psb_private *dev_priv = connector->dev->dev_private;
-
        if (mode->clock > 165000)
                return MODE_CLOCK_HIGH;
        if (mode->clock < 20000)
@@ -257,11 +255,6 @@ static int cdv_hdmi_mode_valid(struct drm_connector *connector,
        if (mode->flags & DRM_MODE_FLAG_INTERLACE)
                return MODE_NO_INTERLACE;
 
-       /* We assume worst case scenario of 32 bpp here, since we don't know */
-       if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) >
-           dev_priv->vram_stolen_size)
-               return MODE_MEM;
-
        return MODE_OK;
 }
 
index 8359c1a..44a8353 100644 (file)
@@ -356,6 +356,8 @@ static void cdv_intel_lvds_mode_set(struct drm_encoder *encoder,
 {
        struct drm_device *dev = encoder->dev;
        struct drm_psb_private *dev_priv = dev->dev_private;
+       struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(
+                                                       encoder->crtc);
        u32 pfit_control;
 
        /*
@@ -377,6 +379,8 @@ static void cdv_intel_lvds_mode_set(struct drm_encoder *encoder,
        else
                pfit_control = 0;
 
+       pfit_control |= psb_intel_crtc->pipe << PFIT_PIPE_SHIFT;
+
        if (dev_priv->lvds_dither)
                pfit_control |= PANEL_8TO6_DITHER_ENABLE;
 
@@ -556,6 +560,56 @@ const struct drm_encoder_funcs cdv_intel_lvds_enc_funcs = {
        .destroy = cdv_intel_lvds_enc_destroy,
 };
 
+/*
+ * Enumerate the child dev array parsed from VBT to check whether
+ * the LVDS is present.
+ * If it is present, return 1.
+ * If it is not present, return false.
+ * If no child dev is parsed from VBT, it assumes that the LVDS is present.
+ */
+static bool lvds_is_present_in_vbt(struct drm_device *dev,
+                                  u8 *i2c_pin)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       int i;
+
+       if (!dev_priv->child_dev_num)
+               return true;
+
+       for (i = 0; i < dev_priv->child_dev_num; i++) {
+               struct child_device_config *child = dev_priv->child_dev + i;
+
+               /* If the device type is not LFP, continue.
+                * We have to check both the new identifiers as well as the
+                * old for compatibility with some BIOSes.
+                */
+               if (child->device_type != DEVICE_TYPE_INT_LFP &&
+                   child->device_type != DEVICE_TYPE_LFP)
+                       continue;
+
+               if (child->i2c_pin)
+                   *i2c_pin = child->i2c_pin;
+
+               /* However, we cannot trust the BIOS writers to populate
+                * the VBT correctly.  Since LVDS requires additional
+                * information from AIM blocks, a non-zero addin offset is
+                * a good indicator that the LVDS is actually present.
+                */
+               if (child->addin_offset)
+                       return true;
+
+               /* But even then some BIOS writers perform some black magic
+                * and instantiate the device without reference to any
+                * additional data.  Trust that if the VBT was written into
+                * the OpRegion then they have validated the LVDS's existence.
+                */
+               if (dev_priv->opregion.vbt)
+                       return true;
+       }
+
+       return false;
+}
+
 /**
  * cdv_intel_lvds_init - setup LVDS connectors on this device
  * @dev: drm device
@@ -576,6 +630,13 @@ void cdv_intel_lvds_init(struct drm_device *dev,
        struct drm_psb_private *dev_priv = dev->dev_private;
        u32 lvds;
        int pipe;
+       u8 pin;
+
+       pin = GMBUS_PORT_PANEL;
+       if (!lvds_is_present_in_vbt(dev, &pin)) {
+               DRM_DEBUG_KMS("LVDS is not present in VBT\n");
+               return;
+       }
 
        psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder),
                                    GFP_KERNEL);
@@ -710,6 +771,19 @@ void cdv_intel_lvds_init(struct drm_device *dev,
                goto failed_find;
        }
 
+       /* setup PWM */
+       {
+               u32 pwm;
+
+               pwm = REG_READ(BLC_PWM_CTL2);
+               if (pipe == 1)
+                       pwm |= PWM_PIPE_B;
+               else
+                       pwm &= ~PWM_PIPE_B;
+               pwm |= PWM_ENABLE;
+               REG_WRITE(BLC_PWM_CTL2, pwm);
+       }
+
 out:
        drm_sysfs_connector_add(connector);
        return;
index 8ea202f..c9fe4bd 100644 (file)
@@ -543,9 +543,25 @@ static int psbfb_probe(struct drm_fb_helper *helper,
                                struct drm_fb_helper_surface_size *sizes)
 {
        struct psb_fbdev *psb_fbdev = (struct psb_fbdev *)helper;
+       struct drm_device *dev = psb_fbdev->psb_fb_helper.dev;
+       struct drm_psb_private *dev_priv = dev->dev_private;
        int new_fb = 0;
+       int bytespp;
        int ret;
 
+       bytespp = sizes->surface_bpp / 8;
+       if (bytespp == 3)       /* no 24bit packed */
+               bytespp = 4;
+
+       /* If the mode will not fit in 32bit then switch to 16bit to get
+          a console on full resolution. The X mode setting server will
+          allocate its own 32bit GEM framebuffer */
+       if (ALIGN(sizes->fb_width * bytespp, 64) * sizes->fb_height >
+                       dev_priv->vram_stolen_size) {
+                sizes->surface_bpp = 16;
+                sizes->surface_depth = 16;
+        }
+
        if (!helper->fb) {
                ret = psbfb_create(psb_fbdev, sizes);
                if (ret)
@@ -732,10 +748,7 @@ static void psb_setup_outputs(struct drm_device *dev)
                        clone_mask = (1 << INTEL_OUTPUT_SDVO);
                        break;
                case INTEL_OUTPUT_LVDS:
-                       if (IS_MRST(dev))
-                               crtc_mask = (1 << 0);
-                       else
-                               crtc_mask = (1 << 1);
+                       crtc_mask = dev_priv->ops->lvds_mask;
                        clone_mask = (1 << INTEL_OUTPUT_LVDS);
                        break;
                case INTEL_OUTPUT_MIPI:
@@ -747,10 +760,7 @@ static void psb_setup_outputs(struct drm_device *dev)
                        clone_mask = (1 << INTEL_OUTPUT_MIPI2);
                        break;
                case INTEL_OUTPUT_HDMI:
-                       if (IS_MFLD(dev))
-                               crtc_mask = (1 << 1);
-                       else    
-                               crtc_mask = (1 << 0);
+                       crtc_mask = dev_priv->ops->hdmi_mask;
                        clone_mask = (1 << INTEL_OUTPUT_HDMI);
                        break;
                }
@@ -786,6 +796,9 @@ void psb_modeset_init(struct drm_device *dev)
        dev->mode_config.max_height = 2048;
 
        psb_setup_outputs(dev);
+
+       if (dev_priv->ops->errata)
+               dev_priv->ops->errata(dev);
 }
 
 void psb_modeset_cleanup(struct drm_device *dev)
index 9fbb868..fc7d144 100644 (file)
@@ -124,6 +124,8 @@ static int psb_gem_create(struct drm_file *file,
                dev_err(dev->dev, "GEM init failed for %lld\n", size);
                return -ENOMEM;
        }
+       /* Limit the object to 32bit mappings */
+       mapping_set_gfp_mask(r->gem.filp->f_mapping, GFP_KERNEL | __GFP_DMA32);
        /* Give the object a handle so we can carry it more easily */
        ret = drm_gem_handle_create(file, &r->gem, &handle);
        if (ret) {
index c6465b4..54e5c9e 100644 (file)
@@ -39,6 +39,10 @@ static inline uint32_t psb_gtt_mask_pte(uint32_t pfn, int type)
 {
        uint32_t mask = PSB_PTE_VALID;
 
+       /* Ensure we explode rather than put an invalid low mapping of
+          a high mapping page into the gtt */
+       BUG_ON(pfn & ~(0xFFFFFFFF >> PAGE_SHIFT));
+
        if (type & PSB_MMU_CACHED_MEMORY)
                mask |= PSB_PTE_CACHED;
        if (type & PSB_MMU_RO_MEMORY)
@@ -93,7 +97,7 @@ static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r)
        pages = r->pages;
 
        /* Make sure changes are visible to the GPU */
-       set_pages_array_uc(pages, r->npage);
+       set_pages_array_wc(pages, r->npage);
 
        /* Write our page entries into the GTT itself */
        for (i = r->roll; i < r->npage; i++) {
index d4d0c5b..479e449 100644 (file)
@@ -26,6 +26,8 @@
 #include "psb_intel_reg.h"
 #include "intel_bios.h"
 
+#define        SLAVE_ADDR1     0x70
+#define        SLAVE_ADDR2     0x72
 
 static void *find_section(struct bdb_header *bdb, int section_id)
 {
@@ -52,6 +54,16 @@ static void *find_section(struct bdb_header *bdb, int section_id)
        return NULL;
 }
 
+static u16
+get_blocksize(void *p)
+{
+       u16 *block_ptr, block_size;
+
+       block_ptr = (u16 *)((char *)p - 2);
+       block_size = *block_ptr;
+       return block_size;
+}
+
 static void fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
                        struct lvds_dvo_timing *dvo_timing)
 {
@@ -75,6 +87,16 @@ static void fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
        panel_fixed_mode->clock = dvo_timing->clock * 10;
        panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED;
 
+       if (dvo_timing->hsync_positive)
+               panel_fixed_mode->flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               panel_fixed_mode->flags |= DRM_MODE_FLAG_NHSYNC;
+
+       if (dvo_timing->vsync_positive)
+               panel_fixed_mode->flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC;
+
        /* Some VBTs have bogus h/vtotal values */
        if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal)
                panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1;
@@ -217,6 +239,180 @@ static void parse_general_features(struct drm_psb_private *dev_priv,
        }
 }
 
+static void
+parse_sdvo_device_mapping(struct drm_psb_private *dev_priv,
+                         struct bdb_header *bdb)
+{
+       struct sdvo_device_mapping *p_mapping;
+       struct bdb_general_definitions *p_defs;
+       struct child_device_config *p_child;
+       int i, child_device_num, count;
+       u16     block_size;
+
+       p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
+       if (!p_defs) {
+               DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n");
+               return;
+       }
+       /* judge whether the size of child device meets the requirements.
+        * If the child device size obtained from general definition block
+        * is different with sizeof(struct child_device_config), skip the
+        * parsing of sdvo device info
+        */
+       if (p_defs->child_dev_size != sizeof(*p_child)) {
+               /* different child dev size . Ignore it */
+               DRM_DEBUG_KMS("different child size is found. Invalid.\n");
+               return;
+       }
+       /* get the block size of general definitions */
+       block_size = get_blocksize(p_defs);
+       /* get the number of child device */
+       child_device_num = (block_size - sizeof(*p_defs)) /
+                               sizeof(*p_child);
+       count = 0;
+       for (i = 0; i < child_device_num; i++) {
+               p_child = &(p_defs->devices[i]);
+               if (!p_child->device_type) {
+                       /* skip the device block if device type is invalid */
+                       continue;
+               }
+               if (p_child->slave_addr != SLAVE_ADDR1 &&
+                       p_child->slave_addr != SLAVE_ADDR2) {
+                       /*
+                        * If the slave address is neither 0x70 nor 0x72,
+                        * it is not a SDVO device. Skip it.
+                        */
+                       continue;
+               }
+               if (p_child->dvo_port != DEVICE_PORT_DVOB &&
+                       p_child->dvo_port != DEVICE_PORT_DVOC) {
+                       /* skip the incorrect SDVO port */
+                       DRM_DEBUG_KMS("Incorrect SDVO port. Skip it\n");
+                       continue;
+               }
+               DRM_DEBUG_KMS("the SDVO device with slave addr %2x is found on"
+                               " %s port\n",
+                               p_child->slave_addr,
+                               (p_child->dvo_port == DEVICE_PORT_DVOB) ?
+                                       "SDVOB" : "SDVOC");
+               p_mapping = &(dev_priv->sdvo_mappings[p_child->dvo_port - 1]);
+               if (!p_mapping->initialized) {
+                       p_mapping->dvo_port = p_child->dvo_port;
+                       p_mapping->slave_addr = p_child->slave_addr;
+                       p_mapping->dvo_wiring = p_child->dvo_wiring;
+                       p_mapping->ddc_pin = p_child->ddc_pin;
+                       p_mapping->i2c_pin = p_child->i2c_pin;
+                       p_mapping->initialized = 1;
+                       DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d\n",
+                                     p_mapping->dvo_port,
+                                     p_mapping->slave_addr,
+                                     p_mapping->dvo_wiring,
+                                     p_mapping->ddc_pin,
+                                     p_mapping->i2c_pin);
+               } else {
+                       DRM_DEBUG_KMS("Maybe one SDVO port is shared by "
+                                        "two SDVO device.\n");
+               }
+               if (p_child->slave2_addr) {
+                       /* Maybe this is a SDVO device with multiple inputs */
+                       /* And the mapping info is not added */
+                       DRM_DEBUG_KMS("there exists the slave2_addr. Maybe this"
+                               " is a SDVO device with multiple inputs.\n");
+               }
+               count++;
+       }
+
+       if (!count) {
+               /* No SDVO device info is found */
+               DRM_DEBUG_KMS("No SDVO device info is found in VBT\n");
+       }
+       return;
+}
+
+
+static void
+parse_driver_features(struct drm_psb_private *dev_priv,
+                     struct bdb_header *bdb)
+{
+       struct bdb_driver_features *driver;
+
+       driver = find_section(bdb, BDB_DRIVER_FEATURES);
+       if (!driver)
+               return;
+
+       /* This bit means to use 96Mhz for DPLL_A or not */
+       if (driver->primary_lfp_id)
+               dev_priv->dplla_96mhz = true;
+       else
+               dev_priv->dplla_96mhz = false;
+}
+
+static void
+parse_device_mapping(struct drm_psb_private *dev_priv,
+                      struct bdb_header *bdb)
+{
+       struct bdb_general_definitions *p_defs;
+       struct child_device_config *p_child, *child_dev_ptr;
+       int i, child_device_num, count;
+       u16     block_size;
+
+       p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
+       if (!p_defs) {
+               DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n");
+               return;
+       }
+       /* judge whether the size of child device meets the requirements.
+        * If the child device size obtained from general definition block
+        * is different with sizeof(struct child_device_config), skip the
+        * parsing of sdvo device info
+        */
+       if (p_defs->child_dev_size != sizeof(*p_child)) {
+               /* different child dev size . Ignore it */
+               DRM_DEBUG_KMS("different child size is found. Invalid.\n");
+               return;
+       }
+       /* get the block size of general definitions */
+       block_size = get_blocksize(p_defs);
+       /* get the number of child device */
+       child_device_num = (block_size - sizeof(*p_defs)) /
+                               sizeof(*p_child);
+       count = 0;
+       /* get the number of child devices that are present */
+       for (i = 0; i < child_device_num; i++) {
+               p_child = &(p_defs->devices[i]);
+               if (!p_child->device_type) {
+                       /* skip the device block if device type is invalid */
+                       continue;
+               }
+               count++;
+       }
+       if (!count) {
+               DRM_DEBUG_KMS("no child dev is parsed from VBT\n");
+               return;
+       }
+       dev_priv->child_dev = kcalloc(count, sizeof(*p_child), GFP_KERNEL);
+       if (!dev_priv->child_dev) {
+               DRM_DEBUG_KMS("No memory space for child devices\n");
+               return;
+       }
+
+       dev_priv->child_dev_num = count;
+       count = 0;
+       for (i = 0; i < child_device_num; i++) {
+               p_child = &(p_defs->devices[i]);
+               if (!p_child->device_type) {
+                       /* skip the device block if device type is invalid */
+                       continue;
+               }
+               child_dev_ptr = dev_priv->child_dev + count;
+               count++;
+               memcpy((void *)child_dev_ptr, (void *)p_child,
+                                       sizeof(*p_child));
+       }
+       return;
+}
+
+
 /**
  * psb_intel_init_bios - initialize VBIOS settings & find VBT
  * @dev: DRM device
@@ -236,38 +432,54 @@ bool psb_intel_init_bios(struct drm_device *dev)
        struct drm_psb_private *dev_priv = dev->dev_private;
        struct pci_dev *pdev = dev->pdev;
        struct vbt_header *vbt = NULL;
-       struct bdb_header *bdb;
-       u8 __iomem *bios;
+       struct bdb_header *bdb = NULL;
+       u8 __iomem *bios = NULL;
        size_t size;
        int i;
 
-       bios = pci_map_rom(pdev, &size);
-       if (!bios)
-               return -1;
+       /* XXX Should this validation be moved to intel_opregion.c? */
+       if (dev_priv->opregion.vbt) {
+               struct vbt_header *vbt = dev_priv->opregion.vbt;
+               if (memcmp(vbt->signature, "$VBT", 4) == 0) {
+                       DRM_DEBUG_KMS("Using VBT from OpRegion: %20s\n",
+                                        vbt->signature);
+                       bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset);
+               } else
+                       dev_priv->opregion.vbt = NULL;
+       }
 
-       /* Scour memory looking for the VBT signature */
-       for (i = 0; i + 4 < size; i++) {
-               if (!memcmp(bios + i, "$VBT", 4)) {
-                       vbt = (struct vbt_header *)(bios + i);
-                       break;
+       if (bdb == NULL) {
+               bios = pci_map_rom(pdev, &size);
+               if (!bios)
+                       return -1;
+
+               /* Scour memory looking for the VBT signature */
+               for (i = 0; i + 4 < size; i++) {
+                       if (!memcmp(bios + i, "$VBT", 4)) {
+                               vbt = (struct vbt_header *)(bios + i);
+                               break;
+                       }
                }
-       }
 
-       if (!vbt) {
-               dev_err(dev->dev, "VBT signature missing\n");
-               pci_unmap_rom(pdev, bios);
-               return -1;
+               if (!vbt) {
+                       dev_err(dev->dev, "VBT signature missing\n");
+                       pci_unmap_rom(pdev, bios);
+                       return -1;
+               }
+               bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
        }
 
-       bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
-
-       /* Grab useful general definitions */
+       /* Grab useful general dxefinitions */
        parse_general_features(dev_priv, bdb);
+       parse_driver_features(dev_priv, bdb);
        parse_lfp_panel_data(dev_priv, bdb);
        parse_sdvo_panel_data(dev_priv, bdb);
+       parse_sdvo_device_mapping(dev_priv, bdb);
+       parse_device_mapping(dev_priv, bdb);
        parse_backlight_data(dev_priv, bdb);
 
-       pci_unmap_rom(pdev, bios);
+       if (bios)
+               pci_unmap_rom(pdev, bios);
 
        return 0;
 }
index 70f1bf0..0a73866 100644 (file)
@@ -127,9 +127,93 @@ struct bdb_general_features {
        /* bits 5 */
        u8 int_crt_support:1;
        u8 int_tv_support:1;
-       u8 rsvd11:6; /* finish byte */
+       u8 int_efp_support:1;
+       u8 dp_ssc_enb:1;        /* PCH attached eDP supports SSC */
+       u8 dp_ssc_freq:1;       /* SSC freq for PCH attached eDP */
+       u8 rsvd11:3; /* finish byte */
 } __attribute__((packed));
 
+/* pre-915 */
+#define GPIO_PIN_DVI_LVDS      0x03 /* "DVI/LVDS DDC GPIO pins" */
+#define GPIO_PIN_ADD_I2C       0x05 /* "ADDCARD I2C GPIO pins" */
+#define GPIO_PIN_ADD_DDC       0x04 /* "ADDCARD DDC GPIO pins" */
+#define GPIO_PIN_ADD_DDC_I2C   0x06 /* "ADDCARD DDC/I2C GPIO pins" */
+
+/* Pre 915 */
+#define DEVICE_TYPE_NONE       0x00
+#define DEVICE_TYPE_CRT                0x01
+#define DEVICE_TYPE_TV         0x09
+#define DEVICE_TYPE_EFP                0x12
+#define DEVICE_TYPE_LFP                0x22
+/* On 915+ */
+#define DEVICE_TYPE_CRT_DPMS           0x6001
+#define DEVICE_TYPE_CRT_DPMS_HOTPLUG   0x4001
+#define DEVICE_TYPE_TV_COMPOSITE       0x0209
+#define DEVICE_TYPE_TV_MACROVISION     0x0289
+#define DEVICE_TYPE_TV_RF_COMPOSITE    0x020c
+#define DEVICE_TYPE_TV_SVIDEO_COMPOSITE        0x0609
+#define DEVICE_TYPE_TV_SCART           0x0209
+#define DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR 0x6009
+#define DEVICE_TYPE_EFP_HOTPLUG_PWR    0x6012
+#define DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR        0x6052
+#define DEVICE_TYPE_EFP_DVI_I          0x6053
+#define DEVICE_TYPE_EFP_DVI_D_DUAL     0x6152
+#define DEVICE_TYPE_EFP_DVI_D_HDCP     0x60d2
+#define DEVICE_TYPE_OPENLDI_HOTPLUG_PWR        0x6062
+#define DEVICE_TYPE_OPENLDI_DUALPIX    0x6162
+#define DEVICE_TYPE_LFP_PANELLINK      0x5012
+#define DEVICE_TYPE_LFP_CMOS_PWR       0x5042
+#define DEVICE_TYPE_LFP_LVDS_PWR       0x5062
+#define DEVICE_TYPE_LFP_LVDS_DUAL      0x5162
+#define DEVICE_TYPE_LFP_LVDS_DUAL_HDCP 0x51e2
+
+#define DEVICE_CFG_NONE                0x00
+#define DEVICE_CFG_12BIT_DVOB  0x01
+#define DEVICE_CFG_12BIT_DVOC  0x02
+#define DEVICE_CFG_24BIT_DVOBC 0x09
+#define DEVICE_CFG_24BIT_DVOCB 0x0a
+#define DEVICE_CFG_DUAL_DVOB   0x11
+#define DEVICE_CFG_DUAL_DVOC   0x12
+#define DEVICE_CFG_DUAL_DVOBC  0x13
+#define DEVICE_CFG_DUAL_LINK_DVOBC     0x19
+#define DEVICE_CFG_DUAL_LINK_DVOCB     0x1a
+
+#define DEVICE_WIRE_NONE       0x00
+#define DEVICE_WIRE_DVOB       0x01
+#define DEVICE_WIRE_DVOC       0x02
+#define DEVICE_WIRE_DVOBC      0x03
+#define DEVICE_WIRE_DVOBB      0x05
+#define DEVICE_WIRE_DVOCC      0x06
+#define DEVICE_WIRE_DVOB_MASTER 0x0d
+#define DEVICE_WIRE_DVOC_MASTER 0x0e
+
+#define DEVICE_PORT_DVOA       0x00 /* none on 845+ */
+#define DEVICE_PORT_DVOB       0x01
+#define DEVICE_PORT_DVOC       0x02
+
+struct child_device_config {
+       u16 handle;
+       u16 device_type;
+       u8  device_id[10]; /* ascii string */
+       u16 addin_offset;
+       u8  dvo_port; /* See Device_PORT_* above */
+       u8  i2c_pin;
+       u8  slave_addr;
+       u8  ddc_pin;
+       u16 edid_ptr;
+       u8  dvo_cfg; /* See DEVICE_CFG_* above */
+       u8  dvo2_port;
+       u8  i2c2_pin;
+       u8  slave2_addr;
+       u8  ddc2_pin;
+       u8  capabilities;
+       u8  dvo_wiring;/* See DEVICE_WIRE_* above */
+       u8  dvo2_wiring;
+       u16 extended_type;
+       u8  dvo_function;
+} __attribute__((packed));
+
+
 struct bdb_general_definitions {
        /* DDC GPIO */
        u8 crt_ddc_gmbus_pin;
@@ -144,13 +228,18 @@ struct bdb_general_definitions {
        u8 boot_display[2];
        u8 child_dev_size;
 
-       /* device info */
-       u8 tv_or_lvds_info[33];
-       u8 dev1[33];
-       u8 dev2[33];
-       u8 dev3[33];
-       u8 dev4[33];
-       /* may be another device block here on some platforms */
+       /*
+        * Device info:
+        * If TV is present, it'll be at devices[0].
+        * LVDS will be next, either devices[0] or [1], if present.
+        * On some platforms the number of device is 6. But could be as few as
+        * 4 if both TV and LVDS are missing.
+        * And the device num is related with the size of general definition
+        * block. It is obtained by using the following formula:
+        * number = (block_size - sizeof(bdb_general_definitions))/
+        *           sizeof(child_device_config);
+        */
+       struct child_device_config devices[0];
 };
 
 struct bdb_lvds_options {
@@ -302,6 +391,45 @@ struct bdb_sdvo_lvds_options {
        u8 panel_misc_bits_4;
 } __attribute__((packed));
 
+struct bdb_driver_features {
+       u8 boot_dev_algorithm:1;
+       u8 block_display_switch:1;
+       u8 allow_display_switch:1;
+       u8 hotplug_dvo:1;
+       u8 dual_view_zoom:1;
+       u8 int15h_hook:1;
+       u8 sprite_in_clone:1;
+       u8 primary_lfp_id:1;
+
+       u16 boot_mode_x;
+       u16 boot_mode_y;
+       u8 boot_mode_bpp;
+       u8 boot_mode_refresh;
+
+       u16 enable_lfp_primary:1;
+       u16 selective_mode_pruning:1;
+       u16 dual_frequency:1;
+       u16 render_clock_freq:1; /* 0: high freq; 1: low freq */
+       u16 nt_clone_support:1;
+       u16 power_scheme_ui:1; /* 0: CUI; 1: 3rd party */
+       u16 sprite_display_assign:1; /* 0: secondary; 1: primary */
+       u16 cui_aspect_scaling:1;
+       u16 preserve_aspect_ratio:1;
+       u16 sdvo_device_power_down:1;
+       u16 crt_hotplug:1;
+       u16 lvds_config:2;
+       u16 tv_hotplug:1;
+       u16 hdmi_config:2;
+
+       u8 static_display:1;
+       u8 reserved2:7;
+       u16 legacy_crt_max_x;
+       u16 legacy_crt_max_y;
+       u8 legacy_crt_max_refresh;
+
+       u8 hdmi_termination;
+       u8 custom_vbt_version;
+} __attribute__((packed));
 
 extern bool psb_intel_init_bios(struct drm_device *dev);
 extern void psb_intel_destroy_bios(struct drm_device *dev);
@@ -427,4 +555,21 @@ extern void psb_intel_destroy_bios(struct drm_device *dev);
 #define   SWF14_APM_STANDBY    0x1
 #define   SWF14_APM_RESTORE    0x0
 
+/* Add the device class for LFP, TV, HDMI */
+#define         DEVICE_TYPE_INT_LFP    0x1022
+#define         DEVICE_TYPE_INT_TV     0x1009
+#define         DEVICE_TYPE_HDMI       0x60D2
+#define         DEVICE_TYPE_DP         0x68C6
+#define         DEVICE_TYPE_eDP        0x78C6
+
+/* define the DVO port for HDMI output type */
+#define                DVO_B           1
+#define                DVO_C           2
+#define                DVO_D           3
+
+/* define the PORT for DP output type */
+#define                PORT_IDPB       7
+#define                PORT_IDPC       8
+#define                PORT_IDPD       9
+
 #endif /* _I830_BIOS_H_ */
index d946bc1..7041f40 100644 (file)
 
 #include "psb_drv.h"
 
+#define PCI_ASLE 0xe4
+#define PCI_ASLS 0xfc
+
+#define OPREGION_HEADER_OFFSET 0
+#define OPREGION_ACPI_OFFSET   0x100
+#define   ACPI_CLID 0x01ac /* current lid state indicator */
+#define   ACPI_CDCK 0x01b0 /* current docking state indicator */
+#define OPREGION_SWSCI_OFFSET  0x200
+#define OPREGION_ASLE_OFFSET   0x300
+#define OPREGION_VBT_OFFSET    0x400
+
+#define OPREGION_SIGNATURE "IntelGraphicsMem"
+#define MBOX_ACPI      (1<<0)
+#define MBOX_SWSCI     (1<<1)
+#define MBOX_ASLE      (1<<2)
+
 struct opregion_header {
        u8 signature[16];
        u32 size;
@@ -36,21 +52,94 @@ struct opregion_header {
        u8 reserved[164];
 } __packed;
 
-struct opregion_apci {
-       /*FIXME: add it later*/
-} __packed;
+/* OpRegion mailbox #1: public ACPI methods */
+struct opregion_acpi {
+       u32 drdy;       /* driver readiness */
+       u32 csts;       /* notification status */
+       u32 cevt;       /* current event */
+       u8 rsvd1[20];
+       u32 didl[8];    /* supported display devices ID list */
+       u32 cpdl[8];    /* currently presented display list */
+       u32 cadl[8];    /* currently active display list */
+       u32 nadl[8];    /* next active devices list */
+       u32 aslp;       /* ASL sleep time-out */
+       u32 tidx;       /* toggle table index */
+       u32 chpd;       /* current hotplug enable indicator */
+       u32 clid;       /* current lid state*/
+       u32 cdck;       /* current docking state */
+       u32 sxsw;       /* Sx state resume */
+       u32 evts;       /* ASL supported events */
+       u32 cnot;       /* current OS notification */
+       u32 nrdy;       /* driver status */
+       u8 rsvd2[60];
+} __attribute__((packed));
 
+/* OpRegion mailbox #2: SWSCI */
 struct opregion_swsci {
-       /*FIXME: add it later*/
-} __packed;
+       u32 scic;       /* SWSCI command|status|data */
+       u32 parm;       /* command parameters */
+       u32 dslp;       /* driver sleep time-out */
+       u8 rsvd[244];
+} __attribute__((packed));
 
-struct opregion_acpi {
-       /*FIXME: add it later*/
-} __packed;
+/* OpRegion mailbox #3: ASLE */
+struct opregion_asle {
+       u32 ardy;       /* driver readiness */
+       u32 aslc;       /* ASLE interrupt command */
+       u32 tche;       /* technology enabled indicator */
+       u32 alsi;       /* current ALS illuminance reading */
+       u32 bclp;       /* backlight brightness to set */
+       u32 pfit;       /* panel fitting state */
+       u32 cblv;       /* current brightness level */
+       u16 bclm[20];   /* backlight level duty cycle mapping table */
+       u32 cpfm;       /* current panel fitting mode */
+       u32 epfm;       /* enabled panel fitting modes */
+       u8 plut[74];    /* panel LUT and identifier */
+       u32 pfmb;       /* PWM freq and min brightness */
+       u8 rsvd[102];
+} __attribute__((packed));
+
+/* ASLE irq request bits */
+#define ASLE_SET_ALS_ILLUM     (1 << 0)
+#define ASLE_SET_BACKLIGHT     (1 << 1)
+#define ASLE_SET_PFIT          (1 << 2)
+#define ASLE_SET_PWM_FREQ      (1 << 3)
+#define ASLE_REQ_MSK           0xf
+
+/* response bits of ASLE irq request */
+#define ASLE_ALS_ILLUM_FAILED  (1<<10)
+#define ASLE_BACKLIGHT_FAILED  (1<<12)
+#define ASLE_PFIT_FAILED       (1<<14)
+#define ASLE_PWM_FREQ_FAILED   (1<<16)
+
+/* ASLE backlight brightness to set */
+#define ASLE_BCLP_VALID                (1<<31)
+#define ASLE_BCLP_MSK          (~(1<<31))
+
+/* ASLE panel fitting request */
+#define ASLE_PFIT_VALID         (1<<31)
+#define ASLE_PFIT_CENTER (1<<0)
+#define ASLE_PFIT_STRETCH_TEXT (1<<1)
+#define ASLE_PFIT_STRETCH_GFX (1<<2)
+
+/* PWM frequency and minimum brightness */
+#define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
+#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
+#define ASLE_PFMB_PWM_MASK (0x7ffffe00)
+#define ASLE_PFMB_PWM_VALID (1<<31)
+
+#define ASLE_CBLV_VALID         (1<<31)
+
+#define ACPI_OTHER_OUTPUT (0<<8)
+#define ACPI_VGA_OUTPUT (1<<8)
+#define ACPI_TV_OUTPUT (2<<8)
+#define ACPI_DIGITAL_OUTPUT (3<<8)
+#define ACPI_LVDS_OUTPUT (4<<8)
 
 int gma_intel_opregion_init(struct drm_device *dev)
 {
        struct drm_psb_private *dev_priv = dev->dev_private;
+       struct psb_intel_opregion *opregion = &dev_priv->opregion;
        u32 opregion_phy;
        void *base;
        u32 *lid_state;
@@ -64,18 +153,26 @@ int gma_intel_opregion_init(struct drm_device *dev)
        base = ioremap(opregion_phy, 8*1024);
        if (!base)
                return -ENOMEM;
+       /* FIXME: should use _io ops - ditto on i915 */
+       if (memcmp(base, OPREGION_SIGNATURE, 16)) {
+               DRM_ERROR("opregion signature mismatch\n");
+               iounmap(base);
+               return -EINVAL;
+       }
 
        lid_state = base + 0x01ac;
 
        dev_priv->lid_state = lid_state;
        dev_priv->lid_last_state = readl(lid_state);
+       opregion->header = base;
+       opregion->vbt = base + OPREGION_VBT_OFFSET;
        return 0;
 }
 
 int gma_intel_opregion_exit(struct drm_device *dev)
 {
        struct drm_psb_private *dev_priv = dev->dev_private;
-       if (dev_priv->lid_state)
-               iounmap(dev_priv->lid_state);
+       if (dev_priv->opregion.header)
+               iounmap(dev_priv->opregion.header);
        return 0;
 }
index af65678..a0bd48c 100644 (file)
@@ -672,6 +672,8 @@ const struct psb_ops mdfld_chip_ops = {
        .accel_2d = 0,
        .pipes = 3,
        .crtcs = 3,
+       .lvds_mask = (1 << 1);
+       .hdmi_mask = (1 << 1);
        .sgx_offset = MRST_SGX_OFFSET,
 
        .chip_setup = mid_chip_setup,
index 41d1924..4c5a186 100644 (file)
@@ -487,6 +487,8 @@ const struct psb_ops oaktrail_chip_ops = {
        .accel_2d = 1,
        .pipes = 2,
        .crtcs = 2,
+       .hdmi_mask = (1 << 0),
+       .lvds_mask = (1 << 0),
        .sgx_offset = MRST_SGX_OFFSET,
 
        .chip_setup = oaktrail_chip_setup,
index f8b367b..2595660 100644 (file)
@@ -179,7 +179,6 @@ static void oaktrail_hdmi_dpms(struct drm_encoder *encoder, int mode)
 static int oaktrail_hdmi_mode_valid(struct drm_connector *connector,
                                struct drm_display_mode *mode)
 {
-       struct drm_psb_private *dev_priv = connector->dev->dev_private;
        if (mode->clock > 165000)
                return MODE_CLOCK_HIGH;
        if (mode->clock < 20000)
@@ -188,11 +187,6 @@ static int oaktrail_hdmi_mode_valid(struct drm_connector *connector,
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
                return MODE_NO_DBLESCAN;
 
-       /* We assume worst case scenario of 32 bpp here, since we don't know */
-       if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) >
-           dev_priv->vram_stolen_size)
-               return MODE_MEM;
-
        return MODE_OK;
 }
 
index 95d163e..34e6866 100644 (file)
@@ -308,6 +308,8 @@ const struct psb_ops psb_chip_ops = {
        .accel_2d = 1,
        .pipes = 2,
        .crtcs = 2,
+       .hdmi_mask = (1 << 0),
+       .lvds_mask = (1 << 1),
        .sgx_offset = PSB_SGX_OFFSET,
        .chip_setup = psb_chip_setup,
        .chip_teardown = psb_chip_teardown,
index c34adf9..d5a6eab 100644 (file)
@@ -246,6 +246,7 @@ static int psb_driver_unload(struct drm_device *dev)
                }
                psb_gtt_takedown(dev);
                if (dev_priv->scratch_page) {
+                       set_pages_wb(dev_priv->scratch_page, 1);
                        __free_page(dev_priv->scratch_page);
                        dev_priv->scratch_page = NULL;
                }
index 40ce2c9..d3528a6 100644 (file)
@@ -130,6 +130,7 @@ enum {
 #define _PSB_VSYNC_PIPEA_FLAG    (1<<7)
 #define _MDFLD_MIPIA_FLAG        (1<<16)
 #define _MDFLD_MIPIC_FLAG        (1<<17)
+#define _PSB_IRQ_DISP_HOTSYNC    (1<<17)
 #define _PSB_IRQ_SGX_FLAG        (1<<18)
 #define _PSB_IRQ_MSVDX_FLAG      (1<<19)
 #define _LNC_IRQ_TOPAZ_FLAG      (1<<20)
@@ -257,6 +258,7 @@ struct psb_intel_opregion {
        struct opregion_acpi *acpi;
        struct opregion_swsci *swsci;
        struct opregion_asle *asle;
+       void *vbt;
        int enabled;
 };
 
@@ -494,6 +496,9 @@ struct psb_ops;
 struct drm_psb_private {
        struct drm_device *dev;
        const struct psb_ops *ops;
+       
+       struct child_device_config *child_dev;
+       int child_dev_num;
 
        struct psb_gtt gtt;
 
@@ -621,6 +626,11 @@ struct drm_psb_private {
        uint32_t msi_addr;
        uint32_t msi_data;
 
+       /*
+        * Hotplug handling
+        */
+
+       struct work_struct hotplug_work;
 
        /*
         * LID-Switch
@@ -669,6 +679,8 @@ struct drm_psb_private {
        u32 dspcntr[3];
 
        int mdfld_panel_id;
+
+       bool dplla_96mhz;       /* DPLL data from the VBT */
 };
 
 
@@ -682,6 +694,8 @@ struct psb_ops {
        int pipes;              /* Number of output pipes */
        int crtcs;              /* Number of CRTCs */
        int sgx_offset;         /* Base offset of SGX device */
+       int hdmi_mask;          /* Mask of HDMI CRTCs */
+       int lvds_mask;          /* Mask of LVDS CRTCs */
 
        /* Sub functions */
        struct drm_crtc_helper_funcs const *crtc_helper;
@@ -690,9 +704,13 @@ struct psb_ops {
        /* Setup hooks */
        int (*chip_setup)(struct drm_device *dev);
        void (*chip_teardown)(struct drm_device *dev);
+       /* Optional helper caller after modeset */
+       void (*errata)(struct drm_device *dev);
 
        /* Display management hooks */
        int (*output_init)(struct drm_device *dev);
+       int (*hotplug)(struct drm_device *dev);
+       void (*hotplug_enable)(struct drm_device *dev, bool on);
        /* Power management hooks */
        void (*init_pm)(struct drm_device *dev);
        int (*save_regs)(struct drm_device *dev);
index f40535e..81852b4 100644 (file)
@@ -193,6 +193,9 @@ struct psb_intel_crtc {
        /*crtc mode setting flags*/
        u32 mode_flags;
 
+       bool active;
+       bool crtc_enable;
+
        /* Saved Crtc HW states */
        struct psb_intel_crtc_state *crtc_state;
 };
index e89d3a2..519a9cd 100644 (file)
@@ -91,6 +91,9 @@
 
 #define BLC_PWM_CTL            0x61254
 #define BLC_PWM_CTL2           0x61250
+#define  PWM_ENABLE            (1 << 31)
+#define  PWM_LEGACY_MODE       (1 << 30)
+#define  PWM_PIPE_B            (1 << 29)
 #define BLC_PWM_CTL_C          0x62254
 #define BLC_PWM_CTL2_C         0x62250
 #define BACKLIGHT_MODULATION_FREQ_SHIFT                (17)
 #define DPLLB_LVDS_P2_CLOCK_DIV_14     (0 << 24)       /* i915 */
 #define DPLLB_LVDS_P2_CLOCK_DIV_7      (1 << 24)       /* i915 */
 #define DPLL_P2_CLOCK_DIV_MASK         0x03000000      /* i915 */
-#define DPLL_FPA01_P1_POST_DIV_MASK    0x00ff0000      /* i915 */
+#define DPLL_FPA0h1_P1_POST_DIV_MASK   0x00ff0000      /* i915 */
 #define DPLL_LOCK                      (1 << 15)       /* CDV */
 
 /*
 #define FP_M2_DIV_SHIFT                        0
 
 #define PORT_HOTPLUG_EN                0x61110
+#define HDMIB_HOTPLUG_INT_EN           (1 << 29)
+#define HDMIC_HOTPLUG_INT_EN           (1 << 28)
+#define HDMID_HOTPLUG_INT_EN           (1 << 27)
 #define SDVOB_HOTPLUG_INT_EN           (1 << 26)
 #define SDVOC_HOTPLUG_INT_EN           (1 << 25)
 #define TV_HOTPLUG_INT_EN              (1 << 18)
 #define PIPE_VSYNC_ENABL                       (1UL << 25)
 #define PIPE_HDMI_AUDIO_UNDERRUN               (1UL << 26)
 #define PIPE_HDMI_AUDIO_BUFFER_DONE            (1UL << 27)
+#define PIPE_FIFO_UNDERRUN                     (1UL << 31)
 #define PIPE_HDMI_AUDIO_INT_MASK               (PIPE_HDMI_AUDIO_UNDERRUN | \
                                                PIPE_HDMI_AUDIO_BUFFER_DONE)
 #define PIPE_EVENT_MASK ((1 << 29)|(1 << 28)|(1 << 27)|(1 << 26)|(1 << 24)|(1 << 23)|(1 << 22)|(1 << 21)|(1 << 20)|(1 << 16))
@@ -569,12 +576,27 @@ struct dpst_guardband {
 #define PIPE_PIXEL_MASK                0x00ffffff
 #define PIPE_PIXEL_SHIFT       0
 
+#define FW_BLC_SELF            0x20e0 
+#define FW_BLC_SELF_EN          (1<<15)
+
 #define DSPARB                 0x70030
 #define DSPFW1                 0x70034
+#define DSP_FIFO_SR_WM_MASK            0xFF800000
+#define DSP_FIFO_SR_WM_SHIFT           23
+#define CURSOR_B_FIFO_WM_MASK          0x003F0000
+#define CURSOR_B_FIFO_WM_SHIFT         16
 #define DSPFW2                 0x70038
+#define CURSOR_A_FIFO_WM_MASK          0x3F00
+#define CURSOR_A_FIFO_WM_SHIFT         8
+#define DSP_PLANE_C_FIFO_WM_MASK       0x7F
+#define DSP_PLANE_C_FIFO_WM_SHIFT      0
 #define DSPFW3                 0x7003c
 #define DSPFW4                 0x70050
 #define DSPFW5                 0x70054
+#define DSP_PLANE_B_FIFO_WM1_SHIFT     24
+#define DSP_PLANE_A_FIFO_WM1_SHIFT     16
+#define CURSOR_B_FIFO_WM1_SHIFT                8
+#define CURSOR_FIFO_SR_WM1_SHIFT       0
 #define DSPFW6                 0x70058
 #define DSPCHICKENBIT          0x70400
 #define DSPACNTR               0x70180
@@ -1290,6 +1312,15 @@ No status bits are changed.
 #define SB_N_CB_TUNE_MASK                      PSB_MASK(25, 24)
 #define SB_N_CB_TUNE_SHIFT                     24
 
+/* the bit 14:13 is used to select between the different reference clock for Pipe A/B */
+#define SB_REF_DPLLA           0x8010
+#define SB_REF_DPLLB           0x8030
+#define        REF_CLK_MASK            (0x3 << 13)
+#define REF_CLK_CORE           (0 << 13)
+#define REF_CLK_DPLL           (1 << 13)
+#define REF_CLK_DPLLA          (2 << 13)
+/* For the DPLL B, it will use the reference clk from DPLL A when using (2 << 13) */
+
 #define _SB_REF_A              0x8018
 #define _SB_REF_B              0x8038
 #define SB_REF_SFR(pipe)       _PIPE(pipe, _SB_REF_A, _SB_REF_B)
@@ -1313,6 +1344,7 @@ No status bits are changed.
 
 #define LANE_PLL_MASK          (0x7 << 20)
 #define LANE_PLL_ENABLE                (0x3 << 20)
+#define LANE_PLL_PIPE(p)       (((p) == 0) ? (1 << 21) : (0 << 21))
 
 
 #endif
index 36330ca..958b4e2 100644 (file)
@@ -1141,7 +1141,6 @@ static void psb_intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
 static int psb_intel_sdvo_mode_valid(struct drm_connector *connector,
                                 struct drm_display_mode *mode)
 {
-       struct drm_psb_private *dev_priv = connector->dev->dev_private;
        struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector);
 
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
@@ -1161,11 +1160,6 @@ static int psb_intel_sdvo_mode_valid(struct drm_connector *connector,
                        return MODE_PANEL;
        }
 
-       /* We assume worst case scenario of 32 bpp here, since we don't know */
-       if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) >
-           dev_priv->vram_stolen_size)
-               return MODE_MEM;
-
        return MODE_OK;
 }
 
index 1869586..2fcdffd 100644 (file)
@@ -199,11 +199,9 @@ static void psb_vdc_interrupt(struct drm_device *dev, uint32_t vdc_stat)
 
 irqreturn_t psb_irq_handler(DRM_IRQ_ARGS)
 {
-       struct drm_device *dev = (struct drm_device *) arg;
-       struct drm_psb_private *dev_priv =
-           (struct drm_psb_private *) dev->dev_private;
-
-       uint32_t vdc_stat, dsp_int = 0, sgx_int = 0;
+       struct drm_device *dev = arg;
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       uint32_t vdc_stat, dsp_int = 0, sgx_int = 0, hotplug_int = 0;
        int handled = 0;
 
        spin_lock(&dev_priv->irqmask_lock);
@@ -220,6 +218,8 @@ irqreturn_t psb_irq_handler(DRM_IRQ_ARGS)
 
        if (vdc_stat & _PSB_IRQ_SGX_FLAG)
                sgx_int = 1;
+       if (vdc_stat & _PSB_IRQ_DISP_HOTSYNC)
+               hotplug_int = 1;
 
        vdc_stat &= dev_priv->vdc_irq_mask;
        spin_unlock(&dev_priv->irqmask_lock);
@@ -241,6 +241,13 @@ irqreturn_t psb_irq_handler(DRM_IRQ_ARGS)
                handled = 1;
        }
 
+       /* Note: this bit has other meanings on some devices, so we will
+          need to address that later if it ever matters */
+       if (hotplug_int && dev_priv->ops->hotplug) {
+               handled = dev_priv->ops->hotplug(dev);
+               REG_WRITE(PORT_HOTPLUG_STAT, REG_READ(PORT_HOTPLUG_STAT));
+       }
+
        PSB_WVDC32(vdc_stat, PSB_INT_IDENTITY_R);
        (void) PSB_RVDC32(PSB_INT_IDENTITY_R);
        DRM_READMEMORYBARRIER();
@@ -273,6 +280,10 @@ void psb_irq_preinstall(struct drm_device *dev)
                dev_priv->vdc_irq_mask |= _MDFLD_PIPEC_EVENT_FLAG;
        */
 
+       /* Revisit this area - want per device masks ? */
+       if (dev_priv->ops->hotplug)
+               dev_priv->vdc_irq_mask |= _PSB_IRQ_DISP_HOTSYNC;
+
        /* This register is safe even if display island is off */
        PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R);
        spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
@@ -305,18 +316,23 @@ int psb_irq_postinstall(struct drm_device *dev)
        else
                psb_disable_pipestat(dev_priv, 2, PIPE_VBLANK_INTERRUPT_ENABLE);
 
+       if (dev_priv->ops->hotplug_enable)
+               dev_priv->ops->hotplug_enable(dev, true);
+
        spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
        return 0;
 }
 
 void psb_irq_uninstall(struct drm_device *dev)
 {
-       struct drm_psb_private *dev_priv =
-           (struct drm_psb_private *) dev->dev_private;
+       struct drm_psb_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
 
        spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
 
+       if (dev_priv->ops->hotplug_enable)
+               dev_priv->ops->hotplug_enable(dev, false);
+
        PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM);
 
        if (dev->vblank_enabled[0])
index b5ff1f7..2fab38f 100644 (file)
@@ -588,8 +588,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                if (encoder->crtc == crtc) {
                        radeon_encoder = to_radeon_encoder(encoder);
                        connector = radeon_get_connector_for_encoder(encoder);
-                       /* if (connector && connector->display_info.bpc)
-                               bpc = connector->display_info.bpc; */
+                       bpc = radeon_get_monitor_bpc(connector);
                        encoder_mode = atombios_get_encoder_mode(encoder);
                        is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock);
                        if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
@@ -965,9 +964,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
                struct radeon_connector_atom_dig *dig_connector =
                        radeon_connector->con_priv;
                int dp_clock;
-
-               /* if (connector->display_info.bpc)
-                       bpc = connector->display_info.bpc; */
+               bpc = radeon_get_monitor_bpc(connector);
 
                switch (encoder_mode) {
                case ATOM_ENCODER_MODE_DP_MST:
index c57d856..cadbb10 100644 (file)
@@ -405,13 +405,10 @@ static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
 /* get bpc from the EDID */
 static int convert_bpc_to_bpp(int bpc)
 {
-#if 0
        if (bpc == 0)
                return 24;
        else
                return bpc * 3;
-#endif
-       return 24;
 }
 
 /* get the max pix clock supported by the link rate and lane num */
@@ -463,7 +460,7 @@ static int radeon_dp_get_dp_lane_number(struct drm_connector *connector,
                                        u8 dpcd[DP_DPCD_SIZE],
                                        int pix_clock)
 {
-       int bpp = convert_bpc_to_bpp(connector->display_info.bpc);
+       int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
        int max_link_rate = dp_get_max_link_rate(dpcd);
        int max_lane_num = dp_get_max_lane_number(dpcd);
        int lane_num;
@@ -482,7 +479,7 @@ static int radeon_dp_get_dp_link_clock(struct drm_connector *connector,
                                       u8 dpcd[DP_DPCD_SIZE],
                                       int pix_clock)
 {
-       int bpp = convert_bpc_to_bpp(connector->display_info.bpc);
+       int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
        int lane_num, max_pix_clock;
 
        if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) ==
index 2d39f99..b92a694 100644 (file)
@@ -545,7 +545,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo
                dp_clock = dig_connector->dp_clock;
                dp_lane_count = dig_connector->dp_lane_count;
                hpd_id = radeon_connector->hpd.hpd;
-               /* bpc = connector->display_info.bpc; */
+               bpc = radeon_get_monitor_bpc(connector);
        }
 
        /* no dig encoder assigned */
@@ -1163,7 +1163,7 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
                dp_lane_count = dig_connector->dp_lane_count;
                connector_object_id =
                        (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
-               /* bpc = connector->display_info.bpc; */
+               bpc = radeon_get_monitor_bpc(connector);
        }
 
        memset(&args, 0, sizeof(args));
index cfa372c..eed7ace 100644 (file)
@@ -2594,6 +2594,7 @@ int evergreen_irq_set(struct radeon_device *rdev)
        u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
        u32 grbm_int_cntl = 0;
        u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0;
+       u32 afmt1 = 0, afmt2 = 0, afmt3 = 0, afmt4 = 0, afmt5 = 0, afmt6 = 0;
 
        if (!rdev->irq.installed) {
                WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
@@ -2614,6 +2615,13 @@ int evergreen_irq_set(struct radeon_device *rdev)
        hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
        hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
 
+       afmt1 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
+       afmt2 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
+       afmt3 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
+       afmt4 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
+       afmt5 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
+       afmt6 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
+
        if (rdev->family >= CHIP_CAYMAN) {
                /* enable CP interrupts on all rings */
                if (rdev->irq.sw_int[RADEON_RING_TYPE_GFX_INDEX]) {
@@ -2690,6 +2698,30 @@ int evergreen_irq_set(struct radeon_device *rdev)
                DRM_DEBUG("evergreen_irq_set: hpd 6\n");
                hpd6 |= DC_HPDx_INT_EN;
        }
+       if (rdev->irq.afmt[0]) {
+               DRM_DEBUG("evergreen_irq_set: hdmi 0\n");
+               afmt1 |= AFMT_AZ_FORMAT_WTRIG_MASK;
+       }
+       if (rdev->irq.afmt[1]) {
+               DRM_DEBUG("evergreen_irq_set: hdmi 1\n");
+               afmt2 |= AFMT_AZ_FORMAT_WTRIG_MASK;
+       }
+       if (rdev->irq.afmt[2]) {
+               DRM_DEBUG("evergreen_irq_set: hdmi 2\n");
+               afmt3 |= AFMT_AZ_FORMAT_WTRIG_MASK;
+       }
+       if (rdev->irq.afmt[3]) {
+               DRM_DEBUG("evergreen_irq_set: hdmi 3\n");
+               afmt4 |= AFMT_AZ_FORMAT_WTRIG_MASK;
+       }
+       if (rdev->irq.afmt[4]) {
+               DRM_DEBUG("evergreen_irq_set: hdmi 4\n");
+               afmt5 |= AFMT_AZ_FORMAT_WTRIG_MASK;
+       }
+       if (rdev->irq.afmt[5]) {
+               DRM_DEBUG("evergreen_irq_set: hdmi 5\n");
+               afmt6 |= AFMT_AZ_FORMAT_WTRIG_MASK;
+       }
        if (rdev->irq.gui_idle) {
                DRM_DEBUG("gui idle\n");
                grbm_int_cntl |= GUI_IDLE_INT_ENABLE;
@@ -2732,6 +2764,13 @@ int evergreen_irq_set(struct radeon_device *rdev)
        WREG32(DC_HPD5_INT_CONTROL, hpd5);
        WREG32(DC_HPD6_INT_CONTROL, hpd6);
 
+       WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, afmt1);
+       WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, afmt2);
+       WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, afmt3);
+       WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, afmt4);
+       WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, afmt5);
+       WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, afmt6);
+
        return 0;
 }
 
@@ -2756,6 +2795,13 @@ static void evergreen_irq_ack(struct radeon_device *rdev)
                rdev->irq.stat_regs.evergreen.d6grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET);
        }
 
+       rdev->irq.stat_regs.evergreen.afmt_status1 = RREG32(AFMT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET);
+       rdev->irq.stat_regs.evergreen.afmt_status2 = RREG32(AFMT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET);
+       rdev->irq.stat_regs.evergreen.afmt_status3 = RREG32(AFMT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET);
+       rdev->irq.stat_regs.evergreen.afmt_status4 = RREG32(AFMT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET);
+       rdev->irq.stat_regs.evergreen.afmt_status5 = RREG32(AFMT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET);
+       rdev->irq.stat_regs.evergreen.afmt_status6 = RREG32(AFMT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET);
+
        if (rdev->irq.stat_regs.evergreen.d1grph_int & GRPH_PFLIP_INT_OCCURRED)
                WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
        if (rdev->irq.stat_regs.evergreen.d2grph_int & GRPH_PFLIP_INT_OCCURRED)
@@ -2829,6 +2875,36 @@ static void evergreen_irq_ack(struct radeon_device *rdev)
                tmp |= DC_HPDx_INT_ACK;
                WREG32(DC_HPD6_INT_CONTROL, tmp);
        }
+       if (rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG) {
+               tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET);
+               tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
+               WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.afmt_status2 & AFMT_AZ_FORMAT_WTRIG) {
+               tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET);
+               tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
+               WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.afmt_status3 & AFMT_AZ_FORMAT_WTRIG) {
+               tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET);
+               tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
+               WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.afmt_status4 & AFMT_AZ_FORMAT_WTRIG) {
+               tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET);
+               tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
+               WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.afmt_status5 & AFMT_AZ_FORMAT_WTRIG) {
+               tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET);
+               tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
+               WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.afmt_status6 & AFMT_AZ_FORMAT_WTRIG) {
+               tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
+               tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
+               WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, tmp);
+       }
 }
 
 void evergreen_irq_disable(struct radeon_device *rdev)
@@ -2878,6 +2954,7 @@ int evergreen_irq_process(struct radeon_device *rdev)
        u32 ring_index;
        unsigned long flags;
        bool queue_hotplug = false;
+       bool queue_hdmi = false;
 
        if (!rdev->ih.enabled || rdev->shutdown)
                return IRQ_NONE;
@@ -3111,6 +3188,55 @@ restart_ih:
                                break;
                        }
                        break;
+               case 44: /* hdmi */
+                       switch (src_data) {
+                       case 0:
+                               if (rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG) {
+                                       rdev->irq.stat_regs.evergreen.afmt_status1 &= ~AFMT_AZ_FORMAT_WTRIG;
+                                       queue_hdmi = true;
+                                       DRM_DEBUG("IH: HDMI0\n");
+                               }
+                               break;
+                       case 1:
+                               if (rdev->irq.stat_regs.evergreen.afmt_status2 & AFMT_AZ_FORMAT_WTRIG) {
+                                       rdev->irq.stat_regs.evergreen.afmt_status2 &= ~AFMT_AZ_FORMAT_WTRIG;
+                                       queue_hdmi = true;
+                                       DRM_DEBUG("IH: HDMI1\n");
+                               }
+                               break;
+                       case 2:
+                               if (rdev->irq.stat_regs.evergreen.afmt_status3 & AFMT_AZ_FORMAT_WTRIG) {
+                                       rdev->irq.stat_regs.evergreen.afmt_status3 &= ~AFMT_AZ_FORMAT_WTRIG;
+                                       queue_hdmi = true;
+                                       DRM_DEBUG("IH: HDMI2\n");
+                               }
+                               break;
+                       case 3:
+                               if (rdev->irq.stat_regs.evergreen.afmt_status4 & AFMT_AZ_FORMAT_WTRIG) {
+                                       rdev->irq.stat_regs.evergreen.afmt_status4 &= ~AFMT_AZ_FORMAT_WTRIG;
+                                       queue_hdmi = true;
+                                       DRM_DEBUG("IH: HDMI3\n");
+                               }
+                               break;
+                       case 4:
+                               if (rdev->irq.stat_regs.evergreen.afmt_status5 & AFMT_AZ_FORMAT_WTRIG) {
+                                       rdev->irq.stat_regs.evergreen.afmt_status5 &= ~AFMT_AZ_FORMAT_WTRIG;
+                                       queue_hdmi = true;
+                                       DRM_DEBUG("IH: HDMI4\n");
+                               }
+                               break;
+                       case 5:
+                               if (rdev->irq.stat_regs.evergreen.afmt_status6 & AFMT_AZ_FORMAT_WTRIG) {
+                                       rdev->irq.stat_regs.evergreen.afmt_status6 &= ~AFMT_AZ_FORMAT_WTRIG;
+                                       queue_hdmi = true;
+                                       DRM_DEBUG("IH: HDMI5\n");
+                               }
+                               break;
+                       default:
+                               DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data);
+                               break;
+                       }
+                       break;
                case 176: /* CP_INT in ring buffer */
                case 177: /* CP_INT in IB1 */
                case 178: /* CP_INT in IB2 */
@@ -3154,6 +3280,8 @@ restart_ih:
                goto restart_ih;
        if (queue_hotplug)
                schedule_work(&rdev->hotplug_work);
+       if (queue_hdmi)
+               schedule_work(&rdev->audio_work);
        rdev->ih.rptr = rptr;
        WREG32(IH_RB_RPTR, rdev->ih.rptr);
        spin_unlock_irqrestore(&rdev->ih.lock, flags);
index 96c10b3..8beac10 100644 (file)
 /* HDMI blocks at 0x7030, 0x7c30, 0x10830, 0x11430, 0x12030, 0x12c30 */
 #define EVERGREEN_HDMI_BASE                            0x7030
 
-#define EVERGREEN_HDMI_CONFIG_OFFSET                   0xf0
-
 #endif
index b4eefc3..79130bf 100644 (file)
 #define        CP_SEM_INCOMPLETE_TIMER_CNTL                    0x85C8
 #define        CP_DEBUG                                        0xC1FC
 
+/* Audio clocks */
+#define DCCG_AUDIO_DTO_SOURCE             0x05ac
+#       define DCCG_AUDIO_DTO0_SOURCE_SEL(x) ((x) << 0) /* crtc0 - crtc5 */
+#       define DCCG_AUDIO_DTO_SEL         (1 << 4) /* 0=dto0 1=dto1 */
+
+#define DCCG_AUDIO_DTO0_PHASE             0x05b0
+#define DCCG_AUDIO_DTO0_MODULE            0x05b4
+#define DCCG_AUDIO_DTO0_LOAD              0x05b8
+#define DCCG_AUDIO_DTO0_CNTL              0x05bc
+
+#define DCCG_AUDIO_DTO1_PHASE             0x05c0
+#define DCCG_AUDIO_DTO1_MODULE            0x05c4
+#define DCCG_AUDIO_DTO1_LOAD              0x05c8
+#define DCCG_AUDIO_DTO1_CNTL              0x05cc
+
+/* DCE 4.0 AFMT */
+#define HDMI_CONTROL                         0x7030
+#       define HDMI_KEEPOUT_MODE             (1 << 0)
+#       define HDMI_PACKET_GEN_VERSION       (1 << 4) /* 0 = r6xx compat */
+#       define HDMI_ERROR_ACK                (1 << 8)
+#       define HDMI_ERROR_MASK               (1 << 9)
+#       define HDMI_DEEP_COLOR_ENABLE        (1 << 24)
+#       define HDMI_DEEP_COLOR_DEPTH         (((x) & 3) << 28)
+#       define HDMI_24BIT_DEEP_COLOR         0
+#       define HDMI_30BIT_DEEP_COLOR         1
+#       define HDMI_36BIT_DEEP_COLOR         2
+#define HDMI_STATUS                          0x7034
+#       define HDMI_ACTIVE_AVMUTE            (1 << 0)
+#       define HDMI_AUDIO_PACKET_ERROR       (1 << 16)
+#       define HDMI_VBI_PACKET_ERROR         (1 << 20)
+#define HDMI_AUDIO_PACKET_CONTROL            0x7038
+#       define HDMI_AUDIO_DELAY_EN(x)        (((x) & 3) << 4)
+#       define HDMI_AUDIO_PACKETS_PER_LINE(x)  (((x) & 0x1f) << 16)
+#define HDMI_ACR_PACKET_CONTROL              0x703c
+#       define HDMI_ACR_SEND                 (1 << 0)
+#       define HDMI_ACR_CONT                 (1 << 1)
+#       define HDMI_ACR_SELECT(x)            (((x) & 3) << 4)
+#       define HDMI_ACR_HW                   0
+#       define HDMI_ACR_32                   1
+#       define HDMI_ACR_44                   2
+#       define HDMI_ACR_48                   3
+#       define HDMI_ACR_SOURCE               (1 << 8) /* 0 - hw; 1 - cts value */
+#       define HDMI_ACR_AUTO_SEND            (1 << 12)
+#       define HDMI_ACR_N_MULTIPLE(x)        (((x) & 7) << 16)
+#       define HDMI_ACR_X1                   1
+#       define HDMI_ACR_X2                   2
+#       define HDMI_ACR_X4                   4
+#       define HDMI_ACR_AUDIO_PRIORITY       (1 << 31)
+#define HDMI_VBI_PACKET_CONTROL              0x7040
+#       define HDMI_NULL_SEND                (1 << 0)
+#       define HDMI_GC_SEND                  (1 << 4)
+#       define HDMI_GC_CONT                  (1 << 5) /* 0 - once; 1 - every frame */
+#define HDMI_INFOFRAME_CONTROL0              0x7044
+#       define HDMI_AVI_INFO_SEND            (1 << 0)
+#       define HDMI_AVI_INFO_CONT            (1 << 1)
+#       define HDMI_AUDIO_INFO_SEND          (1 << 4)
+#       define HDMI_AUDIO_INFO_CONT          (1 << 5)
+#       define HDMI_MPEG_INFO_SEND           (1 << 8)
+#       define HDMI_MPEG_INFO_CONT           (1 << 9)
+#define HDMI_INFOFRAME_CONTROL1              0x7048
+#       define HDMI_AVI_INFO_LINE(x)         (((x) & 0x3f) << 0)
+#       define HDMI_AUDIO_INFO_LINE(x)       (((x) & 0x3f) << 8)
+#       define HDMI_MPEG_INFO_LINE(x)        (((x) & 0x3f) << 16)
+#define HDMI_GENERIC_PACKET_CONTROL          0x704c
+#       define HDMI_GENERIC0_SEND            (1 << 0)
+#       define HDMI_GENERIC0_CONT            (1 << 1)
+#       define HDMI_GENERIC1_SEND            (1 << 4)
+#       define HDMI_GENERIC1_CONT            (1 << 5)
+#       define HDMI_GENERIC0_LINE(x)         (((x) & 0x3f) << 16)
+#       define HDMI_GENERIC1_LINE(x)         (((x) & 0x3f) << 24)
+#define HDMI_GC                              0x7058
+#       define HDMI_GC_AVMUTE                (1 << 0)
+#       define HDMI_GC_AVMUTE_CONT           (1 << 2)
+#define AFMT_AUDIO_PACKET_CONTROL2           0x705c
+#       define AFMT_AUDIO_LAYOUT_OVRD        (1 << 0)
+#       define AFMT_AUDIO_LAYOUT_SELECT      (1 << 1)
+#       define AFMT_60958_CS_SOURCE          (1 << 4)
+#       define AFMT_AUDIO_CHANNEL_ENABLE(x)  (((x) & 0xff) << 8)
+#       define AFMT_DP_AUDIO_STREAM_ID(x)    (((x) & 0xff) << 16)
+#define AFMT_AVI_INFO0                       0x7084
+#       define AFMT_AVI_INFO_CHECKSUM(x)     (((x) & 0xff) << 0)
+#       define AFMT_AVI_INFO_S(x)            (((x) & 3) << 8)
+#       define AFMT_AVI_INFO_B(x)            (((x) & 3) << 10)
+#       define AFMT_AVI_INFO_A(x)            (((x) & 1) << 12)
+#       define AFMT_AVI_INFO_Y(x)            (((x) & 3) << 13)
+#       define AFMT_AVI_INFO_Y_RGB           0
+#       define AFMT_AVI_INFO_Y_YCBCR422      1
+#       define AFMT_AVI_INFO_Y_YCBCR444      2
+#       define AFMT_AVI_INFO_Y_A_B_S(x)      (((x) & 0xff) << 8)
+#       define AFMT_AVI_INFO_R(x)            (((x) & 0xf) << 16)
+#       define AFMT_AVI_INFO_M(x)            (((x) & 0x3) << 20)
+#       define AFMT_AVI_INFO_C(x)            (((x) & 0x3) << 22)
+#       define AFMT_AVI_INFO_C_M_R(x)        (((x) & 0xff) << 16)
+#       define AFMT_AVI_INFO_SC(x)           (((x) & 0x3) << 24)
+#       define AFMT_AVI_INFO_Q(x)            (((x) & 0x3) << 26)
+#       define AFMT_AVI_INFO_EC(x)           (((x) & 0x3) << 28)
+#       define AFMT_AVI_INFO_ITC(x)          (((x) & 0x1) << 31)
+#       define AFMT_AVI_INFO_ITC_EC_Q_SC(x)  (((x) & 0xff) << 24)
+#define AFMT_AVI_INFO1                       0x7088
+#       define AFMT_AVI_INFO_VIC(x)          (((x) & 0x7f) << 0) /* don't use avi infoframe v1 */
+#       define AFMT_AVI_INFO_PR(x)           (((x) & 0xf) << 8) /* don't use avi infoframe v1 */
+#       define AFMT_AVI_INFO_CN(x)           (((x) & 0x3) << 12)
+#       define AFMT_AVI_INFO_YQ(x)           (((x) & 0x3) << 14)
+#       define AFMT_AVI_INFO_TOP(x)          (((x) & 0xffff) << 16)
+#define AFMT_AVI_INFO2                       0x708c
+#       define AFMT_AVI_INFO_BOTTOM(x)       (((x) & 0xffff) << 0)
+#       define AFMT_AVI_INFO_LEFT(x)         (((x) & 0xffff) << 16)
+#define AFMT_AVI_INFO3                       0x7090
+#       define AFMT_AVI_INFO_RIGHT(x)        (((x) & 0xffff) << 0)
+#       define AFMT_AVI_INFO_VERSION(x)      (((x) & 3) << 24)
+#define AFMT_MPEG_INFO0                      0x7094
+#       define AFMT_MPEG_INFO_CHECKSUM(x)    (((x) & 0xff) << 0)
+#       define AFMT_MPEG_INFO_MB0(x)         (((x) & 0xff) << 8)
+#       define AFMT_MPEG_INFO_MB1(x)         (((x) & 0xff) << 16)
+#       define AFMT_MPEG_INFO_MB2(x)         (((x) & 0xff) << 24)
+#define AFMT_MPEG_INFO1                      0x7098
+#       define AFMT_MPEG_INFO_MB3(x)         (((x) & 0xff) << 0)
+#       define AFMT_MPEG_INFO_MF(x)          (((x) & 3) << 8)
+#       define AFMT_MPEG_INFO_FR(x)          (((x) & 1) << 12)
+#define AFMT_GENERIC0_HDR                    0x709c
+#define AFMT_GENERIC0_0                      0x70a0
+#define AFMT_GENERIC0_1                      0x70a4
+#define AFMT_GENERIC0_2                      0x70a8
+#define AFMT_GENERIC0_3                      0x70ac
+#define AFMT_GENERIC0_4                      0x70b0
+#define AFMT_GENERIC0_5                      0x70b4
+#define AFMT_GENERIC0_6                      0x70b8
+#define AFMT_GENERIC1_HDR                    0x70bc
+#define AFMT_GENERIC1_0                      0x70c0
+#define AFMT_GENERIC1_1                      0x70c4
+#define AFMT_GENERIC1_2                      0x70c8
+#define AFMT_GENERIC1_3                      0x70cc
+#define AFMT_GENERIC1_4                      0x70d0
+#define AFMT_GENERIC1_5                      0x70d4
+#define AFMT_GENERIC1_6                      0x70d8
+#define HDMI_ACR_32_0                        0x70dc
+#       define HDMI_ACR_CTS_32(x)            (((x) & 0xfffff) << 12)
+#define HDMI_ACR_32_1                        0x70e0
+#       define HDMI_ACR_N_32(x)              (((x) & 0xfffff) << 0)
+#define HDMI_ACR_44_0                        0x70e4
+#       define HDMI_ACR_CTS_44(x)            (((x) & 0xfffff) << 12)
+#define HDMI_ACR_44_1                        0x70e8
+#       define HDMI_ACR_N_44(x)              (((x) & 0xfffff) << 0)
+#define HDMI_ACR_48_0                        0x70ec
+#       define HDMI_ACR_CTS_48(x)            (((x) & 0xfffff) << 12)
+#define HDMI_ACR_48_1                        0x70f0
+#       define HDMI_ACR_N_48(x)              (((x) & 0xfffff) << 0)
+#define HDMI_ACR_STATUS_0                    0x70f4
+#define HDMI_ACR_STATUS_1                    0x70f8
+#define AFMT_AUDIO_INFO0                     0x70fc
+#       define AFMT_AUDIO_INFO_CHECKSUM(x)   (((x) & 0xff) << 0)
+#       define AFMT_AUDIO_INFO_CC(x)         (((x) & 7) << 8)
+#       define AFMT_AUDIO_INFO_CT(x)         (((x) & 0xf) << 11)
+#       define AFMT_AUDIO_INFO_CHECKSUM_OFFSET(x)   (((x) & 0xff) << 16)
+#       define AFMT_AUDIO_INFO_CXT(x)        (((x) & 0x1f) << 24)
+#define AFMT_AUDIO_INFO1                     0x7100
+#       define AFMT_AUDIO_INFO_CA(x)         (((x) & 0xff) << 0)
+#       define AFMT_AUDIO_INFO_LSV(x)        (((x) & 0xf) << 11)
+#       define AFMT_AUDIO_INFO_DM_INH(x)     (((x) & 1) << 15)
+#       define AFMT_AUDIO_INFO_DM_INH_LSV(x) (((x) & 0xff) << 8)
+#       define AFMT_AUDIO_INFO_LFEBPL(x)     (((x) & 3) << 16)
+#define AFMT_60958_0                         0x7104
+#       define AFMT_60958_CS_A(x)            (((x) & 1) << 0)
+#       define AFMT_60958_CS_B(x)            (((x) & 1) << 1)
+#       define AFMT_60958_CS_C(x)            (((x) & 1) << 2)
+#       define AFMT_60958_CS_D(x)            (((x) & 3) << 3)
+#       define AFMT_60958_CS_MODE(x)         (((x) & 3) << 6)
+#       define AFMT_60958_CS_CATEGORY_CODE(x)      (((x) & 0xff) << 8)
+#       define AFMT_60958_CS_SOURCE_NUMBER(x)      (((x) & 0xf) << 16)
+#       define AFMT_60958_CS_CHANNEL_NUMBER_L(x)   (((x) & 0xf) << 20)
+#       define AFMT_60958_CS_SAMPLING_FREQUENCY(x) (((x) & 0xf) << 24)
+#       define AFMT_60958_CS_CLOCK_ACCURACY(x)     (((x) & 3) << 28)
+#define AFMT_60958_1                         0x7108
+#       define AFMT_60958_CS_WORD_LENGTH(x)  (((x) & 0xf) << 0)
+#       define AFMT_60958_CS_ORIGINAL_SAMPLING_FREQUENCY(x)   (((x) & 0xf) << 4)
+#       define AFMT_60958_CS_VALID_L(x)      (((x) & 1) << 16)
+#       define AFMT_60958_CS_VALID_R(x)      (((x) & 1) << 18)
+#       define AFMT_60958_CS_CHANNEL_NUMBER_R(x)   (((x) & 0xf) << 20)
+#define AFMT_AUDIO_CRC_CONTROL               0x710c
+#       define AFMT_AUDIO_CRC_EN             (1 << 0)
+#define AFMT_RAMP_CONTROL0                   0x7110
+#       define AFMT_RAMP_MAX_COUNT(x)        (((x) & 0xffffff) << 0)
+#       define AFMT_RAMP_DATA_SIGN           (1 << 31)
+#define AFMT_RAMP_CONTROL1                   0x7114
+#       define AFMT_RAMP_MIN_COUNT(x)        (((x) & 0xffffff) << 0)
+#       define AFMT_AUDIO_TEST_CH_DISABLE(x) (((x) & 0xff) << 24)
+#define AFMT_RAMP_CONTROL2                   0x7118
+#       define AFMT_RAMP_INC_COUNT(x)        (((x) & 0xffffff) << 0)
+#define AFMT_RAMP_CONTROL3                   0x711c
+#       define AFMT_RAMP_DEC_COUNT(x)        (((x) & 0xffffff) << 0)
+#define AFMT_60958_2                         0x7120
+#       define AFMT_60958_CS_CHANNEL_NUMBER_2(x)   (((x) & 0xf) << 0)
+#       define AFMT_60958_CS_CHANNEL_NUMBER_3(x)   (((x) & 0xf) << 4)
+#       define AFMT_60958_CS_CHANNEL_NUMBER_4(x)   (((x) & 0xf) << 8)
+#       define AFMT_60958_CS_CHANNEL_NUMBER_5(x)   (((x) & 0xf) << 12)
+#       define AFMT_60958_CS_CHANNEL_NUMBER_6(x)   (((x) & 0xf) << 16)
+#       define AFMT_60958_CS_CHANNEL_NUMBER_7(x)   (((x) & 0xf) << 20)
+#define AFMT_STATUS                          0x7128
+#       define AFMT_AUDIO_ENABLE             (1 << 4)
+#       define AFMT_AUDIO_HBR_ENABLE         (1 << 8)
+#       define AFMT_AZ_FORMAT_WTRIG          (1 << 28)
+#       define AFMT_AZ_FORMAT_WTRIG_INT      (1 << 29)
+#       define AFMT_AZ_AUDIO_ENABLE_CHG      (1 << 30)
+#define AFMT_AUDIO_PACKET_CONTROL            0x712c
+#       define AFMT_AUDIO_SAMPLE_SEND        (1 << 0)
+#       define AFMT_RESET_FIFO_WHEN_AUDIO_DIS (1 << 11) /* set to 1 */
+#       define AFMT_AUDIO_TEST_EN            (1 << 12)
+#       define AFMT_AUDIO_CHANNEL_SWAP       (1 << 24)
+#       define AFMT_60958_CS_UPDATE          (1 << 26)
+#       define AFMT_AZ_AUDIO_ENABLE_CHG_MASK (1 << 27)
+#       define AFMT_AZ_FORMAT_WTRIG_MASK     (1 << 28)
+#       define AFMT_AZ_FORMAT_WTRIG_ACK      (1 << 29)
+#       define AFMT_AZ_AUDIO_ENABLE_CHG_ACK  (1 << 30)
+#define AFMT_VBI_PACKET_CONTROL              0x7130
+#       define AFMT_GENERIC0_UPDATE          (1 << 2)
+#define AFMT_INFOFRAME_CONTROL0              0x7134
+#       define AFMT_AUDIO_INFO_SOURCE        (1 << 6) /* 0 - sound block; 1 - afmt regs */
+#       define AFMT_AUDIO_INFO_UPDATE        (1 << 7)
+#       define AFMT_MPEG_INFO_UPDATE         (1 << 10)
+#define AFMT_GENERIC0_7                      0x7138
 
 #define        GC_USER_SHADER_PIPE_CONFIG                      0x8954
 #define                INACTIVE_QD_PIPES(x)                            ((x) << 8)
index 5b9b81c..222245d 100644 (file)
@@ -2968,6 +2968,15 @@ static void r600_disable_interrupt_state(struct radeon_device *rdev)
                        WREG32(DC_HPD5_INT_CONTROL, tmp);
                        tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY;
                        WREG32(DC_HPD6_INT_CONTROL, tmp);
+                       tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET0) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
+                       WREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET0, tmp);
+                       tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET1) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
+                       WREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET1, tmp);
+               } else {
+                       tmp = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
+                       WREG32(HDMI0_AUDIO_PACKET_CONTROL, tmp);
+                       tmp = RREG32(DCE3_HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
+                       WREG32(DCE3_HDMI1_AUDIO_PACKET_CONTROL, tmp);
                }
        } else {
                WREG32(DACA_AUTODETECT_INT_CONTROL, 0);
@@ -2978,6 +2987,10 @@ static void r600_disable_interrupt_state(struct radeon_device *rdev)
                WREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL, tmp);
                tmp = RREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL) & DC_HOT_PLUG_DETECTx_INT_POLARITY;
                WREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL, tmp);
+               tmp = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
+               WREG32(HDMI0_AUDIO_PACKET_CONTROL, tmp);
+               tmp = RREG32(HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
+               WREG32(HDMI1_AUDIO_PACKET_CONTROL, tmp);
        }
 }
 
@@ -3074,7 +3087,7 @@ int r600_irq_set(struct radeon_device *rdev)
        u32 mode_int = 0;
        u32 hpd1, hpd2, hpd3, hpd4 = 0, hpd5 = 0, hpd6 = 0;
        u32 grbm_int_cntl = 0;
-       u32 hdmi1, hdmi2;
+       u32 hdmi0, hdmi1;
        u32 d1grph = 0, d2grph = 0;
 
        if (!rdev->irq.installed) {
@@ -3089,9 +3102,7 @@ int r600_irq_set(struct radeon_device *rdev)
                return 0;
        }
 
-       hdmi1 = RREG32(R600_HDMI_BLOCK1 + R600_HDMI_CNTL) & ~R600_HDMI_INT_EN;
        if (ASIC_IS_DCE3(rdev)) {
-               hdmi2 = RREG32(R600_HDMI_BLOCK3 + R600_HDMI_CNTL) & ~R600_HDMI_INT_EN;
                hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
                hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
                hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
@@ -3099,12 +3110,18 @@ int r600_irq_set(struct radeon_device *rdev)
                if (ASIC_IS_DCE32(rdev)) {
                        hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
                        hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+                       hdmi0 = RREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET0) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
+                       hdmi1 = RREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET1) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
+               } else {
+                       hdmi0 = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
+                       hdmi1 = RREG32(DCE3_HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
                }
        } else {
-               hdmi2 = RREG32(R600_HDMI_BLOCK2 + R600_HDMI_CNTL) & ~R600_HDMI_INT_EN;
                hpd1 = RREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL) & ~DC_HPDx_INT_EN;
                hpd2 = RREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL) & ~DC_HPDx_INT_EN;
                hpd3 = RREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL) & ~DC_HPDx_INT_EN;
+               hdmi0 = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
+               hdmi1 = RREG32(HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
        }
 
        if (rdev->irq.sw_int[RADEON_RING_TYPE_GFX_INDEX]) {
@@ -3146,13 +3163,13 @@ int r600_irq_set(struct radeon_device *rdev)
                DRM_DEBUG("r600_irq_set: hpd 6\n");
                hpd6 |= DC_HPDx_INT_EN;
        }
-       if (rdev->irq.hdmi[0]) {
-               DRM_DEBUG("r600_irq_set: hdmi 1\n");
-               hdmi1 |= R600_HDMI_INT_EN;
+       if (rdev->irq.afmt[0]) {
+               DRM_DEBUG("r600_irq_set: hdmi 0\n");
+               hdmi0 |= HDMI0_AZ_FORMAT_WTRIG_MASK;
        }
-       if (rdev->irq.hdmi[1]) {
-               DRM_DEBUG("r600_irq_set: hdmi 2\n");
-               hdmi2 |= R600_HDMI_INT_EN;
+       if (rdev->irq.afmt[1]) {
+               DRM_DEBUG("r600_irq_set: hdmi 0\n");
+               hdmi1 |= HDMI0_AZ_FORMAT_WTRIG_MASK;
        }
        if (rdev->irq.gui_idle) {
                DRM_DEBUG("gui idle\n");
@@ -3164,9 +3181,7 @@ int r600_irq_set(struct radeon_device *rdev)
        WREG32(D1GRPH_INTERRUPT_CONTROL, d1grph);
        WREG32(D2GRPH_INTERRUPT_CONTROL, d2grph);
        WREG32(GRBM_INT_CNTL, grbm_int_cntl);
-       WREG32(R600_HDMI_BLOCK1 + R600_HDMI_CNTL, hdmi1);
        if (ASIC_IS_DCE3(rdev)) {
-               WREG32(R600_HDMI_BLOCK3 + R600_HDMI_CNTL, hdmi2);
                WREG32(DC_HPD1_INT_CONTROL, hpd1);
                WREG32(DC_HPD2_INT_CONTROL, hpd2);
                WREG32(DC_HPD3_INT_CONTROL, hpd3);
@@ -3174,12 +3189,18 @@ int r600_irq_set(struct radeon_device *rdev)
                if (ASIC_IS_DCE32(rdev)) {
                        WREG32(DC_HPD5_INT_CONTROL, hpd5);
                        WREG32(DC_HPD6_INT_CONTROL, hpd6);
+                       WREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET0, hdmi0);
+                       WREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET1, hdmi1);
+               } else {
+                       WREG32(HDMI0_AUDIO_PACKET_CONTROL, hdmi0);
+                       WREG32(DCE3_HDMI1_AUDIO_PACKET_CONTROL, hdmi1);
                }
        } else {
-               WREG32(R600_HDMI_BLOCK2 + R600_HDMI_CNTL, hdmi2);
                WREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL, hpd1);
                WREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL, hpd2);
                WREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL, hpd3);
+               WREG32(HDMI0_AUDIO_PACKET_CONTROL, hdmi0);
+               WREG32(HDMI1_AUDIO_PACKET_CONTROL, hdmi1);
        }
 
        return 0;
@@ -3193,10 +3214,19 @@ static void r600_irq_ack(struct radeon_device *rdev)
                rdev->irq.stat_regs.r600.disp_int = RREG32(DCE3_DISP_INTERRUPT_STATUS);
                rdev->irq.stat_regs.r600.disp_int_cont = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE);
                rdev->irq.stat_regs.r600.disp_int_cont2 = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE2);
+               if (ASIC_IS_DCE32(rdev)) {
+                       rdev->irq.stat_regs.r600.hdmi0_status = RREG32(AFMT_STATUS + DCE3_HDMI_OFFSET0);
+                       rdev->irq.stat_regs.r600.hdmi1_status = RREG32(AFMT_STATUS + DCE3_HDMI_OFFSET1);
+               } else {
+                       rdev->irq.stat_regs.r600.hdmi0_status = RREG32(HDMI0_STATUS);
+                       rdev->irq.stat_regs.r600.hdmi1_status = RREG32(DCE3_HDMI1_STATUS);
+               }
        } else {
                rdev->irq.stat_regs.r600.disp_int = RREG32(DISP_INTERRUPT_STATUS);
                rdev->irq.stat_regs.r600.disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE);
                rdev->irq.stat_regs.r600.disp_int_cont2 = 0;
+               rdev->irq.stat_regs.r600.hdmi0_status = RREG32(HDMI0_STATUS);
+               rdev->irq.stat_regs.r600.hdmi1_status = RREG32(HDMI1_STATUS);
        }
        rdev->irq.stat_regs.r600.d1grph_int = RREG32(D1GRPH_INTERRUPT_STATUS);
        rdev->irq.stat_regs.r600.d2grph_int = RREG32(D2GRPH_INTERRUPT_STATUS);
@@ -3262,17 +3292,32 @@ static void r600_irq_ack(struct radeon_device *rdev)
                        tmp |= DC_HPDx_INT_ACK;
                        WREG32(DC_HPD6_INT_CONTROL, tmp);
                }
-       }
-       if (RREG32(R600_HDMI_BLOCK1 + R600_HDMI_STATUS) & R600_HDMI_INT_PENDING) {
-               WREG32_P(R600_HDMI_BLOCK1 + R600_HDMI_CNTL, R600_HDMI_INT_ACK, ~R600_HDMI_INT_ACK);
-       }
-       if (ASIC_IS_DCE3(rdev)) {
-               if (RREG32(R600_HDMI_BLOCK3 + R600_HDMI_STATUS) & R600_HDMI_INT_PENDING) {
-                       WREG32_P(R600_HDMI_BLOCK3 + R600_HDMI_CNTL, R600_HDMI_INT_ACK, ~R600_HDMI_INT_ACK);
+               if (rdev->irq.stat_regs.r600.hdmi0_status & AFMT_AZ_FORMAT_WTRIG) {
+                       tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET0);
+                       tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
+                       WREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET0, tmp);
+               }
+               if (rdev->irq.stat_regs.r600.hdmi1_status & AFMT_AZ_FORMAT_WTRIG) {
+                       tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET1);
+                       tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
+                       WREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET1, tmp);
                }
        } else {
-               if (RREG32(R600_HDMI_BLOCK2 + R600_HDMI_STATUS) & R600_HDMI_INT_PENDING) {
-                       WREG32_P(R600_HDMI_BLOCK2 + R600_HDMI_CNTL, R600_HDMI_INT_ACK, ~R600_HDMI_INT_ACK);
+               if (rdev->irq.stat_regs.r600.hdmi0_status & HDMI0_AZ_FORMAT_WTRIG) {
+                       tmp = RREG32(HDMI0_AUDIO_PACKET_CONTROL);
+                       tmp |= HDMI0_AZ_FORMAT_WTRIG_ACK;
+                       WREG32(HDMI0_AUDIO_PACKET_CONTROL, tmp);
+               }
+               if (rdev->irq.stat_regs.r600.hdmi1_status & HDMI0_AZ_FORMAT_WTRIG) {
+                       if (ASIC_IS_DCE3(rdev)) {
+                               tmp = RREG32(DCE3_HDMI1_AUDIO_PACKET_CONTROL);
+                               tmp |= HDMI0_AZ_FORMAT_WTRIG_ACK;
+                               WREG32(DCE3_HDMI1_AUDIO_PACKET_CONTROL, tmp);
+                       } else {
+                               tmp = RREG32(HDMI1_AUDIO_PACKET_CONTROL);
+                               tmp |= HDMI0_AZ_FORMAT_WTRIG_ACK;
+                               WREG32(HDMI1_AUDIO_PACKET_CONTROL, tmp);
+                       }
                }
        }
 }
@@ -3348,6 +3393,7 @@ int r600_irq_process(struct radeon_device *rdev)
        u32 ring_index;
        unsigned long flags;
        bool queue_hotplug = false;
+       bool queue_hdmi = false;
 
        if (!rdev->ih.enabled || rdev->shutdown)
                return IRQ_NONE;
@@ -3483,9 +3529,26 @@ restart_ih:
                                break;
                        }
                        break;
-               case 21: /* HDMI */
-                       DRM_DEBUG("IH: HDMI: 0x%x\n", src_data);
-                       r600_audio_schedule_polling(rdev);
+               case 21: /* hdmi */
+                       switch (src_data) {
+                       case 4:
+                               if (rdev->irq.stat_regs.r600.hdmi0_status & HDMI0_AZ_FORMAT_WTRIG) {
+                                       rdev->irq.stat_regs.r600.hdmi0_status &= ~HDMI0_AZ_FORMAT_WTRIG;
+                                       queue_hdmi = true;
+                                       DRM_DEBUG("IH: HDMI0\n");
+                               }
+                               break;
+                       case 5:
+                               if (rdev->irq.stat_regs.r600.hdmi1_status & HDMI0_AZ_FORMAT_WTRIG) {
+                                       rdev->irq.stat_regs.r600.hdmi1_status &= ~HDMI0_AZ_FORMAT_WTRIG;
+                                       queue_hdmi = true;
+                                       DRM_DEBUG("IH: HDMI1\n");
+                               }
+                               break;
+                       default:
+                               DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data);
+                               break;
+                       }
                        break;
                case 176: /* CP_INT in ring buffer */
                case 177: /* CP_INT in IB1 */
@@ -3517,6 +3580,8 @@ restart_ih:
                goto restart_ih;
        if (queue_hotplug)
                schedule_work(&rdev->hotplug_work);
+       if (queue_hdmi)
+               schedule_work(&rdev->audio_work);
        rdev->ih.rptr = rptr;
        WREG32(IH_RB_RPTR, rdev->ih.rptr);
        spin_unlock_irqrestore(&rdev->ih.lock, flags);
index ba66f30..b922a3c 100644 (file)
@@ -29,8 +29,6 @@
 #include "radeon_asic.h"
 #include "atom.h"
 
-#define AUDIO_TIMER_INTERVALL 100 /* 1/10 sekund should be enough */
-
 /*
  * check if the chipset is supported
  */
@@ -105,21 +103,13 @@ uint8_t r600_audio_category_code(struct radeon_device *rdev)
        return (RREG32(R600_AUDIO_STATUS_BITS) >> 8) & 0xff;
 }
 
-/*
- * schedule next audio update event
- */
-void r600_audio_schedule_polling(struct radeon_device *rdev)
-{
-       mod_timer(&rdev->audio_timer,
-               jiffies + msecs_to_jiffies(AUDIO_TIMER_INTERVALL));
-}
-
 /*
  * update all hdmi interfaces with current audio parameters
  */
-static void r600_audio_update_hdmi(unsigned long param)
+void r600_audio_update_hdmi(struct work_struct *work)
 {
-       struct radeon_device *rdev = (struct radeon_device *)param;
+       struct radeon_device *rdev = container_of(work, struct radeon_device,
+                                                 audio_work);
        struct drm_device *dev = rdev->ddev;
 
        int channels = r600_audio_channels(rdev);
@@ -127,33 +117,27 @@ static void r600_audio_update_hdmi(unsigned long param)
        int bps = r600_audio_bits_per_sample(rdev);
        uint8_t status_bits = r600_audio_status_bits(rdev);
        uint8_t category_code = r600_audio_category_code(rdev);
-
        struct drm_encoder *encoder;
-       int changes = 0, still_going = 0;
+       int changes = 0;
 
-       changes |= channels != rdev->audio_channels;
-       changes |= rate != rdev->audio_rate;
-       changes |= bps != rdev->audio_bits_per_sample;
-       changes |= status_bits != rdev->audio_status_bits;
-       changes |= category_code != rdev->audio_category_code;
+       changes |= channels != rdev->audio.channels;
+       changes |= rate != rdev->audio.rate;
+       changes |= bps != rdev->audio.bits_per_sample;
+       changes |= status_bits != rdev->audio.status_bits;
+       changes |= category_code != rdev->audio.category_code;
 
        if (changes) {
-               rdev->audio_channels = channels;
-               rdev->audio_rate = rate;
-               rdev->audio_bits_per_sample = bps;
-               rdev->audio_status_bits = status_bits;
-               rdev->audio_category_code = category_code;
+               rdev->audio.channels = channels;
+               rdev->audio.rate = rate;
+               rdev->audio.bits_per_sample = bps;
+               rdev->audio.status_bits = status_bits;
+               rdev->audio.category_code = category_code;
        }
 
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-               still_going |= radeon_encoder->audio_polling_active;
                if (changes || r600_hdmi_buffer_status_changed(encoder))
                        r600_hdmi_update_audio_settings(encoder);
        }
-
-       if (still_going)
-               r600_audio_schedule_polling(rdev);
 }
 
 /*
@@ -173,11 +157,11 @@ static void r600_audio_engine_enable(struct radeon_device *rdev, bool enable)
                WREG32_P(R600_AUDIO_ENABLE,
                         enable ? 0x81000000 : 0x0, ~0x81000000);
        }
-       rdev->audio_enabled = enable;
+       rdev->audio.enabled = enable;
 }
 
 /*
- * initialize the audio vars and register the update timer
+ * initialize the audio vars
  */
 int r600_audio_init(struct radeon_device *rdev)
 {
@@ -186,50 +170,15 @@ int r600_audio_init(struct radeon_device *rdev)
 
        r600_audio_engine_enable(rdev, true);
 
-       rdev->audio_channels = -1;
-       rdev->audio_rate = -1;
-       rdev->audio_bits_per_sample = -1;
-       rdev->audio_status_bits = 0;
-       rdev->audio_category_code = 0;
-
-       setup_timer(
-               &rdev->audio_timer,
-               r600_audio_update_hdmi,
-               (unsigned long)rdev);
+       rdev->audio.channels = -1;
+       rdev->audio.rate = -1;
+       rdev->audio.bits_per_sample = -1;
+       rdev->audio.status_bits = 0;
+       rdev->audio.category_code = 0;
 
        return 0;
 }
 
-/*
- * enable the polling timer, to check for status changes
- */
-void r600_audio_enable_polling(struct drm_encoder *encoder)
-{
-       struct drm_device *dev = encoder->dev;
-       struct radeon_device *rdev = dev->dev_private;
-       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-
-       DRM_DEBUG("r600_audio_enable_polling: %d\n",
-               radeon_encoder->audio_polling_active);
-       if (radeon_encoder->audio_polling_active)
-               return;
-
-       radeon_encoder->audio_polling_active = 1;
-       if (rdev->audio_enabled)
-               mod_timer(&rdev->audio_timer, jiffies + 1);
-}
-
-/*
- * disable the polling timer, so we get no more status updates
- */
-void r600_audio_disable_polling(struct drm_encoder *encoder)
-{
-       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-       DRM_DEBUG("r600_audio_disable_polling: %d\n",
-               radeon_encoder->audio_polling_active);
-       radeon_encoder->audio_polling_active = 0;
-}
-
 /*
  * atach the audio codec to the clock source of the encoder
  */
@@ -294,10 +243,8 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock)
  */
 void r600_audio_fini(struct radeon_device *rdev)
 {
-       if (!rdev->audio_enabled)
+       if (!rdev->audio.enabled)
                return;
 
-       del_timer(&rdev->audio_timer);
-
        r600_audio_engine_enable(rdev, false);
 }
index 0b59206..c6de002 100644 (file)
@@ -27,6 +27,7 @@
 #include "radeon_drm.h"
 #include "radeon.h"
 #include "radeon_asic.h"
+#include "r600d.h"
 #include "atom.h"
 
 /*
@@ -108,20 +109,20 @@ static void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock)
        CTS = r600_hdmi_ACR[i].CTS_32kHz;
        N = r600_hdmi_ACR[i].N_32kHz;
        r600_hdmi_calc_CTS(clock, &CTS, N, 32000);
-       WREG32(offset+R600_HDMI_32kHz_CTS, CTS << 12);
-       WREG32(offset+R600_HDMI_32kHz_N, N);
+       WREG32(HDMI0_ACR_32_0 + offset, HDMI0_ACR_CTS_32(CTS));
+       WREG32(HDMI0_ACR_32_1 + offset, N);
 
        CTS = r600_hdmi_ACR[i].CTS_44_1kHz;
        N = r600_hdmi_ACR[i].N_44_1kHz;
        r600_hdmi_calc_CTS(clock, &CTS, N, 44100);
-       WREG32(offset+R600_HDMI_44_1kHz_CTS, CTS << 12);
-       WREG32(offset+R600_HDMI_44_1kHz_N, N);
+       WREG32(HDMI0_ACR_44_0 + offset, HDMI0_ACR_CTS_44(CTS));
+       WREG32(HDMI0_ACR_44_1 + offset, N);
 
        CTS = r600_hdmi_ACR[i].CTS_48kHz;
        N = r600_hdmi_ACR[i].N_48kHz;
        r600_hdmi_calc_CTS(clock, &CTS, N, 48000);
-       WREG32(offset+R600_HDMI_48kHz_CTS, CTS << 12);
-       WREG32(offset+R600_HDMI_48kHz_N, N);
+       WREG32(HDMI0_ACR_48_0 + offset, HDMI0_ACR_CTS_48(CTS));
+       WREG32(HDMI0_ACR_48_1 + offset, N);
 }
 
 /*
@@ -204,13 +205,13 @@ static void r600_hdmi_videoinfoframe(
         * workaround this issue. */
        frame[0x0] += 2;
 
-       WREG32(offset+R600_HDMI_VIDEOINFOFRAME_0,
+       WREG32(HDMI0_AVI_INFO0 + offset,
                frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
-       WREG32(offset+R600_HDMI_VIDEOINFOFRAME_1,
+       WREG32(HDMI0_AVI_INFO1 + offset,
                frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x7] << 24));
-       WREG32(offset+R600_HDMI_VIDEOINFOFRAME_2,
+       WREG32(HDMI0_AVI_INFO2 + offset,
                frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
-       WREG32(offset+R600_HDMI_VIDEOINFOFRAME_3,
+       WREG32(HDMI0_AVI_INFO3 + offset,
                frame[0xC] | (frame[0xD] << 8));
 }
 
@@ -249,9 +250,9 @@ static void r600_hdmi_audioinfoframe(
 
        r600_hdmi_infoframe_checksum(0x84, 0x01, 0x0A, frame);
 
-       WREG32(offset+R600_HDMI_AUDIOINFOFRAME_0,
+       WREG32(HDMI0_AUDIO_INFO0 + offset,
                frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
-       WREG32(offset+R600_HDMI_AUDIOINFOFRAME_1,
+       WREG32(HDMI0_AUDIO_INFO1 + offset,
                frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x8] << 24));
 }
 
@@ -264,7 +265,7 @@ static int r600_hdmi_is_audio_buffer_filled(struct drm_encoder *encoder)
        struct radeon_device *rdev = dev->dev_private;
        uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset;
 
-       return (RREG32(offset+R600_HDMI_STATUS) & 0x10) != 0;
+       return (RREG32(HDMI0_STATUS + offset) & 0x10) != 0;
 }
 
 /*
@@ -275,7 +276,7 @@ int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder)
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        int status, result;
 
-       if (!radeon_encoder->hdmi_offset)
+       if (!radeon_encoder->hdmi_enabled)
                return 0;
 
        status = r600_hdmi_is_audio_buffer_filled(encoder);
@@ -295,18 +296,18 @@ void r600_hdmi_audio_workaround(struct drm_encoder *encoder)
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        uint32_t offset = radeon_encoder->hdmi_offset;
 
-       if (!offset)
+       if (!radeon_encoder->hdmi_enabled)
                return;
 
        if (!radeon_encoder->hdmi_audio_workaround ||
                r600_hdmi_is_audio_buffer_filled(encoder)) {
 
                /* disable audio workaround */
-               WREG32_P(offset+R600_HDMI_CNTL, 0x00000001, ~0x00001001);
+               WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset, 0x0001, ~0x1001);
 
        } else {
                /* enable audio workaround */
-               WREG32_P(offset+R600_HDMI_CNTL, 0x00001001, ~0x00001001);
+               WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset, 0x1001, ~0x1001);
        }
 }
 
@@ -323,34 +324,34 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
        if (ASIC_IS_DCE5(rdev))
                return;
 
-       if (!offset)
+       if (!to_radeon_encoder(encoder)->hdmi_enabled)
                return;
 
        r600_audio_set_clock(encoder, mode->clock);
 
-       WREG32(offset+R600_HDMI_UNKNOWN_0, 0x1000);
-       WREG32(offset+R600_HDMI_UNKNOWN_1, 0x0);
-       WREG32(offset+R600_HDMI_UNKNOWN_2, 0x1000);
+       WREG32(HDMI0_AUDIO_CRC_CONTROL + offset, 0x1000);
+       WREG32(HDMI0_GC + offset, 0x0);
+       WREG32(HDMI0_ACR_PACKET_CONTROL + offset, 0x1000);
 
        r600_hdmi_update_ACR(encoder, mode->clock);
 
-       WREG32(offset+R600_HDMI_VIDEOCNTL, 0x13);
+       WREG32(HDMI0_INFOFRAME_CONTROL0 + offset, 0x13);
 
-       WREG32(offset+R600_HDMI_VERSION, 0x202);
+       WREG32(HDMI0_INFOFRAME_CONTROL1 + offset, 0x202);
 
        r600_hdmi_videoinfoframe(encoder, RGB, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 
        /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */
-       WREG32(offset+R600_HDMI_AUDIO_DEBUG_0, 0x00FFFFFF);
-       WREG32(offset+R600_HDMI_AUDIO_DEBUG_1, 0x007FFFFF);
-       WREG32(offset+R600_HDMI_AUDIO_DEBUG_2, 0x00000001);
-       WREG32(offset+R600_HDMI_AUDIO_DEBUG_3, 0x00000001);
+       WREG32(HDMI0_RAMP_CONTROL0 + offset, 0x00FFFFFF);
+       WREG32(HDMI0_RAMP_CONTROL1 + offset, 0x007FFFFF);
+       WREG32(HDMI0_RAMP_CONTROL2 + offset, 0x00000001);
+       WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001);
 
        r600_hdmi_audio_workaround(encoder);
 
        /* audio packets per line, does anyone know how to calc this ? */
-       WREG32_P(offset+R600_HDMI_CNTL, 0x00040000, ~0x001F0000);
+       WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset, 0x00040000, ~0x001F0000);
 }
 
 /*
@@ -370,7 +371,7 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder)
 
        uint32_t iec;
 
-       if (!offset)
+       if (!to_radeon_encoder(encoder)->hdmi_enabled)
                return;
 
        DRM_DEBUG("%s with %d channels, %d Hz sampling rate, %d bits per sample,\n",
@@ -401,7 +402,7 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder)
        case 192000: iec |= 0xe << 24; break;
        }
 
-       WREG32(offset+R600_HDMI_IEC60958_1, iec);
+       WREG32(HDMI0_60958_0 + offset, iec);
 
        iec = 0;
        switch (bps) {
@@ -412,49 +413,15 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder)
        if (status_bits & AUDIO_STATUS_V)
                iec |= 0x5 << 16;
 
-       WREG32_P(offset+R600_HDMI_IEC60958_2, iec, ~0x5000f);
+       WREG32_P(HDMI0_60958_1 + offset, iec, ~0x5000f);
 
        /* 0x021 or 0x031 sets the audio frame length */
-       WREG32(offset+R600_HDMI_AUDIOCNTL, 0x31);
+       WREG32(HDMI0_VBI_PACKET_CONTROL + offset, 0x31);
        r600_hdmi_audioinfoframe(encoder, channels-1, 0, 0, 0, 0, 0, 0, 0);
 
        r600_hdmi_audio_workaround(encoder);
 }
 
-static int r600_hdmi_find_free_block(struct drm_device *dev)
-{
-       struct radeon_device *rdev = dev->dev_private;
-       struct drm_encoder *encoder;
-       struct radeon_encoder *radeon_encoder;
-       bool free_blocks[3] = { true, true, true };
-
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               radeon_encoder = to_radeon_encoder(encoder);
-               switch (radeon_encoder->hdmi_offset) {
-               case R600_HDMI_BLOCK1:
-                       free_blocks[0] = false;
-                       break;
-               case R600_HDMI_BLOCK2:
-                       free_blocks[1] = false;
-                       break;
-               case R600_HDMI_BLOCK3:
-                       free_blocks[2] = false;
-                       break;
-               }
-       }
-
-       if (rdev->family == CHIP_RS600 || rdev->family == CHIP_RS690 ||
-           rdev->family == CHIP_RS740) {
-               return free_blocks[0] ? R600_HDMI_BLOCK1 : 0;
-       } else if (rdev->family >= CHIP_R600) {
-               if (free_blocks[0])
-                       return R600_HDMI_BLOCK1;
-               else if (free_blocks[1])
-                       return R600_HDMI_BLOCK2;
-       }
-       return 0;
-}
-
 static void r600_hdmi_assign_block(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
@@ -483,20 +450,24 @@ static void r600_hdmi_assign_block(struct drm_encoder *encoder)
                        dev_err(rdev->dev, "Enabling HDMI on unknown dig\n");
                        return;
                }
-               radeon_encoder->hdmi_offset = EVERGREEN_HDMI_BASE +
-                                               eg_offsets[dig->dig_encoder];
-               radeon_encoder->hdmi_config_offset = radeon_encoder->hdmi_offset
-                                               + EVERGREEN_HDMI_CONFIG_OFFSET;
+               radeon_encoder->hdmi_offset = eg_offsets[dig->dig_encoder];
+               /* Temp hack for Evergreen until we split r600_hdmi.c
+                * Evergreen first block is 0x7030 instead of 0x7400.
+                */
+               radeon_encoder->hdmi_offset -= 0x3d0;
        } else if (ASIC_IS_DCE3(rdev)) {
                radeon_encoder->hdmi_offset = dig->dig_encoder ?
-                       R600_HDMI_BLOCK3 : R600_HDMI_BLOCK1;
-               if (ASIC_IS_DCE32(rdev))
-                       radeon_encoder->hdmi_config_offset = dig->dig_encoder ?
-                               R600_HDMI_CONFIG2 : R600_HDMI_CONFIG1;
-       } else if (rdev->family >= CHIP_R600 || rdev->family == CHIP_RS600 ||
-                  rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) {
-               radeon_encoder->hdmi_offset = r600_hdmi_find_free_block(dev);
+                       DCE3_HDMI_OFFSET1 : DCE3_HDMI_OFFSET0;
+       } else if (rdev->family >= CHIP_R600) {
+               /* 2 routable blocks, but using dig_encoder should be fine */
+               radeon_encoder->hdmi_offset = dig->dig_encoder ?
+                       DCE2_HDMI_OFFSET1 : DCE2_HDMI_OFFSET0;
+       } else if (rdev->family == CHIP_RS600 || rdev->family == CHIP_RS690 ||
+                  rdev->family == CHIP_RS740) {
+               /* Only 1 routable block */
+               radeon_encoder->hdmi_offset = DCE2_HDMI_OFFSET0;
        }
+       radeon_encoder->hdmi_enabled = true;
 }
 
 /*
@@ -512,9 +483,9 @@ void r600_hdmi_enable(struct drm_encoder *encoder)
        if (ASIC_IS_DCE5(rdev))
                return;
 
-       if (!radeon_encoder->hdmi_offset) {
+       if (!radeon_encoder->hdmi_enabled) {
                r600_hdmi_assign_block(encoder);
-               if (!radeon_encoder->hdmi_offset) {
+               if (!radeon_encoder->hdmi_enabled) {
                        dev_warn(rdev->dev, "Could not find HDMI block for "
                                "0x%x encoder\n", radeon_encoder->encoder_id);
                        return;
@@ -525,9 +496,9 @@ void r600_hdmi_enable(struct drm_encoder *encoder)
        if (ASIC_IS_DCE5(rdev)) {
                /* TODO */
        } else if (ASIC_IS_DCE4(rdev)) {
-               WREG32_P(radeon_encoder->hdmi_config_offset + 0xc, 0x1, ~0x1);
+               WREG32_P(0x74fc + radeon_encoder->hdmi_offset, 0x1, ~0x1);
        } else if (ASIC_IS_DCE32(rdev)) {
-               WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0x1, ~0x1);
+               WREG32_P(AFMT_AUDIO_PACKET_CONTROL + radeon_encoder->hdmi_offset, 0x1, ~0x1);
        } else if (ASIC_IS_DCE3(rdev)) {
                /* TODO */
        } else if (rdev->family >= CHIP_R600) {
@@ -535,12 +506,12 @@ void r600_hdmi_enable(struct drm_encoder *encoder)
                case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
                        WREG32_P(AVIVO_TMDSA_CNTL, AVIVO_TMDSA_CNTL_HDMI_EN,
                                 ~AVIVO_TMDSA_CNTL_HDMI_EN);
-                       WREG32(offset + R600_HDMI_ENABLE, 0x101);
+                       WREG32(HDMI0_CONTROL + offset, 0x101);
                        break;
                case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
                        WREG32_P(AVIVO_LVTMA_CNTL, AVIVO_LVTMA_CNTL_HDMI_EN,
                                 ~AVIVO_LVTMA_CNTL_HDMI_EN);
-                       WREG32(offset + R600_HDMI_ENABLE, 0x105);
+                       WREG32(HDMI0_CONTROL + offset, 0x105);
                        break;
                default:
                        dev_err(rdev->dev, "Unknown HDMI output type\n");
@@ -548,19 +519,10 @@ void r600_hdmi_enable(struct drm_encoder *encoder)
                }
        }
 
-       if (rdev->irq.installed
-           && rdev->family != CHIP_RS600
-           && rdev->family != CHIP_RS690
-           && rdev->family != CHIP_RS740
-           && !ASIC_IS_DCE4(rdev)) {
+       if (rdev->irq.installed) {
                /* if irq is available use it */
-               rdev->irq.hdmi[offset == R600_HDMI_BLOCK1 ? 0 : 1] = true;
+               rdev->irq.afmt[offset == 0 ? 0 : 1] = true;
                radeon_irq_set(rdev);
-
-               r600_audio_disable_polling(encoder);
-       } else {
-               /* if not fallback to polling */
-               r600_audio_enable_polling(encoder);
        }
 
        DRM_DEBUG("Enabling HDMI interface @ 0x%04X for encoder 0x%x\n",
@@ -581,7 +543,7 @@ void r600_hdmi_disable(struct drm_encoder *encoder)
                return;
 
        offset = radeon_encoder->hdmi_offset;
-       if (!offset) {
+       if (!radeon_encoder->hdmi_enabled) {
                dev_err(rdev->dev, "Disabling not enabled HDMI\n");
                return;
        }
@@ -590,29 +552,27 @@ void r600_hdmi_disable(struct drm_encoder *encoder)
                offset, radeon_encoder->encoder_id);
 
        /* disable irq */
-       rdev->irq.hdmi[offset == R600_HDMI_BLOCK1 ? 0 : 1] = false;
+       rdev->irq.afmt[offset == 0 ? 0 : 1] = false;
        radeon_irq_set(rdev);
 
-       /* disable polling */
-       r600_audio_disable_polling(encoder);
 
        if (ASIC_IS_DCE5(rdev)) {
                /* TODO */
        } else if (ASIC_IS_DCE4(rdev)) {
-               WREG32_P(radeon_encoder->hdmi_config_offset + 0xc, 0, ~0x1);
+               WREG32_P(0x74fc + radeon_encoder->hdmi_offset, 0, ~0x1);
        } else if (ASIC_IS_DCE32(rdev)) {
-               WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0, ~0x1);
+               WREG32_P(AFMT_AUDIO_PACKET_CONTROL + radeon_encoder->hdmi_offset, 0, ~0x1);
        } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) {
                switch (radeon_encoder->encoder_id) {
                case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
                        WREG32_P(AVIVO_TMDSA_CNTL, 0,
                                 ~AVIVO_TMDSA_CNTL_HDMI_EN);
-                       WREG32(offset + R600_HDMI_ENABLE, 0);
+                       WREG32(HDMI0_CONTROL + offset, 0);
                        break;
                case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
                        WREG32_P(AVIVO_LVTMA_CNTL, 0,
                                 ~AVIVO_LVTMA_CNTL_HDMI_EN);
-                       WREG32(offset + R600_HDMI_ENABLE, 0);
+                       WREG32(HDMI0_CONTROL + offset, 0);
                        break;
                default:
                        dev_err(rdev->dev, "Unknown HDMI output type\n");
@@ -620,6 +580,6 @@ void r600_hdmi_disable(struct drm_encoder *encoder)
                }
        }
 
+       radeon_encoder->hdmi_enabled = false;
        radeon_encoder->hdmi_offset = 0;
-       radeon_encoder->hdmi_config_offset = 0;
 }
index f869897..c44304a 100644 (file)
 #define R600_AUDIO_PIN_WIDGET_CNTL        0x73d4
 #define R600_AUDIO_STATUS_BITS            0x73d8
 
-/* HDMI base register addresses */
-#define R600_HDMI_BLOCK1                  0x7400
-#define R600_HDMI_BLOCK2                  0x7700
-#define R600_HDMI_BLOCK3                  0x7800
-
-/* HDMI registers */
-#define R600_HDMI_ENABLE                0x00
-#define R600_HDMI_STATUS                0x04
-#       define R600_HDMI_INT_PENDING    (1 << 29)
-#define R600_HDMI_CNTL                  0x08
-#       define R600_HDMI_INT_EN         (1 << 28)
-#       define R600_HDMI_INT_ACK        (1 << 29)
-#define R600_HDMI_UNKNOWN_0             0x0C
-#define R600_HDMI_AUDIOCNTL             0x10
-#define R600_HDMI_VIDEOCNTL             0x14
-#define R600_HDMI_VERSION               0x18
-#define R600_HDMI_UNKNOWN_1             0x28
-#define R600_HDMI_VIDEOINFOFRAME_0      0x54
-#define R600_HDMI_VIDEOINFOFRAME_1      0x58
-#define R600_HDMI_VIDEOINFOFRAME_2      0x5c
-#define R600_HDMI_VIDEOINFOFRAME_3      0x60
-#define R600_HDMI_32kHz_CTS             0xac
-#define R600_HDMI_32kHz_N               0xb0
-#define R600_HDMI_44_1kHz_CTS           0xb4
-#define R600_HDMI_44_1kHz_N             0xb8
-#define R600_HDMI_48kHz_CTS             0xbc
-#define R600_HDMI_48kHz_N               0xc0
-#define R600_HDMI_AUDIOINFOFRAME_0      0xcc
-#define R600_HDMI_AUDIOINFOFRAME_1      0xd0
-#define R600_HDMI_IEC60958_1            0xd4
-#define R600_HDMI_IEC60958_2            0xd8
-#define R600_HDMI_UNKNOWN_2             0xdc
-#define R600_HDMI_AUDIO_DEBUG_0         0xe0
-#define R600_HDMI_AUDIO_DEBUG_1         0xe4
-#define R600_HDMI_AUDIO_DEBUG_2         0xe8
-#define R600_HDMI_AUDIO_DEBUG_3         0xec
-
-/* HDMI additional config base register addresses */
-#define R600_HDMI_CONFIG1                 0x7600
-#define R600_HDMI_CONFIG2                 0x7a00
-
 #endif
index 59f9c99..a9652be 100644 (file)
 #       define TARGET_LINK_SPEED_MASK                     (0xf << 0)
 #       define SELECTABLE_DEEMPHASIS                      (1 << 6)
 
+/* Audio clocks */
+#define DCCG_AUDIO_DTO0_PHASE             0x0514
+#define DCCG_AUDIO_DTO0_MODULE            0x0518
+#define DCCG_AUDIO_DTO0_LOAD              0x051c
+#       define DTO_LOAD                   (1 << 31)
+#define DCCG_AUDIO_DTO0_CNTL              0x0520
+
+#define DCCG_AUDIO_DTO1_PHASE             0x0524
+#define DCCG_AUDIO_DTO1_MODULE            0x0528
+#define DCCG_AUDIO_DTO1_LOAD              0x052c
+#define DCCG_AUDIO_DTO1_CNTL              0x0530
+
+#define DCCG_AUDIO_DTO_SELECT             0x0534
+
+/* digital blocks */
+#define TMDSA_CNTL                       0x7880
+#       define TMDSA_HDMI_EN             (1 << 2)
+#define LVTMA_CNTL                       0x7a80
+#       define LVTMA_HDMI_EN             (1 << 2)
+#define DDIA_CNTL                        0x7200
+#       define DDIA_HDMI_EN              (1 << 2)
+#define DIG0_CNTL                        0x75a0
+#       define DIG_MODE(x)               (((x) & 7) << 8)
+#       define DIG_MODE_DP               0
+#       define DIG_MODE_LVDS             1
+#       define DIG_MODE_TMDS_DVI         2
+#       define DIG_MODE_TMDS_HDMI        3
+#       define DIG_MODE_SDVO             4
+#define DIG1_CNTL                        0x79a0
+
+/* rs6xx/rs740 and r6xx share the same HDMI blocks, however, rs6xx has only one
+ * instance of the blocks while r6xx has 2.  DCE 3.0 cards are slightly
+ * different due to the new DIG blocks, but also have 2 instances.
+ * DCE 3.0 HDMI blocks are part of each DIG encoder.
+ */
+
+/* rs6xx/rs740/r6xx/dce3 */
+#define HDMI0_CONTROL                0x7400
+/* rs6xx/rs740/r6xx */
+#       define HDMI0_ENABLE          (1 << 0)
+#       define HDMI0_STREAM(x)       (((x) & 3) << 2)
+#       define HDMI0_STREAM_TMDSA    0
+#       define HDMI0_STREAM_LVTMA    1
+#       define HDMI0_STREAM_DVOA     2
+#       define HDMI0_STREAM_DDIA     3
+/* rs6xx/r6xx/dce3 */
+#       define HDMI0_ERROR_ACK       (1 << 8)
+#       define HDMI0_ERROR_MASK      (1 << 9)
+#define HDMI0_STATUS                 0x7404
+#       define HDMI0_ACTIVE_AVMUTE   (1 << 0)
+#       define HDMI0_AUDIO_ENABLE    (1 << 4)
+#       define HDMI0_AZ_FORMAT_WTRIG     (1 << 28)
+#       define HDMI0_AZ_FORMAT_WTRIG_INT (1 << 29)
+#define HDMI0_AUDIO_PACKET_CONTROL   0x7408
+#       define HDMI0_AUDIO_SAMPLE_SEND  (1 << 0)
+#       define HDMI0_AUDIO_DELAY_EN(x)  (((x) & 3) << 4)
+#       define HDMI0_AUDIO_SEND_MAX_PACKETS  (1 << 8)
+#       define HDMI0_AUDIO_TEST_EN         (1 << 12)
+#       define HDMI0_AUDIO_PACKETS_PER_LINE(x)  (((x) & 0x1f) << 16)
+#       define HDMI0_AUDIO_CHANNEL_SWAP    (1 << 24)
+#       define HDMI0_60958_CS_UPDATE       (1 << 26)
+#       define HDMI0_AZ_FORMAT_WTRIG_MASK  (1 << 28)
+#       define HDMI0_AZ_FORMAT_WTRIG_ACK   (1 << 29)
+#define HDMI0_AUDIO_CRC_CONTROL      0x740c
+#       define HDMI0_AUDIO_CRC_EN    (1 << 0)
+#define HDMI0_VBI_PACKET_CONTROL     0x7410
+#       define HDMI0_NULL_SEND       (1 << 0)
+#       define HDMI0_GC_SEND         (1 << 4)
+#       define HDMI0_GC_CONT         (1 << 5) /* 0 - once; 1 - every frame */
+#define HDMI0_INFOFRAME_CONTROL0     0x7414
+#       define HDMI0_AVI_INFO_SEND   (1 << 0)
+#       define HDMI0_AVI_INFO_CONT   (1 << 1)
+#       define HDMI0_AUDIO_INFO_SEND (1 << 4)
+#       define HDMI0_AUDIO_INFO_CONT (1 << 5)
+#       define HDMI0_AUDIO_INFO_SOURCE (1 << 6) /* 0 - sound block; 1 - hmdi regs */
+#       define HDMI0_AUDIO_INFO_UPDATE (1 << 7)
+#       define HDMI0_MPEG_INFO_SEND  (1 << 8)
+#       define HDMI0_MPEG_INFO_CONT  (1 << 9)
+#       define HDMI0_MPEG_INFO_UPDATE  (1 << 10)
+#define HDMI0_INFOFRAME_CONTROL1     0x7418
+#       define HDMI0_AVI_INFO_LINE(x)  (((x) & 0x3f) << 0)
+#       define HDMI0_AUDIO_INFO_LINE(x)  (((x) & 0x3f) << 8)
+#       define HDMI0_MPEG_INFO_LINE(x)  (((x) & 0x3f) << 16)
+#define HDMI0_GENERIC_PACKET_CONTROL 0x741c
+#       define HDMI0_GENERIC0_SEND   (1 << 0)
+#       define HDMI0_GENERIC0_CONT   (1 << 1)
+#       define HDMI0_GENERIC0_UPDATE (1 << 2)
+#       define HDMI0_GENERIC1_SEND   (1 << 4)
+#       define HDMI0_GENERIC1_CONT   (1 << 5)
+#       define HDMI0_GENERIC0_LINE(x)  (((x) & 0x3f) << 16)
+#       define HDMI0_GENERIC1_LINE(x)  (((x) & 0x3f) << 24)
+#define HDMI0_GC                     0x7428
+#       define HDMI0_GC_AVMUTE       (1 << 0)
+#define HDMI0_AVI_INFO0              0x7454
+#       define HDMI0_AVI_INFO_CHECKSUM(x)  (((x) & 0xff) << 0)
+#       define HDMI0_AVI_INFO_S(x)   (((x) & 3) << 8)
+#       define HDMI0_AVI_INFO_B(x)   (((x) & 3) << 10)
+#       define HDMI0_AVI_INFO_A(x)   (((x) & 1) << 12)
+#       define HDMI0_AVI_INFO_Y(x)   (((x) & 3) << 13)
+#       define HDMI0_AVI_INFO_Y_RGB       0
+#       define HDMI0_AVI_INFO_Y_YCBCR422  1
+#       define HDMI0_AVI_INFO_Y_YCBCR444  2
+#       define HDMI0_AVI_INFO_Y_A_B_S(x)   (((x) & 0xff) << 8)
+#       define HDMI0_AVI_INFO_R(x)   (((x) & 0xf) << 16)
+#       define HDMI0_AVI_INFO_M(x)   (((x) & 0x3) << 20)
+#       define HDMI0_AVI_INFO_C(x)   (((x) & 0x3) << 22)
+#       define HDMI0_AVI_INFO_C_M_R(x)   (((x) & 0xff) << 16)
+#       define HDMI0_AVI_INFO_SC(x)  (((x) & 0x3) << 24)
+#       define HDMI0_AVI_INFO_ITC_EC_Q_SC(x)  (((x) & 0xff) << 24)
+#define HDMI0_AVI_INFO1              0x7458
+#       define HDMI0_AVI_INFO_VIC(x) (((x) & 0x7f) << 0) /* don't use avi infoframe v1 */
+#       define HDMI0_AVI_INFO_PR(x)  (((x) & 0xf) << 8) /* don't use avi infoframe v1 */
+#       define HDMI0_AVI_INFO_TOP(x) (((x) & 0xffff) << 16)
+#define HDMI0_AVI_INFO2              0x745c
+#       define HDMI0_AVI_INFO_BOTTOM(x)  (((x) & 0xffff) << 0)
+#       define HDMI0_AVI_INFO_LEFT(x)    (((x) & 0xffff) << 16)
+#define HDMI0_AVI_INFO3              0x7460
+#       define HDMI0_AVI_INFO_RIGHT(x)    (((x) & 0xffff) << 0)
+#       define HDMI0_AVI_INFO_VERSION(x)  (((x) & 3) << 24)
+#define HDMI0_MPEG_INFO0             0x7464
+#       define HDMI0_MPEG_INFO_CHECKSUM(x)  (((x) & 0xff) << 0)
+#       define HDMI0_MPEG_INFO_MB0(x)  (((x) & 0xff) << 8)
+#       define HDMI0_MPEG_INFO_MB1(x)  (((x) & 0xff) << 16)
+#       define HDMI0_MPEG_INFO_MB2(x)  (((x) & 0xff) << 24)
+#define HDMI0_MPEG_INFO1             0x7468
+#       define HDMI0_MPEG_INFO_MB3(x)  (((x) & 0xff) << 0)
+#       define HDMI0_MPEG_INFO_MF(x)   (((x) & 3) << 8)
+#       define HDMI0_MPEG_INFO_FR(x)   (((x) & 1) << 12)
+#define HDMI0_GENERIC0_HDR           0x746c
+#define HDMI0_GENERIC0_0             0x7470
+#define HDMI0_GENERIC0_1             0x7474
+#define HDMI0_GENERIC0_2             0x7478
+#define HDMI0_GENERIC0_3             0x747c
+#define HDMI0_GENERIC0_4             0x7480
+#define HDMI0_GENERIC0_5             0x7484
+#define HDMI0_GENERIC0_6             0x7488
+#define HDMI0_GENERIC1_HDR           0x748c
+#define HDMI0_GENERIC1_0             0x7490
+#define HDMI0_GENERIC1_1             0x7494
+#define HDMI0_GENERIC1_2             0x7498
+#define HDMI0_GENERIC1_3             0x749c
+#define HDMI0_GENERIC1_4             0x74a0
+#define HDMI0_GENERIC1_5             0x74a4
+#define HDMI0_GENERIC1_6             0x74a8
+#define HDMI0_ACR_32_0               0x74ac
+#       define HDMI0_ACR_CTS_32(x)   (((x) & 0xfffff) << 12)
+#define HDMI0_ACR_32_1               0x74b0
+#       define HDMI0_ACR_N_32(x)   (((x) & 0xfffff) << 0)
+#define HDMI0_ACR_44_0               0x74b4
+#       define HDMI0_ACR_CTS_44(x)   (((x) & 0xfffff) << 12)
+#define HDMI0_ACR_44_1               0x74b8
+#       define HDMI0_ACR_N_44(x)   (((x) & 0xfffff) << 0)
+#define HDMI0_ACR_48_0               0x74bc
+#       define HDMI0_ACR_CTS_48(x)   (((x) & 0xfffff) << 12)
+#define HDMI0_ACR_48_1               0x74c0
+#       define HDMI0_ACR_N_48(x)   (((x) & 0xfffff) << 0)
+#define HDMI0_ACR_STATUS_0           0x74c4
+#define HDMI0_ACR_STATUS_1           0x74c8
+#define HDMI0_AUDIO_INFO0            0x74cc
+#       define HDMI0_AUDIO_INFO_CHECKSUM(x)  (((x) & 0xff) << 0)
+#       define HDMI0_AUDIO_INFO_CC(x)  (((x) & 7) << 8)
+#define HDMI0_AUDIO_INFO1            0x74d0
+#       define HDMI0_AUDIO_INFO_CA(x)  (((x) & 0xff) << 0)
+#       define HDMI0_AUDIO_INFO_LSV(x)  (((x) & 0xf) << 11)
+#       define HDMI0_AUDIO_INFO_DM_INH(x)  (((x) & 1) << 15)
+#       define HDMI0_AUDIO_INFO_DM_INH_LSV(x)  (((x) & 0xff) << 8)
+#define HDMI0_60958_0                0x74d4
+#       define HDMI0_60958_CS_A(x)   (((x) & 1) << 0)
+#       define HDMI0_60958_CS_B(x)   (((x) & 1) << 1)
+#       define HDMI0_60958_CS_C(x)   (((x) & 1) << 2)
+#       define HDMI0_60958_CS_D(x)   (((x) & 3) << 3)
+#       define HDMI0_60958_CS_MODE(x)   (((x) & 3) << 6)
+#       define HDMI0_60958_CS_CATEGORY_CODE(x)      (((x) & 0xff) << 8)
+#       define HDMI0_60958_CS_SOURCE_NUMBER(x)      (((x) & 0xf) << 16)
+#       define HDMI0_60958_CS_CHANNEL_NUMBER_L(x)   (((x) & 0xf) << 20)
+#       define HDMI0_60958_CS_SAMPLING_FREQUENCY(x) (((x) & 0xf) << 24)
+#       define HDMI0_60958_CS_CLOCK_ACCURACY(x)     (((x) & 3) << 28)
+#define HDMI0_60958_1                0x74d8
+#       define HDMI0_60958_CS_WORD_LENGTH(x)        (((x) & 0xf) << 0)
+#       define HDMI0_60958_CS_ORIGINAL_SAMPLING_FREQUENCY(x)   (((x) & 0xf) << 4)
+#       define HDMI0_60958_CS_VALID_L(x)   (((x) & 1) << 16)
+#       define HDMI0_60958_CS_VALID_R(x)   (((x) & 1) << 18)
+#       define HDMI0_60958_CS_CHANNEL_NUMBER_R(x)   (((x) & 0xf) << 20)
+#define HDMI0_ACR_PACKET_CONTROL     0x74dc
+#       define HDMI0_ACR_SEND        (1 << 0)
+#       define HDMI0_ACR_CONT        (1 << 1)
+#       define HDMI0_ACR_SELECT(x)   (((x) & 3) << 4)
+#       define HDMI0_ACR_HW          0
+#       define HDMI0_ACR_32          1
+#       define HDMI0_ACR_44          2
+#       define HDMI0_ACR_48          3
+#       define HDMI0_ACR_SOURCE      (1 << 8) /* 0 - hw; 1 - cts value */
+#       define HDMI0_ACR_AUTO_SEND   (1 << 12)
+#define HDMI0_RAMP_CONTROL0          0x74e0
+#       define HDMI0_RAMP_MAX_COUNT(x)   (((x) & 0xffffff) << 0)
+#define HDMI0_RAMP_CONTROL1          0x74e4
+#       define HDMI0_RAMP_MIN_COUNT(x)   (((x) & 0xffffff) << 0)
+#define HDMI0_RAMP_CONTROL2          0x74e8
+#       define HDMI0_RAMP_INC_COUNT(x)   (((x) & 0xffffff) << 0)
+#define HDMI0_RAMP_CONTROL3          0x74ec
+#       define HDMI0_RAMP_DEC_COUNT(x)   (((x) & 0xffffff) << 0)
+/* HDMI0_60958_2 is r7xx only */
+#define HDMI0_60958_2                0x74f0
+#       define HDMI0_60958_CS_CHANNEL_NUMBER_2(x)   (((x) & 0xf) << 0)
+#       define HDMI0_60958_CS_CHANNEL_NUMBER_3(x)   (((x) & 0xf) << 4)
+#       define HDMI0_60958_CS_CHANNEL_NUMBER_4(x)   (((x) & 0xf) << 8)
+#       define HDMI0_60958_CS_CHANNEL_NUMBER_5(x)   (((x) & 0xf) << 12)
+#       define HDMI0_60958_CS_CHANNEL_NUMBER_6(x)   (((x) & 0xf) << 16)
+#       define HDMI0_60958_CS_CHANNEL_NUMBER_7(x)   (((x) & 0xf) << 20)
+/* r6xx only; second instance starts at 0x7700 */
+#define HDMI1_CONTROL                0x7700
+#define HDMI1_STATUS                 0x7704
+#define HDMI1_AUDIO_PACKET_CONTROL   0x7708
+/* DCE3; second instance starts at 0x7800 NOT 0x7700 */
+#define DCE3_HDMI1_CONTROL                0x7800
+#define DCE3_HDMI1_STATUS                 0x7804
+#define DCE3_HDMI1_AUDIO_PACKET_CONTROL   0x7808
+/* DCE3.2 (for interrupts) */
+#define AFMT_STATUS                          0x7600
+#       define AFMT_AUDIO_ENABLE             (1 << 4)
+#       define AFMT_AZ_FORMAT_WTRIG          (1 << 28)
+#       define AFMT_AZ_FORMAT_WTRIG_INT      (1 << 29)
+#       define AFMT_AZ_AUDIO_ENABLE_CHG      (1 << 30)
+#define AFMT_AUDIO_PACKET_CONTROL            0x7604
+#       define AFMT_AUDIO_SAMPLE_SEND        (1 << 0)
+#       define AFMT_AUDIO_TEST_EN            (1 << 12)
+#       define AFMT_AUDIO_CHANNEL_SWAP       (1 << 24)
+#       define AFMT_60958_CS_UPDATE          (1 << 26)
+#       define AFMT_AZ_AUDIO_ENABLE_CHG_MASK (1 << 27)
+#       define AFMT_AZ_FORMAT_WTRIG_MASK     (1 << 28)
+#       define AFMT_AZ_FORMAT_WTRIG_ACK      (1 << 29)
+#       define AFMT_AZ_AUDIO_ENABLE_CHG_ACK  (1 << 30)
+
+#define DCE2_HDMI_OFFSET0              (0x7400 - 0x7400)
+#define DCE2_HDMI_OFFSET1              (0x7700 - 0x7400)
+/* DCE3.2 second instance starts at 0x7800 */
+#define DCE3_HDMI_OFFSET0              (0x7400 - 0x7400)
+#define DCE3_HDMI_OFFSET1              (0x7800 - 0x7400)
+
 /*
  * PM4
  */
index 138b952..610acee 100644 (file)
@@ -560,6 +560,7 @@ struct radeon_unpin_work {
 
 struct r500_irq_stat_regs {
        u32 disp_int;
+       u32 hdmi0_status;
 };
 
 struct r600_irq_stat_regs {
@@ -568,6 +569,8 @@ struct r600_irq_stat_regs {
        u32 disp_int_cont2;
        u32 d1grph_int;
        u32 d2grph_int;
+       u32 hdmi0_status;
+       u32 hdmi1_status;
 };
 
 struct evergreen_irq_stat_regs {
@@ -583,6 +586,12 @@ struct evergreen_irq_stat_regs {
        u32 d4grph_int;
        u32 d5grph_int;
        u32 d6grph_int;
+       u32 afmt_status1;
+       u32 afmt_status2;
+       u32 afmt_status3;
+       u32 afmt_status4;
+       u32 afmt_status5;
+       u32 afmt_status6;
 };
 
 union radeon_irq_stat_regs {
@@ -593,7 +602,7 @@ union radeon_irq_stat_regs {
 
 #define RADEON_MAX_HPD_PINS 6
 #define RADEON_MAX_CRTCS 6
-#define RADEON_MAX_HDMI_BLOCKS 2
+#define RADEON_MAX_AFMT_BLOCKS 6
 
 struct radeon_irq {
        bool            installed;
@@ -605,7 +614,7 @@ struct radeon_irq {
        bool            gui_idle;
        bool            gui_idle_acked;
        wait_queue_head_t       idle_queue;
-       bool            hdmi[RADEON_MAX_HDMI_BLOCKS];
+       bool            afmt[RADEON_MAX_AFMT_BLOCKS];
        spinlock_t sw_lock;
        int sw_refcount[RADEON_NUM_RINGS];
        union radeon_irq_stat_regs stat_regs;
@@ -1105,6 +1114,15 @@ int radeon_pm_get_type_index(struct radeon_device *rdev,
                             enum radeon_pm_state_type ps_type,
                             int instance);
 
+struct r600_audio {
+       bool                    enabled;
+       int                     channels;
+       int                     rate;
+       int                     bits_per_sample;
+       u8                      status_bits;
+       u8                      category_code;
+};
+
 /*
  * Benchmarking
  */
@@ -1546,19 +1564,11 @@ struct radeon_device {
        struct r600_ih ih; /* r6/700 interrupt ring */
        struct si_rlc rlc;
        struct work_struct hotplug_work;
+       struct work_struct audio_work;
        int num_crtc; /* number of crtcs */
        struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
        struct mutex vram_mutex;
-
-       /* audio stuff */
-       bool                    audio_enabled;
-       struct timer_list       audio_timer;
-       int                     audio_channels;
-       int                     audio_rate;
-       int                     audio_bits_per_sample;
-       uint8_t                 audio_status_bits;
-       uint8_t                 audio_category_code;
-
+       struct r600_audio audio; /* audio stuff */
        struct notifier_block acpi_nb;
        /* only one userspace can use Hyperz features or CMASK at a time */
        struct drm_file *hyperz_filp;
@@ -1828,6 +1838,8 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev,
                     struct radeon_vm *vm,
                     struct radeon_bo *bo);
 
+/* audio */
+void r600_audio_update_hdmi(struct work_struct *work);
 
 /*
  * R600 vram scratch functions
index 3d9f9f1..b135bec 100644 (file)
@@ -369,9 +369,6 @@ int r600_audio_bits_per_sample(struct radeon_device *rdev);
 int r600_audio_rate(struct radeon_device *rdev);
 uint8_t r600_audio_status_bits(struct radeon_device *rdev);
 uint8_t r600_audio_category_code(struct radeon_device *rdev);
-void r600_audio_schedule_polling(struct radeon_device *rdev);
-void r600_audio_enable_polling(struct drm_encoder *encoder);
-void r600_audio_disable_polling(struct drm_encoder *encoder);
 void r600_audio_fini(struct radeon_device *rdev);
 void r600_hdmi_init(struct drm_encoder *encoder);
 int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder);
index bd05156..71fa389 100644 (file)
@@ -84,6 +84,62 @@ static void radeon_property_change_mode(struct drm_encoder *encoder)
                                         crtc->x, crtc->y, crtc->fb);
        }
 }
+
+int radeon_get_monitor_bpc(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct radeon_connector_atom_dig *dig_connector;
+       int bpc = 8;
+
+       switch (connector->connector_type) {
+       case DRM_MODE_CONNECTOR_DVII:
+       case DRM_MODE_CONNECTOR_HDMIB:
+               if (radeon_connector->use_digital) {
+                       if (drm_detect_hdmi_monitor(radeon_connector->edid)) {
+                               if (connector->display_info.bpc)
+                                       bpc = connector->display_info.bpc;
+                       }
+               }
+               break;
+       case DRM_MODE_CONNECTOR_DVID:
+       case DRM_MODE_CONNECTOR_HDMIA:
+               if (drm_detect_hdmi_monitor(radeon_connector->edid)) {
+                       if (connector->display_info.bpc)
+                               bpc = connector->display_info.bpc;
+               }
+               break;
+       case DRM_MODE_CONNECTOR_DisplayPort:
+               dig_connector = radeon_connector->con_priv;
+               if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
+                   (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) ||
+                   drm_detect_hdmi_monitor(radeon_connector->edid)) {
+                       if (connector->display_info.bpc)
+                               bpc = connector->display_info.bpc;
+               }
+               break;
+       case DRM_MODE_CONNECTOR_eDP:
+       case DRM_MODE_CONNECTOR_LVDS:
+               if (connector->display_info.bpc)
+                       bpc = connector->display_info.bpc;
+               else if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) {
+                       struct drm_connector_helper_funcs *connector_funcs =
+                               connector->helper_private;
+                       struct drm_encoder *encoder = connector_funcs->best_encoder(connector);
+                       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+                       struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+
+                       if (dig->lcd_misc & ATOM_PANEL_MISC_V13_6BIT_PER_COLOR)
+                               bpc = 6;
+                       else if (dig->lcd_misc & ATOM_PANEL_MISC_V13_8BIT_PER_COLOR)
+                               bpc = 8;
+               }
+               break;
+       }
+       return bpc;
+}
+
 static void
 radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_connector_status status)
 {
index 66d5fe1..170f171 100644 (file)
@@ -73,6 +73,7 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev)
        for (i = 0; i < RADEON_MAX_CRTCS; i++) {
                rdev->irq.crtc_vblank_int[i] = false;
                rdev->irq.pflip[i] = false;
+               rdev->irq.afmt[i] = false;
        }
        radeon_irq_set(rdev);
        /* Clear bits */
@@ -108,6 +109,7 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev)
        for (i = 0; i < RADEON_MAX_CRTCS; i++) {
                rdev->irq.crtc_vblank_int[i] = false;
                rdev->irq.pflip[i] = false;
+               rdev->irq.afmt[i] = false;
        }
        radeon_irq_set(rdev);
 }
@@ -164,6 +166,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
        int r = 0;
 
        INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
+       INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
 
        spin_lock_init(&rdev->irq.sw_lock);
        for (i = 0; i < rdev->num_crtc; i++)
index f7eb5d8..0c3cdbd 100644 (file)
@@ -384,8 +384,8 @@ struct radeon_encoder {
        struct drm_display_mode native_mode;
        void *enc_priv;
        int audio_polling_active;
+       bool hdmi_enabled;
        int hdmi_offset;
-       int hdmi_config_offset;
        int hdmi_audio_workaround;
        int hdmi_buffer_status;
        bool is_ext_encoder;
@@ -476,6 +476,7 @@ extern u16 radeon_encoder_get_dp_bridge_encoder_id(struct drm_encoder *encoder);
 extern u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector);
 extern bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector);
 extern bool radeon_connector_is_dp12_capable(struct drm_connector *connector);
+extern int radeon_get_monitor_bpc(struct drm_connector *connector);
 
 extern void radeon_connector_hotplug(struct drm_connector *connector);
 extern int radeon_dp_mode_valid_helper(struct drm_connector *connector,
index d25cf86..10706c6 100644 (file)
@@ -553,6 +553,12 @@ int rs600_irq_set(struct radeon_device *rdev)
                ~S_007D08_DC_HOT_PLUG_DETECT1_INT_EN(1);
        u32 hpd2 = RREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL) &
                ~S_007D18_DC_HOT_PLUG_DETECT2_INT_EN(1);
+       u32 hdmi0;
+       if (ASIC_IS_DCE2(rdev))
+               hdmi0 = RREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL) &
+                       ~S_007408_HDMI0_AZ_FORMAT_WTRIG_MASK(1);
+       else
+               hdmi0 = 0;
 
        if (!rdev->irq.installed) {
                WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
@@ -579,10 +585,15 @@ int rs600_irq_set(struct radeon_device *rdev)
        if (rdev->irq.hpd[1]) {
                hpd2 |= S_007D18_DC_HOT_PLUG_DETECT2_INT_EN(1);
        }
+       if (rdev->irq.afmt[0]) {
+               hdmi0 |= S_007408_HDMI0_AZ_FORMAT_WTRIG_MASK(1);
+       }
        WREG32(R_000040_GEN_INT_CNTL, tmp);
        WREG32(R_006540_DxMODE_INT_MASK, mode_int);
        WREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL, hpd1);
        WREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL, hpd2);
+       if (ASIC_IS_DCE2(rdev))
+               WREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL, hdmi0);
        return 0;
 }
 
@@ -622,6 +633,17 @@ static inline u32 rs600_irq_ack(struct radeon_device *rdev)
                rdev->irq.stat_regs.r500.disp_int = 0;
        }
 
+       if (ASIC_IS_DCE2(rdev)) {
+               rdev->irq.stat_regs.r500.hdmi0_status = RREG32(R_007404_HDMI0_STATUS) &
+                       S_007404_HDMI0_AZ_FORMAT_WTRIG(1);
+               if (G_007404_HDMI0_AZ_FORMAT_WTRIG(rdev->irq.stat_regs.r500.hdmi0_status)) {
+                       tmp = RREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL);
+                       tmp |= S_007408_HDMI0_AZ_FORMAT_WTRIG_ACK(1);
+                       WREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL, tmp);
+               }
+       } else
+               rdev->irq.stat_regs.r500.hdmi0_status = 0;
+
        if (irqs) {
                WREG32(R_000044_GEN_INT_STATUS, irqs);
        }
@@ -630,6 +652,9 @@ static inline u32 rs600_irq_ack(struct radeon_device *rdev)
 
 void rs600_irq_disable(struct radeon_device *rdev)
 {
+       u32 hdmi0 = RREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL) &
+               ~S_007408_HDMI0_AZ_FORMAT_WTRIG_MASK(1);
+       WREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL, hdmi0);
        WREG32(R_000040_GEN_INT_CNTL, 0);
        WREG32(R_006540_DxMODE_INT_MASK, 0);
        /* Wait and acknowledge irq */
@@ -641,15 +666,20 @@ int rs600_irq_process(struct radeon_device *rdev)
 {
        u32 status, msi_rearm;
        bool queue_hotplug = false;
+       bool queue_hdmi = false;
 
        /* reset gui idle ack.  the status bit is broken */
        rdev->irq.gui_idle_acked = false;
 
        status = rs600_irq_ack(rdev);
-       if (!status && !rdev->irq.stat_regs.r500.disp_int) {
+       if (!status &&
+           !rdev->irq.stat_regs.r500.disp_int &&
+           !rdev->irq.stat_regs.r500.hdmi0_status) {
                return IRQ_NONE;
        }
-       while (status || rdev->irq.stat_regs.r500.disp_int) {
+       while (status ||
+              rdev->irq.stat_regs.r500.disp_int ||
+              rdev->irq.stat_regs.r500.hdmi0_status) {
                /* SW interrupt */
                if (G_000044_SW_INT(status)) {
                        radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
@@ -687,12 +717,18 @@ int rs600_irq_process(struct radeon_device *rdev)
                        queue_hotplug = true;
                        DRM_DEBUG("HPD2\n");
                }
+               if (G_007404_HDMI0_AZ_FORMAT_WTRIG(rdev->irq.stat_regs.r500.hdmi0_status)) {
+                       queue_hdmi = true;
+                       DRM_DEBUG("HDMI0\n");
+               }
                status = rs600_irq_ack(rdev);
        }
        /* reset gui idle ack.  the status bit is broken */
        rdev->irq.gui_idle_acked = false;
        if (queue_hotplug)
                schedule_work(&rdev->hotplug_work);
+       if (queue_hdmi)
+               schedule_work(&rdev->audio_work);
        if (rdev->msi_enabled) {
                switch (rdev->family) {
                case CHIP_RS600:
index a27c13a..f1f8941 100644 (file)
 #define   S_007D18_DC_HOT_PLUG_DETECT2_INT_EN(x)       (((x) & 0x1) << 16)
 #define   G_007D18_DC_HOT_PLUG_DETECT2_INT_EN(x)       (((x) >> 16) & 0x1)
 #define   C_007D18_DC_HOT_PLUG_DETECT2_INT_EN          0xFFFEFFFF
+#define R_007404_HDMI0_STATUS                          0x007404
+#define   S_007404_HDMI0_AZ_FORMAT_WTRIG(x)            (((x) & 0x1) << 28)
+#define   G_007404_HDMI0_AZ_FORMAT_WTRIG(x)            (((x) >> 28) & 0x1)
+#define   C_007404_HDMI0_AZ_FORMAT_WTRIG               0xEFFFFFFF
+#define   S_007404_HDMI0_AZ_FORMAT_WTRIG_INT(x)        (((x) & 0x1) << 29)
+#define   G_007404_HDMI0_AZ_FORMAT_WTRIG_INT(x)        (((x) >> 29) & 0x1)
+#define   C_007404_HDMI0_AZ_FORMAT_WTRIG_INT           0xDFFFFFFF
+#define R_007408_HDMI0_AUDIO_PACKET_CONTROL            0x007408
+#define   S_007408_HDMI0_AZ_FORMAT_WTRIG_MASK(x)       (((x) & 0x1) << 28)
+#define   G_007408_HDMI0_AZ_FORMAT_WTRIG_MASK(x)       (((x) >> 28) & 0x1)
+#define   C_007408_HDMI0_AZ_FORMAT_WTRIG_MASK          0xEFFFFFFF
+#define   S_007408_HDMI0_AZ_FORMAT_WTRIG_ACK(x)        (((x) & 0x1) << 29)
+#define   G_007408_HDMI0_AZ_FORMAT_WTRIG_ACK(x)        (((x) >> 29) & 0x1)
+#define   C_007408_HDMI0_AZ_FORMAT_WTRIG_ACK           0xDFFFFFFF
 
 /* MC registers */
 #define R_000000_MC_STATUS                           0x000000
index 79fa588..9c549f7 100644 (file)
 
 #define        SRBM_STATUS                                     0x0E50
 
+/* DCE 3.2 HDMI */
+#define HDMI_CONTROL                         0x7400
+#       define HDMI_KEEPOUT_MODE             (1 << 0)
+#       define HDMI_PACKET_GEN_VERSION       (1 << 4) /* 0 = r6xx compat */
+#       define HDMI_ERROR_ACK                (1 << 8)
+#       define HDMI_ERROR_MASK               (1 << 9)
+#define HDMI_STATUS                          0x7404
+#       define HDMI_ACTIVE_AVMUTE            (1 << 0)
+#       define HDMI_AUDIO_PACKET_ERROR       (1 << 16)
+#       define HDMI_VBI_PACKET_ERROR         (1 << 20)
+#define HDMI_AUDIO_PACKET_CONTROL            0x7408
+#       define HDMI_AUDIO_DELAY_EN(x)        (((x) & 3) << 4)
+#       define HDMI_AUDIO_PACKETS_PER_LINE(x)  (((x) & 0x1f) << 16)
+#define HDMI_ACR_PACKET_CONTROL              0x740c
+#       define HDMI_ACR_SEND                 (1 << 0)
+#       define HDMI_ACR_CONT                 (1 << 1)
+#       define HDMI_ACR_SELECT(x)            (((x) & 3) << 4)
+#       define HDMI_ACR_HW                   0
+#       define HDMI_ACR_32                   1
+#       define HDMI_ACR_44                   2
+#       define HDMI_ACR_48                   3
+#       define HDMI_ACR_SOURCE               (1 << 8) /* 0 - hw; 1 - cts value */
+#       define HDMI_ACR_AUTO_SEND            (1 << 12)
+#define HDMI_VBI_PACKET_CONTROL              0x7410
+#       define HDMI_NULL_SEND                (1 << 0)
+#       define HDMI_GC_SEND                  (1 << 4)
+#       define HDMI_GC_CONT                  (1 << 5) /* 0 - once; 1 - every frame */
+#define HDMI_INFOFRAME_CONTROL0              0x7414
+#       define HDMI_AVI_INFO_SEND            (1 << 0)
+#       define HDMI_AVI_INFO_CONT            (1 << 1)
+#       define HDMI_AUDIO_INFO_SEND          (1 << 4)
+#       define HDMI_AUDIO_INFO_CONT          (1 << 5)
+#       define HDMI_MPEG_INFO_SEND           (1 << 8)
+#       define HDMI_MPEG_INFO_CONT           (1 << 9)
+#define HDMI_INFOFRAME_CONTROL1              0x7418
+#       define HDMI_AVI_INFO_LINE(x)         (((x) & 0x3f) << 0)
+#       define HDMI_AUDIO_INFO_LINE(x)       (((x) & 0x3f) << 8)
+#       define HDMI_MPEG_INFO_LINE(x)        (((x) & 0x3f) << 16)
+#define HDMI_GENERIC_PACKET_CONTROL          0x741c
+#       define HDMI_GENERIC0_SEND            (1 << 0)
+#       define HDMI_GENERIC0_CONT            (1 << 1)
+#       define HDMI_GENERIC1_SEND            (1 << 4)
+#       define HDMI_GENERIC1_CONT            (1 << 5)
+#       define HDMI_GENERIC0_LINE(x)         (((x) & 0x3f) << 16)
+#       define HDMI_GENERIC1_LINE(x)         (((x) & 0x3f) << 24)
+#define HDMI_GC                              0x7428
+#       define HDMI_GC_AVMUTE                (1 << 0)
+#define AFMT_AUDIO_PACKET_CONTROL2           0x742c
+#       define AFMT_AUDIO_LAYOUT_OVRD        (1 << 0)
+#       define AFMT_AUDIO_LAYOUT_SELECT      (1 << 1)
+#       define AFMT_60958_CS_SOURCE          (1 << 4)
+#       define AFMT_AUDIO_CHANNEL_ENABLE(x)  (((x) & 0xff) << 8)
+#       define AFMT_DP_AUDIO_STREAM_ID(x)    (((x) & 0xff) << 16)
+#define AFMT_AVI_INFO0                       0x7454
+#       define AFMT_AVI_INFO_CHECKSUM(x)     (((x) & 0xff) << 0)
+#       define AFMT_AVI_INFO_S(x)            (((x) & 3) << 8)
+#       define AFMT_AVI_INFO_B(x)            (((x) & 3) << 10)
+#       define AFMT_AVI_INFO_A(x)            (((x) & 1) << 12)
+#       define AFMT_AVI_INFO_Y(x)            (((x) & 3) << 13)
+#       define AFMT_AVI_INFO_Y_RGB           0
+#       define AFMT_AVI_INFO_Y_YCBCR422      1
+#       define AFMT_AVI_INFO_Y_YCBCR444      2
+#       define AFMT_AVI_INFO_Y_A_B_S(x)      (((x) & 0xff) << 8)
+#       define AFMT_AVI_INFO_R(x)            (((x) & 0xf) << 16)
+#       define AFMT_AVI_INFO_M(x)            (((x) & 0x3) << 20)
+#       define AFMT_AVI_INFO_C(x)            (((x) & 0x3) << 22)
+#       define AFMT_AVI_INFO_C_M_R(x)        (((x) & 0xff) << 16)
+#       define AFMT_AVI_INFO_SC(x)           (((x) & 0x3) << 24)
+#       define AFMT_AVI_INFO_Q(x)            (((x) & 0x3) << 26)
+#       define AFMT_AVI_INFO_EC(x)           (((x) & 0x3) << 28)
+#       define AFMT_AVI_INFO_ITC(x)          (((x) & 0x1) << 31)
+#       define AFMT_AVI_INFO_ITC_EC_Q_SC(x)  (((x) & 0xff) << 24)
+#define AFMT_AVI_INFO1                       0x7458
+#       define AFMT_AVI_INFO_VIC(x)          (((x) & 0x7f) << 0) /* don't use avi infoframe v1 */
+#       define AFMT_AVI_INFO_PR(x)           (((x) & 0xf) << 8) /* don't use avi infoframe v1 */
+#       define AFMT_AVI_INFO_TOP(x)          (((x) & 0xffff) << 16)
+#define AFMT_AVI_INFO2                       0x745c
+#       define AFMT_AVI_INFO_BOTTOM(x)       (((x) & 0xffff) << 0)
+#       define AFMT_AVI_INFO_LEFT(x)         (((x) & 0xffff) << 16)
+#define AFMT_AVI_INFO3                       0x7460
+#       define AFMT_AVI_INFO_RIGHT(x)        (((x) & 0xffff) << 0)
+#       define AFMT_AVI_INFO_VERSION(x)      (((x) & 3) << 24)
+#define AFMT_MPEG_INFO0                      0x7464
+#       define AFMT_MPEG_INFO_CHECKSUM(x)    (((x) & 0xff) << 0)
+#       define AFMT_MPEG_INFO_MB0(x)         (((x) & 0xff) << 8)
+#       define AFMT_MPEG_INFO_MB1(x)         (((x) & 0xff) << 16)
+#       define AFMT_MPEG_INFO_MB2(x)         (((x) & 0xff) << 24)
+#define AFMT_MPEG_INFO1                      0x7468
+#       define AFMT_MPEG_INFO_MB3(x)         (((x) & 0xff) << 0)
+#       define AFMT_MPEG_INFO_MF(x)          (((x) & 3) << 8)
+#       define AFMT_MPEG_INFO_FR(x)          (((x) & 1) << 12)
+#define AFMT_GENERIC0_HDR                    0x746c
+#define AFMT_GENERIC0_0                      0x7470
+#define AFMT_GENERIC0_1                      0x7474
+#define AFMT_GENERIC0_2                      0x7478
+#define AFMT_GENERIC0_3                      0x747c
+#define AFMT_GENERIC0_4                      0x7480
+#define AFMT_GENERIC0_5                      0x7484
+#define AFMT_GENERIC0_6                      0x7488
+#define AFMT_GENERIC1_HDR                    0x748c
+#define AFMT_GENERIC1_0                      0x7490
+#define AFMT_GENERIC1_1                      0x7494
+#define AFMT_GENERIC1_2                      0x7498
+#define AFMT_GENERIC1_3                      0x749c
+#define AFMT_GENERIC1_4                      0x74a0
+#define AFMT_GENERIC1_5                      0x74a4
+#define AFMT_GENERIC1_6                      0x74a8
+#define HDMI_ACR_32_0                        0x74ac
+#       define HDMI_ACR_CTS_32(x)            (((x) & 0xfffff) << 12)
+#define HDMI_ACR_32_1                        0x74b0
+#       define HDMI_ACR_N_32(x)              (((x) & 0xfffff) << 0)
+#define HDMI_ACR_44_0                        0x74b4
+#       define HDMI_ACR_CTS_44(x)            (((x) & 0xfffff) << 12)
+#define HDMI_ACR_44_1                        0x74b8
+#       define HDMI_ACR_N_44(x)              (((x) & 0xfffff) << 0)
+#define HDMI_ACR_48_0                        0x74bc
+#       define HDMI_ACR_CTS_48(x)            (((x) & 0xfffff) << 12)
+#define HDMI_ACR_48_1                        0x74c0
+#       define HDMI_ACR_N_48(x)              (((x) & 0xfffff) << 0)
+#define HDMI_ACR_STATUS_0                    0x74c4
+#define HDMI_ACR_STATUS_1                    0x74c8
+#define AFMT_AUDIO_INFO0                     0x74cc
+#       define AFMT_AUDIO_INFO_CHECKSUM(x)   (((x) & 0xff) << 0)
+#       define AFMT_AUDIO_INFO_CC(x)         (((x) & 7) << 8)
+#       define AFMT_AUDIO_INFO_CHECKSUM_OFFSET(x)   (((x) & 0xff) << 16)
+#define AFMT_AUDIO_INFO1                     0x74d0
+#       define AFMT_AUDIO_INFO_CA(x)         (((x) & 0xff) << 0)
+#       define AFMT_AUDIO_INFO_LSV(x)        (((x) & 0xf) << 11)
+#       define AFMT_AUDIO_INFO_DM_INH(x)     (((x) & 1) << 15)
+#       define AFMT_AUDIO_INFO_DM_INH_LSV(x) (((x) & 0xff) << 8)
+#define AFMT_60958_0                         0x74d4
+#       define AFMT_60958_CS_A(x)            (((x) & 1) << 0)
+#       define AFMT_60958_CS_B(x)            (((x) & 1) << 1)
+#       define AFMT_60958_CS_C(x)            (((x) & 1) << 2)
+#       define AFMT_60958_CS_D(x)            (((x) & 3) << 3)
+#       define AFMT_60958_CS_MODE(x)         (((x) & 3) << 6)
+#       define AFMT_60958_CS_CATEGORY_CODE(x)      (((x) & 0xff) << 8)
+#       define AFMT_60958_CS_SOURCE_NUMBER(x)      (((x) & 0xf) << 16)
+#       define AFMT_60958_CS_CHANNEL_NUMBER_L(x)   (((x) & 0xf) << 20)
+#       define AFMT_60958_CS_SAMPLING_FREQUENCY(x) (((x) & 0xf) << 24)
+#       define AFMT_60958_CS_CLOCK_ACCURACY(x)     (((x) & 3) << 28)
+#define AFMT_60958_1                         0x74d8
+#       define AFMT_60958_CS_WORD_LENGTH(x)  (((x) & 0xf) << 0)
+#       define AFMT_60958_CS_ORIGINAL_SAMPLING_FREQUENCY(x)   (((x) & 0xf) << 4)
+#       define AFMT_60958_CS_VALID_L(x)      (((x) & 1) << 16)
+#       define AFMT_60958_CS_VALID_R(x)      (((x) & 1) << 18)
+#       define AFMT_60958_CS_CHANNEL_NUMBER_R(x)   (((x) & 0xf) << 20)
+#define AFMT_AUDIO_CRC_CONTROL               0x74dc
+#       define AFMT_AUDIO_CRC_EN             (1 << 0)
+#define AFMT_RAMP_CONTROL0                   0x74e0
+#       define AFMT_RAMP_MAX_COUNT(x)        (((x) & 0xffffff) << 0)
+#       define AFMT_RAMP_DATA_SIGN           (1 << 31)
+#define AFMT_RAMP_CONTROL1                   0x74e4
+#       define AFMT_RAMP_MIN_COUNT(x)        (((x) & 0xffffff) << 0)
+#       define AFMT_AUDIO_TEST_CH_DISABLE(x) (((x) & 0xff) << 24)
+#define AFMT_RAMP_CONTROL2                   0x74e8
+#       define AFMT_RAMP_INC_COUNT(x)        (((x) & 0xffffff) << 0)
+#define AFMT_RAMP_CONTROL3                   0x74ec
+#       define AFMT_RAMP_DEC_COUNT(x)        (((x) & 0xffffff) << 0)
+#define AFMT_60958_2                         0x74f0
+#       define AFMT_60958_CS_CHANNEL_NUMBER_2(x)   (((x) & 0xf) << 0)
+#       define AFMT_60958_CS_CHANNEL_NUMBER_3(x)   (((x) & 0xf) << 4)
+#       define AFMT_60958_CS_CHANNEL_NUMBER_4(x)   (((x) & 0xf) << 8)
+#       define AFMT_60958_CS_CHANNEL_NUMBER_5(x)   (((x) & 0xf) << 12)
+#       define AFMT_60958_CS_CHANNEL_NUMBER_6(x)   (((x) & 0xf) << 16)
+#       define AFMT_60958_CS_CHANNEL_NUMBER_7(x)   (((x) & 0xf) << 20)
+#define AFMT_STATUS                          0x7600
+#       define AFMT_AUDIO_ENABLE             (1 << 4)
+#       define AFMT_AZ_FORMAT_WTRIG          (1 << 28)
+#       define AFMT_AZ_FORMAT_WTRIG_INT      (1 << 29)
+#       define AFMT_AZ_AUDIO_ENABLE_CHG      (1 << 30)
+#define AFMT_AUDIO_PACKET_CONTROL            0x7604
+#       define AFMT_AUDIO_SAMPLE_SEND        (1 << 0)
+#       define AFMT_AUDIO_TEST_EN            (1 << 12)
+#       define AFMT_AUDIO_CHANNEL_SWAP       (1 << 24)
+#       define AFMT_60958_CS_UPDATE          (1 << 26)
+#       define AFMT_AZ_AUDIO_ENABLE_CHG_MASK (1 << 27)
+#       define AFMT_AZ_FORMAT_WTRIG_MASK     (1 << 28)
+#       define AFMT_AZ_FORMAT_WTRIG_ACK      (1 << 29)
+#       define AFMT_AZ_AUDIO_ENABLE_CHG_ACK  (1 << 30)
+#define AFMT_VBI_PACKET_CONTROL              0x7608
+#       define AFMT_GENERIC0_UPDATE          (1 << 2)
+#define AFMT_INFOFRAME_CONTROL0              0x760c
+#       define AFMT_AUDIO_INFO_SOURCE        (1 << 6) /* 0 - sound block; 1 - hmdi regs */
+#       define AFMT_AUDIO_INFO_UPDATE        (1 << 7)
+#       define AFMT_MPEG_INFO_UPDATE         (1 << 10)
+#define AFMT_GENERIC0_7                      0x7610
+/* second instance starts at 0x7800 */
+#define HDMI_OFFSET0                      (0x7400 - 0x7400)
+#define HDMI_OFFSET1                      (0x7800 - 0x7400)
+
 #define D1GRPH_PRIMARY_SURFACE_ADDRESS                    0x6110
 #define D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH               0x6914
 #define D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH               0x6114
index 96c83a9..f348388 100644 (file)
@@ -21,6 +21,7 @@ config VGA_SWITCHEROO
        bool "Laptop Hybrid Graphics - GPU switching support"
        depends on X86
        depends on ACPI
+       select VGA_ARB
        help
          Many laptops released in 2008/9/10 have two GPUs with a multiplexer
          to switch between them. This adds support for dynamic switching when
index 58434e8..9d83028 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/pci.h>
 #include <linux/vga_switcheroo.h>
 
+#include <linux/vgaarb.h>
+
 struct vga_switcheroo_client {
        struct pci_dev *pdev;
        struct fb_info *fb_info;
@@ -122,7 +124,7 @@ int vga_switcheroo_register_client(struct pci_dev *pdev,
        vgasr_priv.clients[index].reprobe = reprobe;
        vgasr_priv.clients[index].can_switch = can_switch;
        vgasr_priv.clients[index].id = -1;
-       if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)
+       if (pdev == vga_default_device())
                vgasr_priv.clients[index].active = true;
 
        vgasr_priv.registered_clients |= (1 << index);
@@ -230,9 +232,8 @@ static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
        if (new_client->pwr_state == VGA_SWITCHEROO_OFF)
                vga_switchon(new_client);
 
-       /* swap shadow resource to denote boot VGA device has changed so X starts on new device */
-       active->pdev->resource[PCI_ROM_RESOURCE].flags &= ~IORESOURCE_ROM_SHADOW;
-       new_client->pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
+       vga_set_default_device(new_client->pdev);
+
        return 0;
 }
 
index 111d956..3df8fc0 100644 (file)
@@ -136,6 +136,13 @@ struct pci_dev *vga_default_device(void)
 {
        return vga_default;
 }
+
+EXPORT_SYMBOL_GPL(vga_default_device);
+
+void vga_set_default_device(struct pci_dev *pdev)
+{
+       vga_default = pdev;
+}
 #endif
 
 static inline void vga_irq_set_state(struct vga_device *vgadev, bool state)
@@ -605,10 +612,12 @@ static bool vga_arbiter_del_pci_device(struct pci_dev *pdev)
                goto bail;
        }
 
+#ifndef __ARCH_HAS_VGA_DEFAULT_DEVICE
        if (vga_default == pdev) {
                pci_dev_put(vga_default);
                vga_default = NULL;
        }
+#endif
 
        if (vgadev->decodes & (VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM))
                vga_decode_count--;
index a55e248..86c63fe 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/security.h>
 #include <linux/pci-aspm.h>
 #include <linux/slab.h>
+#include <linux/vgaarb.h>
 #include "pci.h"
 
 static int sysfs_initialized;  /* = 0 */
@@ -417,6 +418,10 @@ static ssize_t
 boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
+       struct pci_dev *vga_dev = vga_default_device();
+
+       if (vga_dev)
+               return sprintf(buf, "%u\n", (pdev == vga_dev));
 
        return sprintf(buf, "%u\n",
                !!(pdev->resource[PCI_ROM_RESOURCE].flags &
index 784139a..b4a632a 100644 (file)
@@ -18,6 +18,8 @@
 
 static bool request_mem_succeeded = false;
 
+static struct pci_dev *default_vga;
+
 static struct fb_var_screeninfo efifb_defined __devinitdata = {
        .activate               = FB_ACTIVATE_NOW,
        .height                 = -1,
@@ -298,35 +300,72 @@ static struct fb_ops efifb_ops = {
        .fb_imageblit   = cfb_imageblit,
 };
 
+struct pci_dev *vga_default_device(void)
+{
+       return default_vga;
+}
+
+EXPORT_SYMBOL_GPL(vga_default_device);
+
+void vga_set_default_device(struct pci_dev *pdev)
+{
+       default_vga = pdev;
+}
+
 static int __init efifb_setup(char *options)
 {
        char *this_opt;
        int i;
+       struct pci_dev *dev = NULL;
+
+       if (options && *options) {
+               while ((this_opt = strsep(&options, ",")) != NULL) {
+                       if (!*this_opt) continue;
+
+                       for (i = 0; i < M_UNKNOWN; i++) {
+                               if (!strcmp(this_opt, dmi_list[i].optname) &&
+                                   dmi_list[i].base != 0) {
+                                       screen_info.lfb_base = dmi_list[i].base;
+                                       screen_info.lfb_linelength = dmi_list[i].stride;
+                                       screen_info.lfb_width = dmi_list[i].width;
+                                       screen_info.lfb_height = dmi_list[i].height;
+                               }
+                       }
+                       if (!strncmp(this_opt, "base:", 5))
+                               screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0);
+                       else if (!strncmp(this_opt, "stride:", 7))
+                               screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4;
+                       else if (!strncmp(this_opt, "height:", 7))
+                               screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0);
+                       else if (!strncmp(this_opt, "width:", 6))
+                               screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
+               }
+       }
 
-       if (!options || !*options)
-               return 0;
+       for_each_pci_dev(dev) {
+               int i;
 
-       while ((this_opt = strsep(&options, ",")) != NULL) {
-               if (!*this_opt) continue;
+               if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
+                       continue;
 
-               for (i = 0; i < M_UNKNOWN; i++) {
-                       if (!strcmp(this_opt, dmi_list[i].optname) &&
-                                       dmi_list[i].base != 0) {
-                               screen_info.lfb_base = dmi_list[i].base;
-                               screen_info.lfb_linelength = dmi_list[i].stride;
-                               screen_info.lfb_width = dmi_list[i].width;
-                               screen_info.lfb_height = dmi_list[i].height;
-                       }
+               for (i=0; i < DEVICE_COUNT_RESOURCE; i++) {
+                       resource_size_t start, end;
+
+                       if (!(pci_resource_flags(dev, i) & IORESOURCE_MEM))
+                               continue;
+
+                       start = pci_resource_start(dev, i);
+                       end  = pci_resource_end(dev, i);
+
+                       if (!start || !end)
+                               continue;
+
+                       if (screen_info.lfb_base >= start &&
+                           (screen_info.lfb_base + screen_info.lfb_size) < end)
+                               default_vga = dev;
                }
-               if (!strncmp(this_opt, "base:", 5))
-                       screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0);
-               else if (!strncmp(this_opt, "stride:", 7))
-                       screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4;
-               else if (!strncmp(this_opt, "height:", 7))
-                       screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0);
-               else if (!strncmp(this_opt, "width:", 6))
-                       screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
        }
+
        return 0;
 }
 
index e250eda..f35e7ed 100644 (file)
@@ -1012,10 +1012,11 @@ extern int drm_add_modes_noedid(struct drm_connector *connector,
                                int hdisplay, int vdisplay);
 
 extern int drm_edid_header_is_valid(const u8 *raw_edid);
-extern bool drm_edid_block_valid(u8 *raw_edid);
+extern bool drm_edid_block_valid(u8 *raw_edid, int block);
 extern bool drm_edid_is_valid(struct edid *edid);
 struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
-                                          int hsize, int vsize, int fresh);
+                                          int hsize, int vsize, int fresh,
+                                          bool rb);
 
 extern int drm_mode_create_dumb_ioctl(struct drm_device *dev,
                                      void *data, struct drm_file *file_priv);
@@ -1026,4 +1027,9 @@ extern int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
 
 extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
                                 int *bpp);
+extern int drm_format_num_planes(uint32_t format);
+extern int drm_format_plane_cpp(uint32_t format, int plane);
+extern int drm_format_horz_chroma_subsampling(uint32_t format);
+extern int drm_format_vert_chroma_subsampling(uint32_t format);
+
 #endif /* __DRM_CRTC_H__ */
index 37515d1..3add00e 100644 (file)
@@ -145,6 +145,4 @@ extern void drm_helper_hpd_irq_event(struct drm_device *dev);
 extern void drm_kms_helper_poll_disable(struct drm_device *dev);
 extern void drm_kms_helper_poll_enable(struct drm_device *dev);
 
-extern int drm_format_num_planes(uint32_t format);
-
 #endif
index bcb9a66..0cac551 100644 (file)
@@ -90,12 +90,26 @@ struct detailed_data_monitor_range {
        u8 min_hfreq_khz;
        u8 max_hfreq_khz;
        u8 pixel_clock_mhz; /* need to multiply by 10 */
-       __le16 sec_gtf_toggle; /* A000=use above, 20=use below */
-       u8 hfreq_start_khz; /* need to multiply by 2 */
-       u8 c; /* need to divide by 2 */
-       __le16 m;
-       u8 k;
-       u8 j; /* need to divide by 2 */
+       u8 flags;
+       union {
+               struct {
+                       u8 reserved;
+                       u8 hfreq_start_khz; /* need to multiply by 2 */
+                       u8 c; /* need to divide by 2 */
+                       __le16 m;
+                       u8 k;
+                       u8 j; /* need to divide by 2 */
+               } __attribute__((packed)) gtf2;
+               struct {
+                       u8 version;
+                       u8 data1; /* high 6 bits: extra clock resolution */
+                       u8 data2; /* plus low 2 of above: max hactive */
+                       u8 supported_aspects;
+                       u8 flags; /* preferred aspect and blanking support */
+                       u8 supported_scalings;
+                       u8 preferred_refresh;
+               } __attribute__((packed)) cvt;
+       } formula;
 } __attribute__((packed));
 
 struct detailed_data_wpindex {
index 4a08a66..0ead502 100644 (file)
@@ -37,6 +37,7 @@ typedef union dfixed {
 #define dfixed_init(A) { .full = dfixed_const((A)) }
 #define dfixed_init_half(A) { .full = dfixed_const_half((A)) }
 #define dfixed_trunc(A) ((A).full >> 12)
+#define dfixed_frac(A) ((A).full & ((1 << 12) - 1))
 
 static inline u32 dfixed_floor(fixed20_12 A)
 {
index c93a9a9..efa26b4 100644 (file)
@@ -461,7 +461,7 @@ static inline int fault_in_pages_readable(const char __user *uaddr, int size)
 static inline int fault_in_multipages_writeable(char __user *uaddr, int size)
 {
        int ret;
-       const char __user *end = uaddr + size - 1;
+       char __user *end = uaddr + size - 1;
 
        if (unlikely(size == 0))
                return 0;
index b572f80..367ab18 100644 (file)
@@ -31,6 +31,7 @@
 #ifndef LINUX_VGA_H
 #define LINUX_VGA_H
 
+#include <video/vga.h>
 
 /* Legacy VGA regions */
 #define VGA_RSRC_NONE         0x00
@@ -183,6 +184,7 @@ extern void vga_put(struct pci_dev *pdev, unsigned int rsrc);
 
 #ifndef __ARCH_HAS_VGA_DEFAULT_DEVICE
 extern struct pci_dev *vga_default_device(void);
+extern void vga_set_default_device(struct pci_dev *pdev);
 #endif
 
 /**