Merge branch 'for-airlied' of git://people.freedesktop.org/~danvet/drm-intel into...
authorDave Airlie <airlied@gmail.com>
Wed, 19 Sep 2012 10:00:10 +0000 (20:00 +1000)
committerDave Airlie <airlied@gmail.com>
Wed, 19 Sep 2012 10:00:10 +0000 (20:00 +1000)
Daniel writes:
"The big ticket item here is the new i915 modeset infrastructure.
Shockingly it didn't not blow up all over the place (i.e. I've managed to
fix the ugly issues before merging). 1-2 smaller corner cases broke, but
we have patches. Also, there's tons of patches on top of this that clean
out cruft and fix a few bugs that couldn't be fixed with the crtc helper
based stuff. So more stuff to come ;-)

Also a few other things:
- Tiny fix in the fb helper to go through the official dpms interface
  instead of calling the crtc helper code.
- forcewake code frobbery from Ben, code should be more in-line with
  what Windows does now.
- fixes for the render ring flush on hsw (Paulo)
- gpu frequency tracepoint
- vlv forcewake changes to better align it with our understanding of the
  forcewake magic.
- a few smaller cleanups"

+ 2 fixes.

* 'for-airlied' of git://people.freedesktop.org/~danvet/drm-intel: (78 commits)
  drm/i915: fix OOPS in lid_notify
  drm/i915: correctly update crtc->x/y in set_base
  drm/fb helper: don't call drm_helper_connector_dpms directly
  drm/i915: improve modeset state checking after dpms calls
  drm/i915: add tons of modeset state checks
  drm/i915: no longer call drm_helper_resume_force_mode
  drm/i915: disable all crtcs at suspend time
  drm/i915: push commit_output_state past the crtc/encoder preparing
  drm/i915: switch the load detect code to the staged modeset config
  drm/i915: WARN if the pipe won't turn off
  drm/i915: s/intel_encoder_disable/intel_encoder_noop
  drm/i915: push commit_output_state past crtc disabling
  drm/i915: implement new set_mode code flow
  drm/i915: compute masks of crtcs affected in set_mode
  drm/i915: use staged outuput config in lvds->mode_fixup
  drm/i915: use staged outuput config in tv->mode_fixup
  drm/i915: extract adjusted mode computation
  drm/i915: move output commit and crtc disabling into set_mode
  drm/i915: remove crtc disabling special case
  drm/i915: push crtc->fb update into pipe_set_base
  ...

35 files changed:
drivers/gpu/drm/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/drm_cache.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_drv.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_cma_helper.c [new file with mode: 0644]
drivers/gpu/drm/drm_gem_cma_helper.c [new file with mode: 0644]
drivers/gpu/drm/drm_vm.c
drivers/gpu/drm/gma500/cdv_intel_hdmi.c
drivers/gpu/drm/nouveau/nouveau_dp.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/shmobile/Kconfig [new file with mode: 0644]
drivers/gpu/drm/shmobile/Makefile [new file with mode: 0644]
drivers/gpu/drm/shmobile/shmob_drm_backlight.c [new file with mode: 0644]
drivers/gpu/drm/shmobile/shmob_drm_backlight.h [new file with mode: 0644]
drivers/gpu/drm/shmobile/shmob_drm_crtc.c [new file with mode: 0644]
drivers/gpu/drm/shmobile/shmob_drm_crtc.h [new file with mode: 0644]
drivers/gpu/drm/shmobile/shmob_drm_drv.c [new file with mode: 0644]
drivers/gpu/drm/shmobile/shmob_drm_drv.h [new file with mode: 0644]
drivers/gpu/drm/shmobile/shmob_drm_kms.c [new file with mode: 0644]
drivers/gpu/drm/shmobile/shmob_drm_kms.h [new file with mode: 0644]
drivers/gpu/drm/shmobile/shmob_drm_plane.c [new file with mode: 0644]
drivers/gpu/drm/shmobile/shmob_drm_plane.h [new file with mode: 0644]
drivers/gpu/drm/shmobile/shmob_drm_regs.h [new file with mode: 0644]
drivers/gpu/drm/udl/udl_main.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
include/drm/drm_crtc.h
include/drm/drm_fb_cma_helper.h [new file with mode: 0644]
include/drm/drm_fourcc.h
include/drm/drm_gem_cma_helper.h [new file with mode: 0644]
include/linux/platform_data/shmob_drm.h [new file with mode: 0644]

index 3a8c68345fe2b3e9142430a442511662ec2430a5..18321b68b88069f3e5588bf23fabd83c268e0359 100644 (file)
@@ -22,9 +22,8 @@ menuconfig DRM
 config DRM_USB
        tristate
        depends on DRM
-       depends on USB_ARCH_HAS_HCD
+       depends on USB_SUPPORT && USB_ARCH_HAS_HCD
        select USB
-       select USB_SUPPORT
 
 config DRM_KMS_HELPER
        tristate
@@ -55,6 +54,21 @@ config DRM_TTM
          GPU memory types. Will be enabled automatically if a device driver
          uses it.
 
+config DRM_GEM_CMA_HELPER
+       bool
+       depends on DRM
+       help
+         Choose this if you need the GEM CMA helper functions
+
+config DRM_KMS_CMA_HELPER
+       bool
+       select DRM_GEM_CMA_HELPER
+       select FB_SYS_FILLRECT
+       select FB_SYS_COPYAREA
+       select FB_SYS_IMAGEBLIT
+       help
+         Choose this if you need the KMS CMA helper functions
+
 config DRM_TDFX
        tristate "3dfx Banshee/Voodoo3+"
        depends on DRM && PCI
@@ -194,3 +208,5 @@ source "drivers/gpu/drm/ast/Kconfig"
 source "drivers/gpu/drm/mgag200/Kconfig"
 
 source "drivers/gpu/drm/cirrus/Kconfig"
+
+source "drivers/gpu/drm/shmobile/Kconfig"
index f65f65ed0ddfc8542f42ea578978ab5db367ceac..2ff5cefe9eadd106fe1e611c19388d097716ccb8 100644 (file)
@@ -15,11 +15,13 @@ drm-y       :=      drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
                drm_trace_points.o drm_global.o drm_prime.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
+drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
 
 drm-usb-y   := drm_usb.o
 
 drm_kms_helper-y := drm_fb_helper.o drm_crtc_helper.o drm_dp_i2c_helper.o
 drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
+drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o
 
 obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
 
@@ -45,4 +47,5 @@ obj-$(CONFIG_DRM_EXYNOS) +=exynos/
 obj-$(CONFIG_DRM_GMA500) += gma500/
 obj-$(CONFIG_DRM_UDL) += udl/
 obj-$(CONFIG_DRM_AST) += ast/
+obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
 obj-y                  += i2c/
index 08758e061478eb77e2db77794d1d5e54c8625474..3dbc7f17eb1146a00cba823151dc2ea8f83ac2a1 100644 (file)
@@ -37,12 +37,13 @@ drm_clflush_page(struct page *page)
 {
        uint8_t *page_virtual;
        unsigned int i;
+       const int size = boot_cpu_data.x86_clflush_size;
 
        if (unlikely(page == NULL))
                return;
 
        page_virtual = kmap_atomic(page);
-       for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size)
+       for (i = 0; i < PAGE_SIZE; i += size)
                clflush(page_virtual + i);
        kunmap_atomic(page_virtual);
 }
index 08a7aa722d6b8f0d798b7a59ccd5b8146183f497..28d0900d7f89767f302f39b69b9b3bb962583e90 100644 (file)
@@ -2169,6 +2169,8 @@ static int format_check(const struct drm_mode_fb_cmd2 *r)
        case DRM_FORMAT_NV21:
        case DRM_FORMAT_NV16:
        case DRM_FORMAT_NV61:
+       case DRM_FORMAT_NV24:
+       case DRM_FORMAT_NV42:
        case DRM_FORMAT_YUV410:
        case DRM_FORMAT_YVU410:
        case DRM_FORMAT_YUV411:
@@ -3718,6 +3720,8 @@ int drm_format_num_planes(uint32_t format)
        case DRM_FORMAT_NV21:
        case DRM_FORMAT_NV16:
        case DRM_FORMAT_NV61:
+       case DRM_FORMAT_NV24:
+       case DRM_FORMAT_NV42:
                return 2;
        default:
                return 1;
@@ -3751,6 +3755,8 @@ int drm_format_plane_cpp(uint32_t format, int plane)
        case DRM_FORMAT_NV21:
        case DRM_FORMAT_NV16:
        case DRM_FORMAT_NV61:
+       case DRM_FORMAT_NV24:
+       case DRM_FORMAT_NV42:
                return plane ? 2 : 1;
        case DRM_FORMAT_YUV410:
        case DRM_FORMAT_YVU410:
index 9238de4009fa15a31613d6f86185e0624810f69e..1490e764eddf9ab5d96d2ccc4a3f9502f405cb48 100644 (file)
@@ -156,14 +156,14 @@ static struct drm_ioctl_desc drm_ioctls[] = {
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 };
index bcc472572cd09741e38683f4a7d9c62cec5f1c3e..de2a0ed8e9456ead489ae6ed5995f100621b31e1 100644 (file)
@@ -158,7 +158,7 @@ MODULE_PARM_DESC(edid_fixup,
  * 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, int block)
+bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid)
 {
        int i;
        u8 csum = 0;
@@ -181,7 +181,9 @@ bool drm_edid_block_valid(u8 *raw_edid, int block)
        for (i = 0; i < EDID_LENGTH; i++)
                csum += raw_edid[i];
        if (csum) {
-               DRM_ERROR("EDID checksum is invalid, remainder is %d\n", csum);
+               if (print_bad_edid) {
+                       DRM_ERROR("EDID checksum is invalid, remainder is %d\n", csum);
+               }
 
                /* allow CEA to slide through, switches mangle this */
                if (raw_edid[0] != 0x02)
@@ -207,7 +209,7 @@ bool drm_edid_block_valid(u8 *raw_edid, int block)
        return 1;
 
 bad:
-       if (raw_edid) {
+       if (raw_edid && print_bad_edid) {
                printk(KERN_ERR "Raw EDID:\n");
                print_hex_dump(KERN_ERR, " \t", DUMP_PREFIX_NONE, 16, 1,
                               raw_edid, EDID_LENGTH, false);
@@ -231,7 +233,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, i))
+               if (!drm_edid_block_valid(raw + i * EDID_LENGTH, i, true))
                        return false;
 
        return true;
@@ -254,6 +256,8 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
                      int block, int len)
 {
        unsigned char start = block * EDID_LENGTH;
+       unsigned char segment = block >> 1;
+       unsigned char xfers = segment ? 3 : 2;
        int ret, retries = 5;
 
        /* The core i2c driver will automatically retry the transfer if the
@@ -265,6 +269,11 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
        do {
                struct i2c_msg msgs[] = {
                        {
+                               .addr   = DDC_SEGMENT_ADDR,
+                               .flags  = 0,
+                               .len    = 1,
+                               .buf    = &segment,
+                       }, {
                                .addr   = DDC_ADDR,
                                .flags  = 0,
                                .len    = 1,
@@ -276,15 +285,21 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
                                .buf    = buf,
                        }
                };
-               ret = i2c_transfer(adapter, msgs, 2);
+
+       /*
+        * Avoid sending the segment addr to not upset non-compliant ddc
+        * monitors.
+        */
+               ret = i2c_transfer(adapter, &msgs[3 - xfers], xfers);
+
                if (ret == -ENXIO) {
                        DRM_DEBUG_KMS("drm: skipping non-existent adapter %s\n",
                                        adapter->name);
                        break;
                }
-       } while (ret != 2 && --retries);
+       } while (ret != xfers && --retries);
 
-       return ret == 2 ? 0 : -1;
+       return ret == xfers ? 0 : -1;
 }
 
 static bool drm_edid_is_zero(u8 *in_edid, int length)
@@ -303,6 +318,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
 {
        int i, j = 0, valid_extensions = 0;
        u8 *block, *new;
+       bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS);
 
        if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
                return NULL;
@@ -311,7 +327,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, 0))
+               if (drm_edid_block_valid(block, 0, print_bad_edid))
                        break;
                if (i == 0 && drm_edid_is_zero(block, EDID_LENGTH)) {
                        connector->null_edid_counter++;
@@ -336,7 +352,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, j)) {
+                       if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH, j, print_bad_edid)) {
                                valid_extensions++;
                                break;
                        }
@@ -359,8 +375,11 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
        return block;
 
 carp:
-       dev_warn(connector->dev->dev, "%s: EDID block %d invalid.\n",
-                drm_get_connector_name(connector), j);
+       if (print_bad_edid) {
+               dev_warn(connector->dev->dev, "%s: EDID block %d invalid.\n",
+                        drm_get_connector_name(connector), j);
+       }
+       connector->bad_edid_counter++;
 
 out:
        kfree(block);
@@ -1516,6 +1535,40 @@ do_cea_modes (struct drm_connector *connector, u8 *db, u8 len)
        return modes;
 }
 
+static int
+cea_db_payload_len(const u8 *db)
+{
+       return db[0] & 0x1f;
+}
+
+static int
+cea_db_tag(const u8 *db)
+{
+       return db[0] >> 5;
+}
+
+static int
+cea_revision(const u8 *cea)
+{
+       return cea[1];
+}
+
+static int
+cea_db_offsets(const u8 *cea, int *start, int *end)
+{
+       /* Data block offset in CEA extension block */
+       *start = 4;
+       *end = cea[2];
+       if (*end == 0)
+               *end = 127;
+       if (*end < 4 || *end > 127)
+               return -ERANGE;
+       return 0;
+}
+
+#define for_each_cea_db(cea, i, start, end) \
+       for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1)
+
 static int
 add_cea_modes(struct drm_connector *connector, struct edid *edid)
 {
@@ -1523,10 +1576,17 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid)
        u8 * db, dbl;
        int modes = 0;
 
-       if (cea && cea[1] >= 3) {
-               for (db = cea + 4; db < cea + cea[2]; db += dbl + 1) {
-                       dbl = db[0] & 0x1f;
-                       if (((db[0] & 0xe0) >> 5) == VIDEO_BLOCK)
+       if (cea && cea_revision(cea) >= 3) {
+               int i, start, end;
+
+               if (cea_db_offsets(cea, &start, &end))
+                       return 0;
+
+               for_each_cea_db(cea, i, start, end) {
+                       db = &cea[i];
+                       dbl = cea_db_payload_len(db);
+
+                       if (cea_db_tag(db) == VIDEO_BLOCK)
                                modes += do_cea_modes (connector, db+1, dbl);
                }
        }
@@ -1535,19 +1595,28 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid)
 }
 
 static void
-parse_hdmi_vsdb(struct drm_connector *connector, uint8_t *db)
+parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db)
 {
-       connector->eld[5] |= (db[6] >> 7) << 1;  /* Supports_AI */
+       u8 len = cea_db_payload_len(db);
 
-       connector->dvi_dual = db[6] & 1;
-       connector->max_tmds_clock = db[7] * 5;
-
-       connector->latency_present[0] = db[8] >> 7;
-       connector->latency_present[1] = (db[8] >> 6) & 1;
-       connector->video_latency[0] = db[9];
-       connector->audio_latency[0] = db[10];
-       connector->video_latency[1] = db[11];
-       connector->audio_latency[1] = db[12];
+       if (len >= 6) {
+               connector->eld[5] |= (db[6] >> 7) << 1;  /* Supports_AI */
+               connector->dvi_dual = db[6] & 1;
+       }
+       if (len >= 7)
+               connector->max_tmds_clock = db[7] * 5;
+       if (len >= 8) {
+               connector->latency_present[0] = db[8] >> 7;
+               connector->latency_present[1] = (db[8] >> 6) & 1;
+       }
+       if (len >= 9)
+               connector->video_latency[0] = db[9];
+       if (len >= 10)
+               connector->audio_latency[0] = db[10];
+       if (len >= 11)
+               connector->video_latency[1] = db[11];
+       if (len >= 12)
+               connector->audio_latency[1] = db[12];
 
        DRM_LOG_KMS("HDMI: DVI dual %d, "
                    "max TMDS clock %d, "
@@ -1571,6 +1640,21 @@ monitor_name(struct detailed_timing *t, void *data)
                *(u8 **)data = t->data.other_data.data.str.str;
 }
 
+static bool cea_db_is_hdmi_vsdb(const u8 *db)
+{
+       int hdmi_id;
+
+       if (cea_db_tag(db) != VENDOR_BLOCK)
+               return false;
+
+       if (cea_db_payload_len(db) < 5)
+               return false;
+
+       hdmi_id = db[1] | (db[2] << 8) | (db[3] << 16);
+
+       return hdmi_id == HDMI_IDENTIFIER;
+}
+
 /**
  * drm_edid_to_eld - build ELD from EDID
  * @connector: connector corresponding to the HDMI/DP sink
@@ -1617,29 +1701,40 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
        eld[18] = edid->prod_code[0];
        eld[19] = edid->prod_code[1];
 
-       if (cea[1] >= 3)
-               for (db = cea + 4; db < cea + cea[2]; db += dbl + 1) {
-                       dbl = db[0] & 0x1f;
-                       
-                       switch ((db[0] & 0xe0) >> 5) {
+       if (cea_revision(cea) >= 3) {
+               int i, start, end;
+
+               if (cea_db_offsets(cea, &start, &end)) {
+                       start = 0;
+                       end = 0;
+               }
+
+               for_each_cea_db(cea, i, start, end) {
+                       db = &cea[i];
+                       dbl = cea_db_payload_len(db);
+
+                       switch (cea_db_tag(db)) {
                        case AUDIO_BLOCK:
                                /* Audio Data Block, contains SADs */
                                sad_count = dbl / 3;
-                               memcpy(eld + 20 + mnl, &db[1], dbl);
+                               if (dbl >= 1)
+                                       memcpy(eld + 20 + mnl, &db[1], dbl);
                                break;
                        case SPEAKER_BLOCK:
-                                /* Speaker Allocation Data Block */
-                               eld[7] = db[1];
+                               /* Speaker Allocation Data Block */
+                               if (dbl >= 1)
+                                       eld[7] = db[1];
                                break;
                        case VENDOR_BLOCK:
                                /* HDMI Vendor-Specific Data Block */
-                               if (db[1] == 0x03 && db[2] == 0x0c && db[3] == 0)
+                               if (cea_db_is_hdmi_vsdb(db))
                                        parse_hdmi_vsdb(connector, db);
                                break;
                        default:
                                break;
                        }
                }
+       }
        eld[5] |= sad_count << 4;
        eld[2] = (20 + mnl + sad_count * 3 + 3) / 4;
 
@@ -1717,38 +1812,26 @@ EXPORT_SYMBOL(drm_select_eld);
 bool drm_detect_hdmi_monitor(struct edid *edid)
 {
        u8 *edid_ext;
-       int i, hdmi_id;
+       int i;
        int start_offset, end_offset;
-       bool is_hdmi = false;
 
        edid_ext = drm_find_cea_extension(edid);
        if (!edid_ext)
-               goto end;
+               return false;
 
-       /* Data block offset in CEA extension block */
-       start_offset = 4;
-       end_offset = edid_ext[2];
+       if (cea_db_offsets(edid_ext, &start_offset, &end_offset))
+               return false;
 
        /*
         * Because HDMI identifier is in Vendor Specific Block,
         * search it from all data blocks of CEA extension.
         */
-       for (i = start_offset; i < end_offset;
-               /* Increased by data block len */
-               i += ((edid_ext[i] & 0x1f) + 1)) {
-               /* Find vendor specific block */
-               if ((edid_ext[i] >> 5) == VENDOR_BLOCK) {
-                       hdmi_id = edid_ext[i + 1] | (edid_ext[i + 2] << 8) |
-                                 edid_ext[i + 3] << 16;
-                       /* Find HDMI identifier */
-                       if (hdmi_id == HDMI_IDENTIFIER)
-                               is_hdmi = true;
-                       break;
-               }
+       for_each_cea_db(edid_ext, i, start_offset, end_offset) {
+               if (cea_db_is_hdmi_vsdb(&edid_ext[i]))
+                       return true;
        }
 
-end:
-       return is_hdmi;
+       return false;
 }
 EXPORT_SYMBOL(drm_detect_hdmi_monitor);
 
@@ -1780,15 +1863,13 @@ bool drm_detect_monitor_audio(struct edid *edid)
                goto end;
        }
 
-       /* Data block offset in CEA extension block */
-       start_offset = 4;
-       end_offset = edid_ext[2];
+       if (cea_db_offsets(edid_ext, &start_offset, &end_offset))
+               goto end;
 
-       for (i = start_offset; i < end_offset;
-                       i += ((edid_ext[i] & 0x1f) + 1)) {
-               if ((edid_ext[i] >> 5) == AUDIO_BLOCK) {
+       for_each_cea_db(edid_ext, i, start_offset, end_offset) {
+               if (cea_db_tag(&edid_ext[i]) == AUDIO_BLOCK) {
                        has_audio = true;
-                       for (j = 1; j < (edid_ext[i] & 0x1f); j += 3)
+                       for (j = 1; j < cea_db_payload_len(&edid_ext[i]) + 1; j += 3)
                                DRM_DEBUG_KMS("CEA audio format %d\n",
                                              (edid_ext[i + j] >> 3) & 0xf);
                        goto end;
index 186832e1874ed071f575c19c0874ae50d2d3e760..ea9cdab3d43164fb55ea81bf55338ec26a408478 100644 (file)
@@ -123,6 +123,7 @@ static u8 *edid_load(struct drm_connector *connector, char *name,
        int fwsize, expected;
        int builtin = 0, err = 0;
        int i, valid_extensions = 0;
+       bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS);
 
        pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
        if (IS_ERR(pdev)) {
@@ -173,7 +174,8 @@ static u8 *edid_load(struct drm_connector *connector, char *name,
        }
        memcpy(edid, fwdata, fwsize);
 
-       if (!drm_edid_block_valid(edid, 0)) {
+       if (!drm_edid_block_valid(edid, 0, print_bad_edid)) {
+               connector->bad_edid_counter++;
                DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
                    name);
                kfree(edid);
@@ -185,7 +187,7 @@ static u8 *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, i))
+               if (drm_edid_block_valid(edid + i * EDID_LENGTH, i, print_bad_edid))
                        valid_extensions++;
        }
 
index ff98a7eb38ddd24ff82358b784e1569c92eaf05f..57459b316adc9cb25ee7e592d91de45e9323bb91 100644 (file)
@@ -89,7 +89,7 @@ static const struct drm_display_mode drm_dmt_modes[] = {
                   976, 1088, 0, 480, 486, 494, 517, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
        /* 1024x768@43Hz, interlace */
-       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 44900, 1024, 1032,
+       { DRM_MODE("1024x768i", DRM_MODE_TYPE_DRIVER, 44900, 1024, 1032,
                   1208, 1264, 0, 768, 768, 772, 817, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
@@ -395,7 +395,7 @@ static const struct drm_display_mode edid_est_modes[] = {
        { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
                   1184, 1344, 0,  768, 771, 777, 806, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@60Hz */
-       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032,
+       { DRM_MODE("1024x768i", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032,
                   1208, 1264, 0, 768, 768, 776, 817, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */
        { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864,
@@ -506,17 +506,17 @@ static const struct drm_display_mode edid_cea_modes[] = {
                   1430, 1650, 0, 720, 725, 730, 750, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
        /* 5 - 1920x1080i@60Hz */
-       { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
+       { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
                   2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
        /* 6 - 1440x480i@60Hz */
-       { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
+       { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
                   1602, 1716, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
        /* 7 - 1440x480i@60Hz */
-       { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
+       { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
                   1602, 1716, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
@@ -531,12 +531,12 @@ static const struct drm_display_mode edid_cea_modes[] = {
                   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,
+       { DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
                   3204, 3432, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
        /* 11 - 2880x480i@60Hz */
-       { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
+       { DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
                   3204, 3432, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
@@ -573,17 +573,17 @@ static const struct drm_display_mode edid_cea_modes[] = {
                   1760, 1980, 0, 720, 725, 730, 750, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
        /* 20 - 1920x1080i@50Hz */
-       { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
+       { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
                   2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
        /* 21 - 1440x576i@50Hz */
-       { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
+       { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
                   1590, 1728, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
        /* 22 - 1440x576i@50Hz */
-       { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
+       { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
                   1590, 1728, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
@@ -598,12 +598,12 @@ static const struct drm_display_mode edid_cea_modes[] = {
                   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,
+       { DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
                   3180, 3456, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
        /* 26 - 2880x576i@50Hz */
-       { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
+       { DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
                   3180, 3456, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
@@ -656,12 +656,12 @@ static const struct drm_display_mode edid_cea_modes[] = {
                   3184, 3456, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 39 - 1920x1080i@50Hz */
-       { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952,
+       { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952,
                   2120, 2304, 0, 1080, 1126, 1136, 1250, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
        /* 40 - 1920x1080i@100Hz */
-       { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
+       { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
                   2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
@@ -688,7 +688,7 @@ static const struct drm_display_mode edid_cea_modes[] = {
                   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,
+       { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
                   2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE) },
@@ -705,12 +705,12 @@ static const struct drm_display_mode edid_cea_modes[] = {
                   798, 858, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 50 - 1440x480i@120Hz */
-       { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
+       { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
                   1602, 1716, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
        /* 51 - 1440x480i@120Hz */
-       { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
+       { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
                   1602, 1716, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
@@ -723,12 +723,12 @@ static const struct drm_display_mode edid_cea_modes[] = {
                   796, 864, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 54 - 1440x576i@200Hz */
-       { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
+       { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
                   1590, 1728, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
        /* 55 - 1440x576i@200Hz */
-       { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
+       { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
                   1590, 1728, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
@@ -741,12 +741,12 @@ static const struct drm_display_mode edid_cea_modes[] = {
                   798, 858, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
        /* 58 - 1440x480i@240 */
-       { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
+       { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
                   1602, 1716, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
        /* 59 - 1440x480i@240 */
-       { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
+       { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
                   1602, 1716, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c
new file mode 100644 (file)
index 0000000..09e11a5
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+ * drm kms/fb cma (contiguous memory allocator) helper functions
+ *
+ * Copyright (C) 2012 Analog Device Inc.
+ *   Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Based on udl_fbdev.c
+ *  Copyright (C) 2012 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <linux/module.h>
+
+struct drm_fb_cma {
+       struct drm_framebuffer          fb;
+       struct drm_gem_cma_object       *obj[4];
+};
+
+struct drm_fbdev_cma {
+       struct drm_fb_helper    fb_helper;
+       struct drm_fb_cma       *fb;
+};
+
+static inline struct drm_fbdev_cma *to_fbdev_cma(struct drm_fb_helper *helper)
+{
+       return container_of(helper, struct drm_fbdev_cma, fb_helper);
+}
+
+static inline struct drm_fb_cma *to_fb_cma(struct drm_framebuffer *fb)
+{
+       return container_of(fb, struct drm_fb_cma, fb);
+}
+
+static void drm_fb_cma_destroy(struct drm_framebuffer *fb)
+{
+       struct drm_fb_cma *fb_cma = to_fb_cma(fb);
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               if (fb_cma->obj[i])
+                       drm_gem_object_unreference_unlocked(&fb_cma->obj[i]->base);
+       }
+
+       drm_framebuffer_cleanup(fb);
+       kfree(fb_cma);
+}
+
+static int drm_fb_cma_create_handle(struct drm_framebuffer *fb,
+       struct drm_file *file_priv, unsigned int *handle)
+{
+       struct drm_fb_cma *fb_cma = to_fb_cma(fb);
+
+       return drm_gem_handle_create(file_priv,
+                       &fb_cma->obj[0]->base, handle);
+}
+
+static struct drm_framebuffer_funcs drm_fb_cma_funcs = {
+       .destroy        = drm_fb_cma_destroy,
+       .create_handle  = drm_fb_cma_create_handle,
+};
+
+static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev,
+       struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_cma_object **obj,
+       unsigned int num_planes)
+{
+       struct drm_fb_cma *fb_cma;
+       int ret;
+       int i;
+
+       fb_cma = kzalloc(sizeof(*fb_cma), GFP_KERNEL);
+       if (!fb_cma)
+               return ERR_PTR(-ENOMEM);
+
+       ret = drm_framebuffer_init(dev, &fb_cma->fb, &drm_fb_cma_funcs);
+       if (ret) {
+               dev_err(dev->dev, "Failed to initalize framebuffer: %d\n", ret);
+               kfree(fb_cma);
+               return ERR_PTR(ret);
+       }
+
+       drm_helper_mode_fill_fb_struct(&fb_cma->fb, mode_cmd);
+
+       for (i = 0; i < num_planes; i++)
+               fb_cma->obj[i] = obj[i];
+
+       return fb_cma;
+}
+
+/**
+ * drm_fb_cma_create() - (struct drm_mode_config_funcs *)->fb_create callback function
+ *
+ * If your hardware has special alignment or pitch requirements these should be
+ * checked before calling this function.
+ */
+struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev,
+       struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd)
+{
+       struct drm_fb_cma *fb_cma;
+       struct drm_gem_cma_object *objs[4];
+       struct drm_gem_object *obj;
+       unsigned int hsub;
+       unsigned int vsub;
+       int ret;
+       int i;
+
+       hsub = drm_format_horz_chroma_subsampling(mode_cmd->pixel_format);
+       vsub = drm_format_vert_chroma_subsampling(mode_cmd->pixel_format);
+
+       for (i = 0; i < drm_format_num_planes(mode_cmd->pixel_format); i++) {
+               unsigned int width = mode_cmd->width / (i ? hsub : 1);
+               unsigned int height = mode_cmd->height / (i ? vsub : 1);
+               unsigned int min_size;
+
+               obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[i]);
+               if (!obj) {
+                       dev_err(dev->dev, "Failed to lookup GEM object\n");
+                       ret = -ENXIO;
+                       goto err_gem_object_unreference;
+               }
+
+               min_size = (height - 1) * mode_cmd->pitches[i]
+                        + width * drm_format_plane_cpp(mode_cmd->pixel_format, i)
+                        + mode_cmd->offsets[i];
+
+               if (obj->size < min_size) {
+                       drm_gem_object_unreference_unlocked(obj);
+                       ret = -EINVAL;
+                       goto err_gem_object_unreference;
+               }
+               objs[i] = to_drm_gem_cma_obj(obj);
+       }
+
+       fb_cma = drm_fb_cma_alloc(dev, mode_cmd, objs, i);
+       if (IS_ERR(fb_cma)) {
+               ret = PTR_ERR(fb_cma);
+               goto err_gem_object_unreference;
+       }
+
+       return &fb_cma->fb;
+
+err_gem_object_unreference:
+       for (i--; i >= 0; i--)
+               drm_gem_object_unreference_unlocked(&objs[i]->base);
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(drm_fb_cma_create);
+
+/**
+ * drm_fb_cma_get_gem_obj() - Get CMA GEM object for framebuffer
+ * @fb: The framebuffer
+ * @plane: Which plane
+ *
+ * Return the CMA GEM object for given framebuffer.
+ *
+ * This function will usually be called from the CRTC callback functions.
+ */
+struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb,
+       unsigned int plane)
+{
+       struct drm_fb_cma *fb_cma = to_fb_cma(fb);
+
+       if (plane >= 4)
+               return NULL;
+
+       return fb_cma->obj[plane];
+}
+EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj);
+
+static struct fb_ops drm_fbdev_cma_ops = {
+       .owner          = THIS_MODULE,
+       .fb_fillrect    = sys_fillrect,
+       .fb_copyarea    = sys_copyarea,
+       .fb_imageblit   = sys_imageblit,
+       .fb_check_var   = drm_fb_helper_check_var,
+       .fb_set_par     = drm_fb_helper_set_par,
+       .fb_blank       = drm_fb_helper_blank,
+       .fb_pan_display = drm_fb_helper_pan_display,
+       .fb_setcmap     = drm_fb_helper_setcmap,
+};
+
+static int drm_fbdev_cma_create(struct drm_fb_helper *helper,
+       struct drm_fb_helper_surface_size *sizes)
+{
+       struct drm_fbdev_cma *fbdev_cma = to_fbdev_cma(helper);
+       struct drm_mode_fb_cmd2 mode_cmd = { 0 };
+       struct drm_device *dev = helper->dev;
+       struct drm_gem_cma_object *obj;
+       struct drm_framebuffer *fb;
+       unsigned int bytes_per_pixel;
+       unsigned long offset;
+       struct fb_info *fbi;
+       size_t size;
+       int ret;
+
+       DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d\n",
+                       sizes->surface_width, sizes->surface_height,
+                       sizes->surface_bpp);
+
+       bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
+
+       mode_cmd.width = sizes->surface_width;
+       mode_cmd.height = sizes->surface_height;
+       mode_cmd.pitches[0] = sizes->surface_width * bytes_per_pixel;
+       mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+               sizes->surface_depth);
+
+       size = mode_cmd.pitches[0] * mode_cmd.height;
+       obj = drm_gem_cma_create(dev, size);
+       if (!obj)
+               return -ENOMEM;
+
+       fbi = framebuffer_alloc(0, dev->dev);
+       if (!fbi) {
+               dev_err(dev->dev, "Failed to allocate framebuffer info.\n");
+               ret = -ENOMEM;
+               goto err_drm_gem_cma_free_object;
+       }
+
+       fbdev_cma->fb = drm_fb_cma_alloc(dev, &mode_cmd, &obj, 1);
+       if (IS_ERR(fbdev_cma->fb)) {
+               dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n");
+               ret = PTR_ERR(fbdev_cma->fb);
+               goto err_framebuffer_release;
+       }
+
+       fb = &fbdev_cma->fb->fb;
+       helper->fb = fb;
+       helper->fbdev = fbi;
+
+       fbi->par = helper;
+       fbi->flags = FBINFO_FLAG_DEFAULT;
+       fbi->fbops = &drm_fbdev_cma_ops;
+
+       ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
+       if (ret) {
+               dev_err(dev->dev, "Failed to allocate color map.\n");
+               goto err_drm_fb_cma_destroy;
+       }
+
+       drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
+       drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
+
+       offset = fbi->var.xoffset * bytes_per_pixel;
+       offset += fbi->var.yoffset * fb->pitches[0];
+
+       dev->mode_config.fb_base = (resource_size_t)obj->paddr;
+       fbi->screen_base = obj->vaddr + offset;
+       fbi->fix.smem_start = (unsigned long)(obj->paddr + offset);
+       fbi->screen_size = size;
+       fbi->fix.smem_len = size;
+
+       return 0;
+
+err_drm_fb_cma_destroy:
+       drm_fb_cma_destroy(fb);
+err_framebuffer_release:
+       framebuffer_release(fbi);
+err_drm_gem_cma_free_object:
+       drm_gem_cma_free_object(&obj->base);
+       return ret;
+}
+
+static int drm_fbdev_cma_probe(struct drm_fb_helper *helper,
+       struct drm_fb_helper_surface_size *sizes)
+{
+       int ret = 0;
+
+       if (!helper->fb) {
+               ret = drm_fbdev_cma_create(helper, sizes);
+               if (ret < 0)
+                       return ret;
+               ret = 1;
+       }
+
+       return ret;
+}
+
+static struct drm_fb_helper_funcs drm_fb_cma_helper_funcs = {
+       .fb_probe = drm_fbdev_cma_probe,
+};
+
+/**
+ * drm_fbdev_cma_init() - Allocate and initializes a drm_fbdev_cma struct
+ * @dev: DRM device
+ * @preferred_bpp: Preferred bits per pixel for the device
+ * @num_crtc: Number of CRTCs
+ * @max_conn_count: Maximum number of connectors
+ *
+ * Returns a newly allocated drm_fbdev_cma struct or a ERR_PTR.
+ */
+struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev,
+       unsigned int preferred_bpp, unsigned int num_crtc,
+       unsigned int max_conn_count)
+{
+       struct drm_fbdev_cma *fbdev_cma;
+       struct drm_fb_helper *helper;
+       int ret;
+
+       fbdev_cma = kzalloc(sizeof(*fbdev_cma), GFP_KERNEL);
+       if (!fbdev_cma) {
+               dev_err(dev->dev, "Failed to allocate drm fbdev.\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       fbdev_cma->fb_helper.funcs = &drm_fb_cma_helper_funcs;
+       helper = &fbdev_cma->fb_helper;
+
+       ret = drm_fb_helper_init(dev, helper, num_crtc, max_conn_count);
+       if (ret < 0) {
+               dev_err(dev->dev, "Failed to initialize drm fb helper.\n");
+               goto err_free;
+       }
+
+       ret = drm_fb_helper_single_add_all_connectors(helper);
+       if (ret < 0) {
+               dev_err(dev->dev, "Failed to add connectors.\n");
+               goto err_drm_fb_helper_fini;
+
+       }
+
+       ret = drm_fb_helper_initial_config(helper, preferred_bpp);
+       if (ret < 0) {
+               dev_err(dev->dev, "Failed to set inital hw configuration.\n");
+               goto err_drm_fb_helper_fini;
+       }
+
+       return fbdev_cma;
+
+err_drm_fb_helper_fini:
+       drm_fb_helper_fini(helper);
+err_free:
+       kfree(fbdev_cma);
+
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(drm_fbdev_cma_init);
+
+/**
+ * drm_fbdev_cma_fini() - Free drm_fbdev_cma struct
+ * @fbdev_cma: The drm_fbdev_cma struct
+ */
+void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma)
+{
+       if (fbdev_cma->fb_helper.fbdev) {
+               struct fb_info *info;
+               int ret;
+
+               info = fbdev_cma->fb_helper.fbdev;
+               ret = unregister_framebuffer(info);
+               if (ret < 0)
+                       DRM_DEBUG_KMS("failed unregister_framebuffer()\n");
+
+               if (info->cmap.len)
+                       fb_dealloc_cmap(&info->cmap);
+
+               framebuffer_release(info);
+       }
+
+       if (fbdev_cma->fb)
+               drm_fb_cma_destroy(&fbdev_cma->fb->fb);
+
+       drm_fb_helper_fini(&fbdev_cma->fb_helper);
+       kfree(fbdev_cma);
+}
+EXPORT_SYMBOL_GPL(drm_fbdev_cma_fini);
+
+/**
+ * drm_fbdev_cma_restore_mode() - Restores initial framebuffer mode
+ * @fbdev_cma: The drm_fbdev_cma struct, may be NULL
+ *
+ * This function is usually called from the DRM drivers lastclose callback.
+ */
+void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma)
+{
+       if (fbdev_cma)
+               drm_fb_helper_restore_fbdev_mode(&fbdev_cma->fb_helper);
+}
+EXPORT_SYMBOL_GPL(drm_fbdev_cma_restore_mode);
+
+/**
+ * drm_fbdev_cma_hotplug_event() - Poll for hotpulug events
+ * @fbdev_cma: The drm_fbdev_cma struct, may be NULL
+ *
+ * This function is usually called from the DRM drivers output_poll_changed
+ * callback.
+ */
+void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma)
+{
+       if (fbdev_cma)
+               drm_fb_helper_hotplug_event(&fbdev_cma->fb_helper);
+}
+EXPORT_SYMBOL_GPL(drm_fbdev_cma_hotplug_event);
diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c
new file mode 100644 (file)
index 0000000..1aa8fee
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * drm gem CMA (contiguous memory allocator) helper functions
+ *
+ * Copyright (C) 2012 Sascha Hauer, Pengutronix
+ *
+ * Based on Samsung Exynos code
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/export.h>
+#include <linux/dma-mapping.h>
+
+#include <drm/drmP.h>
+#include <drm/drm.h>
+#include <drm/drm_gem_cma_helper.h>
+
+static unsigned int get_gem_mmap_offset(struct drm_gem_object *obj)
+{
+       return (unsigned int)obj->map_list.hash.key << PAGE_SHIFT;
+}
+
+static void drm_gem_cma_buf_destroy(struct drm_device *drm,
+               struct drm_gem_cma_object *cma_obj)
+{
+       dma_free_writecombine(drm->dev, cma_obj->base.size, cma_obj->vaddr,
+                       cma_obj->paddr);
+}
+
+/*
+ * drm_gem_cma_create - allocate an object with the given size
+ *
+ * returns a struct drm_gem_cma_object* on success or ERR_PTR values
+ * on failure.
+ */
+struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm,
+               unsigned int size)
+{
+       struct drm_gem_cma_object *cma_obj;
+       struct drm_gem_object *gem_obj;
+       int ret;
+
+       size = round_up(size, PAGE_SIZE);
+
+       cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL);
+       if (!cma_obj)
+               return ERR_PTR(-ENOMEM);
+
+       cma_obj->vaddr = dma_alloc_writecombine(drm->dev, size,
+                       &cma_obj->paddr, GFP_KERNEL | __GFP_NOWARN);
+       if (!cma_obj->vaddr) {
+               dev_err(drm->dev, "failed to allocate buffer with size %d\n", size);
+               ret = -ENOMEM;
+               goto err_dma_alloc;
+       }
+
+       gem_obj = &cma_obj->base;
+
+       ret = drm_gem_object_init(drm, gem_obj, size);
+       if (ret)
+               goto err_obj_init;
+
+       ret = drm_gem_create_mmap_offset(gem_obj);
+       if (ret)
+               goto err_create_mmap_offset;
+
+       return cma_obj;
+
+err_create_mmap_offset:
+       drm_gem_object_release(gem_obj);
+
+err_obj_init:
+       drm_gem_cma_buf_destroy(drm, cma_obj);
+
+err_dma_alloc:
+       kfree(cma_obj);
+
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(drm_gem_cma_create);
+
+/*
+ * drm_gem_cma_create_with_handle - allocate an object with the given
+ * size and create a gem handle on it
+ *
+ * returns a struct drm_gem_cma_object* on success or ERR_PTR values
+ * on failure.
+ */
+static struct drm_gem_cma_object *drm_gem_cma_create_with_handle(
+               struct drm_file *file_priv,
+               struct drm_device *drm, unsigned int size,
+               unsigned int *handle)
+{
+       struct drm_gem_cma_object *cma_obj;
+       struct drm_gem_object *gem_obj;
+       int ret;
+
+       cma_obj = drm_gem_cma_create(drm, size);
+       if (IS_ERR(cma_obj))
+               return cma_obj;
+
+       gem_obj = &cma_obj->base;
+
+       /*
+        * allocate a id of idr table where the obj is registered
+        * and handle has the id what user can see.
+        */
+       ret = drm_gem_handle_create(file_priv, gem_obj, handle);
+       if (ret)
+               goto err_handle_create;
+
+       /* drop reference from allocate - handle holds it now. */
+       drm_gem_object_unreference_unlocked(gem_obj);
+
+       return cma_obj;
+
+err_handle_create:
+       drm_gem_cma_free_object(gem_obj);
+
+       return ERR_PTR(ret);
+}
+
+/*
+ * drm_gem_cma_free_object - (struct drm_driver)->gem_free_object callback
+ * function
+ */
+void drm_gem_cma_free_object(struct drm_gem_object *gem_obj)
+{
+       struct drm_gem_cma_object *cma_obj;
+
+       if (gem_obj->map_list.map)
+               drm_gem_free_mmap_offset(gem_obj);
+
+       drm_gem_object_release(gem_obj);
+
+       cma_obj = to_drm_gem_cma_obj(gem_obj);
+
+       drm_gem_cma_buf_destroy(gem_obj->dev, cma_obj);
+
+       kfree(cma_obj);
+}
+EXPORT_SYMBOL_GPL(drm_gem_cma_free_object);
+
+/*
+ * drm_gem_cma_dumb_create - (struct drm_driver)->dumb_create callback
+ * function
+ *
+ * This aligns the pitch and size arguments to the minimum required. wrap
+ * this into your own function if you need bigger alignment.
+ */
+int drm_gem_cma_dumb_create(struct drm_file *file_priv,
+               struct drm_device *dev, struct drm_mode_create_dumb *args)
+{
+       struct drm_gem_cma_object *cma_obj;
+       int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+
+       if (args->pitch < min_pitch)
+               args->pitch = min_pitch;
+
+       if (args->size < args->pitch * args->height)
+               args->size = args->pitch * args->height;
+
+       cma_obj = drm_gem_cma_create_with_handle(file_priv, dev,
+                       args->size, &args->handle);
+       if (IS_ERR(cma_obj))
+               return PTR_ERR(cma_obj);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_create);
+
+/*
+ * drm_gem_cma_dumb_map_offset - (struct drm_driver)->dumb_map_offset callback
+ * function
+ */
+int drm_gem_cma_dumb_map_offset(struct drm_file *file_priv,
+               struct drm_device *drm, uint32_t handle, uint64_t *offset)
+{
+       struct drm_gem_object *gem_obj;
+
+       mutex_lock(&drm->struct_mutex);
+
+       gem_obj = drm_gem_object_lookup(drm, file_priv, handle);
+       if (!gem_obj) {
+               dev_err(drm->dev, "failed to lookup gem object\n");
+               mutex_unlock(&drm->struct_mutex);
+               return -EINVAL;
+       }
+
+       *offset = get_gem_mmap_offset(gem_obj);
+
+       drm_gem_object_unreference(gem_obj);
+
+       mutex_unlock(&drm->struct_mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_map_offset);
+
+const struct vm_operations_struct drm_gem_cma_vm_ops = {
+       .open = drm_gem_vm_open,
+       .close = drm_gem_vm_close,
+};
+EXPORT_SYMBOL_GPL(drm_gem_cma_vm_ops);
+
+/*
+ * drm_gem_cma_mmap - (struct file_operation)->mmap callback function
+ */
+int drm_gem_cma_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct drm_gem_object *gem_obj;
+       struct drm_gem_cma_object *cma_obj;
+       int ret;
+
+       ret = drm_gem_mmap(filp, vma);
+       if (ret)
+               return ret;
+
+       gem_obj = vma->vm_private_data;
+       cma_obj = to_drm_gem_cma_obj(gem_obj);
+
+       ret = remap_pfn_range(vma, vma->vm_start, cma_obj->paddr >> PAGE_SHIFT,
+                       vma->vm_end - vma->vm_start, vma->vm_page_prot);
+       if (ret)
+               drm_gem_vm_close(vma);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(drm_gem_cma_mmap);
+
+/*
+ * drm_gem_cma_dumb_destroy - (struct drm_driver)->dumb_destroy callback function
+ */
+int drm_gem_cma_dumb_destroy(struct drm_file *file_priv,
+               struct drm_device *drm, unsigned int handle)
+{
+       return drm_gem_handle_delete(file_priv, handle);
+}
+EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_destroy);
index 3f0616672531311c8bb5a3fdeb9855237c38c0aa..6fed215023132981c1af48c8fa8521ce59a210d0 100644 (file)
@@ -619,20 +619,11 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
                offset = drm_core_get_reg_ofs(dev);
                vma->vm_flags |= VM_IO; /* not in core dump */
                vma->vm_page_prot = drm_io_prot(map->type, vma);
-#if !defined(__arm__)
                if (io_remap_pfn_range(vma, vma->vm_start,
                                       (map->offset + offset) >> PAGE_SHIFT,
                                       vma->vm_end - vma->vm_start,
                                       vma->vm_page_prot))
                        return -EAGAIN;
-#else
-               if (remap_pfn_range(vma, vma->vm_start,
-                                       (map->offset + offset) >> PAGE_SHIFT,
-                                       vma->vm_end - vma->vm_start,
-                                       vma->vm_page_prot))
-                       return -EAGAIN;
-#endif
-
                DRM_DEBUG("   Type = %d; start = 0x%lx, end = 0x%lx,"
                          " offset = 0x%llx\n",
                          map->type,
index b1b77bb92a858040f890bad041838c3fe2d9ba1e..7272a461edfe8f91fb0686db7118024efbac4e55 100644 (file)
@@ -139,8 +139,6 @@ static enum drm_connector_status cdv_hdmi_detect(
 {
        struct psb_intel_encoder *psb_intel_encoder =
                                        psb_intel_attached_encoder(connector);
-       struct psb_intel_connector *psb_intel_connector =
-                                       to_psb_intel_connector(connector);
        struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_encoder->dev_priv;
        struct edid *edid = NULL;
        enum drm_connector_status status = connector_status_disconnected;
index 7e289d2ad8e40f75d13b504fadbbc25c99cdeac2..e754aa32edf1f6d9538bdad2d40e70ba5b25b41f 100644 (file)
@@ -289,9 +289,7 @@ dp_link_train_update(struct drm_device *dev, struct dp_state *dp, u32 delay)
        if (ret)
                return ret;
 
-       NV_DEBUG_KMS(dev, "status %02x %02x %02x %02x %02x %02x\n",
-                    dp->stat[0], dp->stat[1], dp->stat[2], dp->stat[3],
-                    dp->stat[4], dp->stat[5]);
+       NV_DEBUG_KMS(dev, "status %*ph\n", 6, dp->stat);
        return 0;
 }
 
index 7712cf5ab33b9a107ddf6ef61f1122622a358951..8a74e1bf04576a35918ab85347d0fb6d303c7d1f 100644 (file)
@@ -658,9 +658,7 @@ static bool radeon_dp_get_link_status(struct radeon_connector *radeon_connector,
                return false;
        }
 
-       DRM_DEBUG_KMS("link status %02x %02x %02x %02x %02x %02x\n",
-                 link_status[0], link_status[1], link_status[2],
-                 link_status[3], link_status[4], link_status[5]);
+       DRM_DEBUG_KMS("link status %*ph\n", 6, link_status);
        return true;
 }
 
diff --git a/drivers/gpu/drm/shmobile/Kconfig b/drivers/gpu/drm/shmobile/Kconfig
new file mode 100644 (file)
index 0000000..7e7d52b
--- /dev/null
@@ -0,0 +1,10 @@
+config DRM_SHMOBILE
+       tristate "DRM Support for SH Mobile"
+       depends on DRM && (SUPERH || ARCH_SHMOBILE)
+       select DRM_KMS_HELPER
+       select DRM_KMS_CMA_HELPER
+       select DRM_GEM_CMA_HELPER
+       help
+         Choose this option if you have an SH Mobile chipset.
+         If M is selected the module will be called shmob-drm.
+
diff --git a/drivers/gpu/drm/shmobile/Makefile b/drivers/gpu/drm/shmobile/Makefile
new file mode 100644 (file)
index 0000000..4c3eeb3
--- /dev/null
@@ -0,0 +1,7 @@
+shmob-drm-y := shmob_drm_backlight.o \
+              shmob_drm_crtc.o \
+              shmob_drm_drv.o \
+              shmob_drm_kms.o \
+              shmob_drm_plane.o
+
+obj-$(CONFIG_DRM_SHMOBILE)     += shmob-drm.o
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_backlight.c b/drivers/gpu/drm/shmobile/shmob_drm_backlight.c
new file mode 100644 (file)
index 0000000..463aee1
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * shmob_drm_backlight.c  --  SH Mobile DRM Backlight
+ *
+ * Copyright (C) 2012 Renesas Corporation
+ *
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/backlight.h>
+
+#include "shmob_drm_backlight.h"
+#include "shmob_drm_crtc.h"
+#include "shmob_drm_drv.h"
+
+static int shmob_drm_backlight_update(struct backlight_device *bdev)
+{
+       struct shmob_drm_connector *scon = bl_get_data(bdev);
+       struct shmob_drm_device *sdev = scon->connector.dev->dev_private;
+       const struct shmob_drm_backlight_data *bdata = &sdev->pdata->backlight;
+       int brightness = bdev->props.brightness;
+
+       if (bdev->props.power != FB_BLANK_UNBLANK ||
+           bdev->props.state & BL_CORE_SUSPENDED)
+               brightness = 0;
+
+       return bdata->set_brightness(brightness);
+}
+
+static int shmob_drm_backlight_get_brightness(struct backlight_device *bdev)
+{
+       struct shmob_drm_connector *scon = bl_get_data(bdev);
+       struct shmob_drm_device *sdev = scon->connector.dev->dev_private;
+       const struct shmob_drm_backlight_data *bdata = &sdev->pdata->backlight;
+
+       return bdata->get_brightness();
+}
+
+static const struct backlight_ops shmob_drm_backlight_ops = {
+       .options        = BL_CORE_SUSPENDRESUME,
+       .update_status  = shmob_drm_backlight_update,
+       .get_brightness = shmob_drm_backlight_get_brightness,
+};
+
+void shmob_drm_backlight_dpms(struct shmob_drm_connector *scon, int mode)
+{
+       if (scon->backlight == NULL)
+               return;
+
+       scon->backlight->props.power = mode == DRM_MODE_DPMS_ON
+                                    ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
+       backlight_update_status(scon->backlight);
+}
+
+int shmob_drm_backlight_init(struct shmob_drm_connector *scon)
+{
+       struct shmob_drm_device *sdev = scon->connector.dev->dev_private;
+       const struct shmob_drm_backlight_data *bdata = &sdev->pdata->backlight;
+       struct drm_connector *connector = &scon->connector;
+       struct drm_device *dev = connector->dev;
+       struct backlight_device *backlight;
+
+       if (!bdata->max_brightness)
+               return 0;
+
+       backlight = backlight_device_register(bdata->name, dev->dev, scon,
+                                             &shmob_drm_backlight_ops, NULL);
+       if (IS_ERR(backlight)) {
+               dev_err(dev->dev, "unable to register backlight device: %ld\n",
+                       PTR_ERR(backlight));
+               return PTR_ERR(backlight);
+       }
+
+       backlight->props.max_brightness = bdata->max_brightness;
+       backlight->props.brightness = bdata->max_brightness;
+       backlight->props.power = FB_BLANK_POWERDOWN;
+       backlight_update_status(backlight);
+
+       scon->backlight = backlight;
+       return 0;
+}
+
+void shmob_drm_backlight_exit(struct shmob_drm_connector *scon)
+{
+       backlight_device_unregister(scon->backlight);
+}
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_backlight.h b/drivers/gpu/drm/shmobile/shmob_drm_backlight.h
new file mode 100644 (file)
index 0000000..9477595
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * shmob_drm_backlight.h  --  SH Mobile DRM Backlight
+ *
+ * Copyright (C) 2012 Renesas Corporation
+ *
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __SHMOB_DRM_BACKLIGHT_H__
+#define __SHMOB_DRM_BACKLIGHT_H__
+
+struct shmob_drm_connector;
+
+void shmob_drm_backlight_dpms(struct shmob_drm_connector *scon, int mode);
+int shmob_drm_backlight_init(struct shmob_drm_connector *scon);
+void shmob_drm_backlight_exit(struct shmob_drm_connector *scon);
+
+#endif /* __SHMOB_DRM_BACKLIGHT_H__ */
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
new file mode 100644 (file)
index 0000000..0e7a930
--- /dev/null
@@ -0,0 +1,763 @@
+/*
+ * shmob_drm_crtc.c  --  SH Mobile DRM CRTCs
+ *
+ * Copyright (C) 2012 Renesas Corporation
+ *
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/backlight.h>
+#include <linux/clk.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include <video/sh_mobile_meram.h>
+
+#include "shmob_drm_backlight.h"
+#include "shmob_drm_crtc.h"
+#include "shmob_drm_drv.h"
+#include "shmob_drm_kms.h"
+#include "shmob_drm_plane.h"
+#include "shmob_drm_regs.h"
+
+/*
+ * TODO: panel support
+ */
+
+/* -----------------------------------------------------------------------------
+ * Clock management
+ */
+
+static void shmob_drm_clk_on(struct shmob_drm_device *sdev)
+{
+       if (sdev->clock)
+               clk_enable(sdev->clock);
+#if 0
+       if (sdev->meram_dev && sdev->meram_dev->pdev)
+               pm_runtime_get_sync(&sdev->meram_dev->pdev->dev);
+#endif
+}
+
+static void shmob_drm_clk_off(struct shmob_drm_device *sdev)
+{
+#if 0
+       if (sdev->meram_dev && sdev->meram_dev->pdev)
+               pm_runtime_put_sync(&sdev->meram_dev->pdev->dev);
+#endif
+       if (sdev->clock)
+               clk_disable(sdev->clock);
+}
+
+/* -----------------------------------------------------------------------------
+ * CRTC
+ */
+
+static void shmob_drm_crtc_setup_geometry(struct shmob_drm_crtc *scrtc)
+{
+       struct drm_crtc *crtc = &scrtc->crtc;
+       struct shmob_drm_device *sdev = crtc->dev->dev_private;
+       const struct shmob_drm_interface_data *idata = &sdev->pdata->iface;
+       const struct drm_display_mode *mode = &crtc->mode;
+       u32 value;
+
+       value = sdev->ldmt1r
+             | ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : LDMT1R_VPOL)
+             | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : LDMT1R_HPOL)
+             | ((idata->flags & SHMOB_DRM_IFACE_FL_DWPOL) ? LDMT1R_DWPOL : 0)
+             | ((idata->flags & SHMOB_DRM_IFACE_FL_DIPOL) ? LDMT1R_DIPOL : 0)
+             | ((idata->flags & SHMOB_DRM_IFACE_FL_DAPOL) ? LDMT1R_DAPOL : 0)
+             | ((idata->flags & SHMOB_DRM_IFACE_FL_HSCNT) ? LDMT1R_HSCNT : 0)
+             | ((idata->flags & SHMOB_DRM_IFACE_FL_DWCNT) ? LDMT1R_DWCNT : 0);
+       lcdc_write(sdev, LDMT1R, value);
+
+       if (idata->interface >= SHMOB_DRM_IFACE_SYS8A &&
+           idata->interface <= SHMOB_DRM_IFACE_SYS24) {
+               /* Setup SYS bus. */
+               value = (idata->sys.cs_setup << LDMT2R_CSUP_SHIFT)
+                     | (idata->sys.vsync_active_high ? LDMT2R_RSV : 0)
+                     | (idata->sys.vsync_dir_input ? LDMT2R_VSEL : 0)
+                     | (idata->sys.write_setup << LDMT2R_WCSC_SHIFT)
+                     | (idata->sys.write_cycle << LDMT2R_WCEC_SHIFT)
+                     | (idata->sys.write_strobe << LDMT2R_WCLW_SHIFT);
+               lcdc_write(sdev, LDMT2R, value);
+
+               value = (idata->sys.read_latch << LDMT3R_RDLC_SHIFT)
+                     | (idata->sys.read_setup << LDMT3R_RCSC_SHIFT)
+                     | (idata->sys.read_cycle << LDMT3R_RCEC_SHIFT)
+                     | (idata->sys.read_strobe << LDMT3R_RCLW_SHIFT);
+               lcdc_write(sdev, LDMT3R, value);
+       }
+
+       value = ((mode->hdisplay / 8) << 16)                    /* HDCN */
+             | (mode->htotal / 8);                             /* HTCN */
+       lcdc_write(sdev, LDHCNR, value);
+
+       value = (((mode->hsync_end - mode->hsync_start) / 8) << 16) /* HSYNW */
+             | (mode->hsync_start / 8);                        /* HSYNP */
+       lcdc_write(sdev, LDHSYNR, value);
+
+       value = ((mode->hdisplay & 7) << 24) | ((mode->htotal & 7) << 16)
+             | (((mode->hsync_end - mode->hsync_start) & 7) << 8)
+             | (mode->hsync_start & 7);
+       lcdc_write(sdev, LDHAJR, value);
+
+       value = ((mode->vdisplay) << 16)                        /* VDLN */
+             | mode->vtotal;                                   /* VTLN */
+       lcdc_write(sdev, LDVLNR, value);
+
+       value = ((mode->vsync_end - mode->vsync_start) << 16)   /* VSYNW */
+             | mode->vsync_start;                              /* VSYNP */
+       lcdc_write(sdev, LDVSYNR, value);
+}
+
+static void shmob_drm_crtc_start_stop(struct shmob_drm_crtc *scrtc, bool start)
+{
+       struct shmob_drm_device *sdev = scrtc->crtc.dev->dev_private;
+       u32 value;
+
+       value = lcdc_read(sdev, LDCNT2R);
+       if (start)
+               lcdc_write(sdev, LDCNT2R, value | LDCNT2R_DO);
+       else
+               lcdc_write(sdev, LDCNT2R, value & ~LDCNT2R_DO);
+
+       /* Wait until power is applied/stopped. */
+       while (1) {
+               value = lcdc_read(sdev, LDPMR) & LDPMR_LPS;
+               if ((start && value) || (!start && !value))
+                       break;
+
+               cpu_relax();
+       }
+
+       if (!start) {
+               /* Stop the dot clock. */
+               lcdc_write(sdev, LDDCKSTPR, LDDCKSTPR_DCKSTP);
+       }
+}
+
+/*
+ * shmob_drm_crtc_start - Configure and start the LCDC
+ * @scrtc: the SH Mobile CRTC
+ *
+ * Configure and start the LCDC device. External devices (clocks, MERAM, panels,
+ * ...) are not touched by this function.
+ */
+static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc)
+{
+       struct drm_crtc *crtc = &scrtc->crtc;
+       struct shmob_drm_device *sdev = crtc->dev->dev_private;
+       const struct shmob_drm_interface_data *idata = &sdev->pdata->iface;
+       const struct shmob_drm_format_info *format;
+       struct drm_device *dev = sdev->ddev;
+       struct drm_plane *plane;
+       u32 value;
+
+       if (scrtc->started)
+               return;
+
+       format = shmob_drm_format_info(crtc->fb->pixel_format);
+       if (WARN_ON(format == NULL))
+               return;
+
+       /* Enable clocks before accessing the hardware. */
+       shmob_drm_clk_on(sdev);
+
+       /* Reset and enable the LCDC. */
+       lcdc_write(sdev, LDCNT2R, lcdc_read(sdev, LDCNT2R) | LDCNT2R_BR);
+       lcdc_wait_bit(sdev, LDCNT2R, LDCNT2R_BR, 0);
+       lcdc_write(sdev, LDCNT2R, LDCNT2R_ME);
+
+       /* Stop the LCDC first and disable all interrupts. */
+       shmob_drm_crtc_start_stop(scrtc, false);
+       lcdc_write(sdev, LDINTR, 0);
+
+       /* Configure power supply, dot clocks and start them. */
+       lcdc_write(sdev, LDPMR, 0);
+
+       value = sdev->lddckr;
+       if (idata->clk_div) {
+               /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider
+                * denominator.
+                */
+               lcdc_write(sdev, LDDCKPAT1R, 0);
+               lcdc_write(sdev, LDDCKPAT2R, (1 << (idata->clk_div / 2)) - 1);
+
+               if (idata->clk_div == 1)
+                       value |= LDDCKR_MOSEL;
+               else
+                       value |= idata->clk_div;
+       }
+
+       lcdc_write(sdev, LDDCKR, value);
+       lcdc_write(sdev, LDDCKSTPR, 0);
+       lcdc_wait_bit(sdev, LDDCKSTPR, ~0, 0);
+
+       /* TODO: Setup SYS panel */
+
+       /* Setup geometry, format, frame buffer memory and operation mode. */
+       shmob_drm_crtc_setup_geometry(scrtc);
+
+       /* TODO: Handle YUV colorspaces. Hardcode REC709 for now. */
+       lcdc_write(sdev, LDDFR, format->lddfr | LDDFR_CF1);
+       lcdc_write(sdev, LDMLSR, scrtc->line_size);
+       lcdc_write(sdev, LDSA1R, scrtc->dma[0]);
+       if (format->yuv)
+               lcdc_write(sdev, LDSA2R, scrtc->dma[1]);
+       lcdc_write(sdev, LDSM1R, 0);
+
+       /* Word and long word swap. */
+       switch (format->fourcc) {
+       case DRM_FORMAT_RGB565:
+       case DRM_FORMAT_NV21:
+       case DRM_FORMAT_NV61:
+       case DRM_FORMAT_NV42:
+               value = LDDDSR_LS | LDDDSR_WS;
+               break;
+       case DRM_FORMAT_RGB888:
+       case DRM_FORMAT_NV12:
+       case DRM_FORMAT_NV16:
+       case DRM_FORMAT_NV24:
+               value = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
+               break;
+       case DRM_FORMAT_ARGB8888:
+       default:
+               value = LDDDSR_LS;
+               break;
+       }
+       lcdc_write(sdev, LDDDSR, value);
+
+       /* Setup planes. */
+       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+               if (plane->crtc == crtc)
+                       shmob_drm_plane_setup(plane);
+       }
+
+       /* Enable the display output. */
+       lcdc_write(sdev, LDCNT1R, LDCNT1R_DE);
+
+       shmob_drm_crtc_start_stop(scrtc, true);
+
+       scrtc->started = true;
+}
+
+static void shmob_drm_crtc_stop(struct shmob_drm_crtc *scrtc)
+{
+       struct drm_crtc *crtc = &scrtc->crtc;
+       struct shmob_drm_device *sdev = crtc->dev->dev_private;
+
+       if (!scrtc->started)
+               return;
+
+       /* Disable the MERAM cache. */
+       if (scrtc->cache) {
+               sh_mobile_meram_cache_free(sdev->meram, scrtc->cache);
+               scrtc->cache = NULL;
+       }
+
+       /* Stop the LCDC. */
+       shmob_drm_crtc_start_stop(scrtc, false);
+
+       /* Disable the display output. */
+       lcdc_write(sdev, LDCNT1R, 0);
+
+       /* Stop clocks. */
+       shmob_drm_clk_off(sdev);
+
+       scrtc->started = false;
+}
+
+void shmob_drm_crtc_suspend(struct shmob_drm_crtc *scrtc)
+{
+       shmob_drm_crtc_stop(scrtc);
+}
+
+void shmob_drm_crtc_resume(struct shmob_drm_crtc *scrtc)
+{
+       if (scrtc->dpms != DRM_MODE_DPMS_ON)
+               return;
+
+       shmob_drm_crtc_start(scrtc);
+}
+
+static void shmob_drm_crtc_compute_base(struct shmob_drm_crtc *scrtc,
+                                       int x, int y)
+{
+       struct drm_crtc *crtc = &scrtc->crtc;
+       struct drm_framebuffer *fb = crtc->fb;
+       struct shmob_drm_device *sdev = crtc->dev->dev_private;
+       struct drm_gem_cma_object *gem;
+       unsigned int bpp;
+
+       bpp = scrtc->format->yuv ? 8 : scrtc->format->bpp;
+       gem = drm_fb_cma_get_gem_obj(fb, 0);
+       scrtc->dma[0] = gem->paddr + fb->offsets[0]
+                     + y * fb->pitches[0] + x * bpp / 8;
+
+       if (scrtc->format->yuv) {
+               bpp = scrtc->format->bpp - 8;
+               gem = drm_fb_cma_get_gem_obj(fb, 1);
+               scrtc->dma[1] = gem->paddr + fb->offsets[1]
+                             + y / (bpp == 4 ? 2 : 1) * fb->pitches[1]
+                             + x * (bpp == 16 ? 2 : 1);
+       }
+
+       if (scrtc->cache)
+               sh_mobile_meram_cache_update(sdev->meram, scrtc->cache,
+                                            scrtc->dma[0], scrtc->dma[1],
+                                            &scrtc->dma[0], &scrtc->dma[1]);
+}
+
+static void shmob_drm_crtc_update_base(struct shmob_drm_crtc *scrtc)
+{
+       struct drm_crtc *crtc = &scrtc->crtc;
+       struct shmob_drm_device *sdev = crtc->dev->dev_private;
+
+       shmob_drm_crtc_compute_base(scrtc, crtc->x, crtc->y);
+
+       lcdc_write_mirror(sdev, LDSA1R, scrtc->dma[0]);
+       if (scrtc->format->yuv)
+               lcdc_write_mirror(sdev, LDSA2R, scrtc->dma[1]);
+
+       lcdc_write(sdev, LDRCNTR, lcdc_read(sdev, LDRCNTR) ^ LDRCNTR_MRS);
+}
+
+#define to_shmob_crtc(c)       container_of(c, struct shmob_drm_crtc, crtc)
+
+static void shmob_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc);
+
+       if (scrtc->dpms == mode)
+               return;
+
+       if (mode == DRM_MODE_DPMS_ON)
+               shmob_drm_crtc_start(scrtc);
+       else
+               shmob_drm_crtc_stop(scrtc);
+
+       scrtc->dpms = mode;
+}
+
+static bool shmob_drm_crtc_mode_fixup(struct drm_crtc *crtc,
+                                     const struct drm_display_mode *mode,
+                                     struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void shmob_drm_crtc_mode_prepare(struct drm_crtc *crtc)
+{
+       shmob_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+}
+
+static int shmob_drm_crtc_mode_set(struct drm_crtc *crtc,
+                                  struct drm_display_mode *mode,
+                                  struct drm_display_mode *adjusted_mode,
+                                  int x, int y,
+                                  struct drm_framebuffer *old_fb)
+{
+       struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc);
+       struct shmob_drm_device *sdev = crtc->dev->dev_private;
+       const struct sh_mobile_meram_cfg *mdata = sdev->pdata->meram;
+       const struct shmob_drm_format_info *format;
+       void *cache;
+
+       format = shmob_drm_format_info(crtc->fb->pixel_format);
+       if (format == NULL) {
+               dev_dbg(sdev->dev, "mode_set: unsupported format %08x\n",
+                       crtc->fb->pixel_format);
+               return -EINVAL;
+       }
+
+       scrtc->format = format;
+       scrtc->line_size = crtc->fb->pitches[0];
+
+       if (sdev->meram) {
+               /* Enable MERAM cache if configured. We need to de-init
+                * configured ICBs before we can re-initialize them.
+                */
+               if (scrtc->cache) {
+                       sh_mobile_meram_cache_free(sdev->meram, scrtc->cache);
+                       scrtc->cache = NULL;
+               }
+
+               cache = sh_mobile_meram_cache_alloc(sdev->meram, mdata,
+                                                   crtc->fb->pitches[0],
+                                                   adjusted_mode->vdisplay,
+                                                   format->meram,
+                                                   &scrtc->line_size);
+               if (!IS_ERR(cache))
+                       scrtc->cache = cache;
+       }
+
+       shmob_drm_crtc_compute_base(scrtc, x, y);
+
+       return 0;
+}
+
+static void shmob_drm_crtc_mode_commit(struct drm_crtc *crtc)
+{
+       shmob_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+}
+
+static int shmob_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+                                       struct drm_framebuffer *old_fb)
+{
+       shmob_drm_crtc_update_base(to_shmob_crtc(crtc));
+
+       return 0;
+}
+
+static const struct drm_crtc_helper_funcs crtc_helper_funcs = {
+       .dpms = shmob_drm_crtc_dpms,
+       .mode_fixup = shmob_drm_crtc_mode_fixup,
+       .prepare = shmob_drm_crtc_mode_prepare,
+       .commit = shmob_drm_crtc_mode_commit,
+       .mode_set = shmob_drm_crtc_mode_set,
+       .mode_set_base = shmob_drm_crtc_mode_set_base,
+};
+
+void shmob_drm_crtc_cancel_page_flip(struct shmob_drm_crtc *scrtc,
+                                    struct drm_file *file)
+{
+       struct drm_pending_vblank_event *event;
+       struct drm_device *dev = scrtc->crtc.dev;
+       unsigned long flags;
+
+       /* Destroy the pending vertical blanking event associated with the
+        * pending page flip, if any, and disable vertical blanking interrupts.
+        */
+       spin_lock_irqsave(&dev->event_lock, flags);
+       event = scrtc->event;
+       if (event && event->base.file_priv == file) {
+               scrtc->event = NULL;
+               event->base.destroy(&event->base);
+               drm_vblank_put(dev, 0);
+       }
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+void shmob_drm_crtc_finish_page_flip(struct shmob_drm_crtc *scrtc)
+{
+       struct drm_pending_vblank_event *event;
+       struct drm_device *dev = scrtc->crtc.dev;
+       struct timeval vblanktime;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+       event = scrtc->event;
+       scrtc->event = NULL;
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       if (event == NULL)
+               return;
+
+       event->event.sequence = drm_vblank_count_and_time(dev, 0, &vblanktime);
+       event->event.tv_sec = vblanktime.tv_sec;
+       event->event.tv_usec = vblanktime.tv_usec;
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+       list_add_tail(&event->base.link, &event->base.file_priv->event_list);
+       wake_up_interruptible(&event->base.file_priv->event_wait);
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       drm_vblank_put(dev, 0);
+}
+
+static int shmob_drm_crtc_page_flip(struct drm_crtc *crtc,
+                                   struct drm_framebuffer *fb,
+                                   struct drm_pending_vblank_event *event)
+{
+       struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc);
+       struct drm_device *dev = scrtc->crtc.dev;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+       if (scrtc->event != NULL) {
+               spin_unlock_irqrestore(&dev->event_lock, flags);
+               return -EBUSY;
+       }
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       crtc->fb = fb;
+       shmob_drm_crtc_update_base(scrtc);
+
+       if (event) {
+               event->pipe = 0;
+               spin_lock_irqsave(&dev->event_lock, flags);
+               scrtc->event = event;
+               spin_unlock_irqrestore(&dev->event_lock, flags);
+               drm_vblank_get(dev, 0);
+       }
+
+       return 0;
+}
+
+static const struct drm_crtc_funcs crtc_funcs = {
+       .destroy = drm_crtc_cleanup,
+       .set_config = drm_crtc_helper_set_config,
+       .page_flip = shmob_drm_crtc_page_flip,
+};
+
+int shmob_drm_crtc_create(struct shmob_drm_device *sdev)
+{
+       struct drm_crtc *crtc = &sdev->crtc.crtc;
+       int ret;
+
+       sdev->crtc.dpms = DRM_MODE_DPMS_OFF;
+
+       ret = drm_crtc_init(sdev->ddev, crtc, &crtc_funcs);
+       if (ret < 0)
+               return ret;
+
+       drm_crtc_helper_add(crtc, &crtc_helper_funcs);
+
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Encoder
+ */
+
+#define to_shmob_encoder(e) \
+       container_of(e, struct shmob_drm_encoder, encoder)
+
+static void shmob_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct shmob_drm_encoder *senc = to_shmob_encoder(encoder);
+       struct shmob_drm_device *sdev = encoder->dev->dev_private;
+       struct shmob_drm_connector *scon = &sdev->connector;
+
+       if (senc->dpms == mode)
+               return;
+
+       shmob_drm_backlight_dpms(scon, mode);
+
+       senc->dpms = mode;
+}
+
+static bool shmob_drm_encoder_mode_fixup(struct drm_encoder *encoder,
+                                        const struct drm_display_mode *mode,
+                                        struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct shmob_drm_device *sdev = dev->dev_private;
+       struct drm_connector *connector = &sdev->connector.connector;
+       const struct drm_display_mode *panel_mode;
+
+       if (list_empty(&connector->modes)) {
+               dev_dbg(dev->dev, "mode_fixup: empty modes list\n");
+               return false;
+       }
+
+       /* The flat panel mode is fixed, just copy it to the adjusted mode. */
+       panel_mode = list_first_entry(&connector->modes,
+                                     struct drm_display_mode, head);
+       drm_mode_copy(adjusted_mode, panel_mode);
+
+       return true;
+}
+
+static void shmob_drm_encoder_mode_prepare(struct drm_encoder *encoder)
+{
+       /* No-op, everything is handled in the CRTC code. */
+}
+
+static void shmob_drm_encoder_mode_set(struct drm_encoder *encoder,
+                                      struct drm_display_mode *mode,
+                                      struct drm_display_mode *adjusted_mode)
+{
+       /* No-op, everything is handled in the CRTC code. */
+}
+
+static void shmob_drm_encoder_mode_commit(struct drm_encoder *encoder)
+{
+       /* No-op, everything is handled in the CRTC code. */
+}
+
+static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
+       .dpms = shmob_drm_encoder_dpms,
+       .mode_fixup = shmob_drm_encoder_mode_fixup,
+       .prepare = shmob_drm_encoder_mode_prepare,
+       .commit = shmob_drm_encoder_mode_commit,
+       .mode_set = shmob_drm_encoder_mode_set,
+};
+
+static void shmob_drm_encoder_destroy(struct drm_encoder *encoder)
+{
+       drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs encoder_funcs = {
+       .destroy = shmob_drm_encoder_destroy,
+};
+
+int shmob_drm_encoder_create(struct shmob_drm_device *sdev)
+{
+       struct drm_encoder *encoder = &sdev->encoder.encoder;
+       int ret;
+
+       sdev->encoder.dpms = DRM_MODE_DPMS_OFF;
+
+       encoder->possible_crtcs = 1;
+
+       ret = drm_encoder_init(sdev->ddev, encoder, &encoder_funcs,
+                              DRM_MODE_ENCODER_LVDS);
+       if (ret < 0)
+               return ret;
+
+       drm_encoder_helper_add(encoder, &encoder_helper_funcs);
+
+       return 0;
+}
+
+void shmob_drm_crtc_enable_vblank(struct shmob_drm_device *sdev, bool enable)
+{
+       unsigned long flags;
+       u32 ldintr;
+
+       /* Be careful not to acknowledge any pending interrupt. */
+       spin_lock_irqsave(&sdev->irq_lock, flags);
+       ldintr = lcdc_read(sdev, LDINTR) | LDINTR_STATUS_MASK;
+       if (enable)
+               ldintr |= LDINTR_VEE;
+       else
+               ldintr &= ~LDINTR_VEE;
+       lcdc_write(sdev, LDINTR, ldintr);
+       spin_unlock_irqrestore(&sdev->irq_lock, flags);
+}
+
+/* -----------------------------------------------------------------------------
+ * Connector
+ */
+
+#define to_shmob_connector(c) \
+       container_of(c, struct shmob_drm_connector, connector)
+
+static int shmob_drm_connector_get_modes(struct drm_connector *connector)
+{
+       struct shmob_drm_device *sdev = connector->dev->dev_private;
+       struct drm_display_mode *mode;
+
+       mode = drm_mode_create(connector->dev);
+       if (mode == NULL)
+               return 0;
+
+       mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
+       mode->clock = sdev->pdata->panel.mode.clock;
+       mode->hdisplay = sdev->pdata->panel.mode.hdisplay;
+       mode->hsync_start = sdev->pdata->panel.mode.hsync_start;
+       mode->hsync_end = sdev->pdata->panel.mode.hsync_end;
+       mode->htotal = sdev->pdata->panel.mode.htotal;
+       mode->vdisplay = sdev->pdata->panel.mode.vdisplay;
+       mode->vsync_start = sdev->pdata->panel.mode.vsync_start;
+       mode->vsync_end = sdev->pdata->panel.mode.vsync_end;
+       mode->vtotal = sdev->pdata->panel.mode.vtotal;
+       mode->flags = sdev->pdata->panel.mode.flags;
+
+       drm_mode_set_name(mode);
+       drm_mode_probed_add(connector, mode);
+
+       connector->display_info.width_mm = sdev->pdata->panel.width_mm;
+       connector->display_info.height_mm = sdev->pdata->panel.height_mm;
+
+       return 1;
+}
+
+static int shmob_drm_connector_mode_valid(struct drm_connector *connector,
+                                         struct drm_display_mode *mode)
+{
+       return MODE_OK;
+}
+
+static struct drm_encoder *
+shmob_drm_connector_best_encoder(struct drm_connector *connector)
+{
+       struct shmob_drm_connector *scon = to_shmob_connector(connector);
+
+       return scon->encoder;
+}
+
+static const struct drm_connector_helper_funcs connector_helper_funcs = {
+       .get_modes = shmob_drm_connector_get_modes,
+       .mode_valid = shmob_drm_connector_mode_valid,
+       .best_encoder = shmob_drm_connector_best_encoder,
+};
+
+static void shmob_drm_connector_destroy(struct drm_connector *connector)
+{
+       struct shmob_drm_connector *scon = to_shmob_connector(connector);
+
+       shmob_drm_backlight_exit(scon);
+       drm_sysfs_connector_remove(connector);
+       drm_connector_cleanup(connector);
+}
+
+static enum drm_connector_status
+shmob_drm_connector_detect(struct drm_connector *connector, bool force)
+{
+       return connector_status_connected;
+}
+
+static const struct drm_connector_funcs connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .detect = shmob_drm_connector_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = shmob_drm_connector_destroy,
+};
+
+int shmob_drm_connector_create(struct shmob_drm_device *sdev,
+                              struct drm_encoder *encoder)
+{
+       struct drm_connector *connector = &sdev->connector.connector;
+       int ret;
+
+       sdev->connector.encoder = encoder;
+
+       connector->display_info.width_mm = sdev->pdata->panel.width_mm;
+       connector->display_info.height_mm = sdev->pdata->panel.height_mm;
+
+       ret = drm_connector_init(sdev->ddev, connector, &connector_funcs,
+                                DRM_MODE_CONNECTOR_LVDS);
+       if (ret < 0)
+               return ret;
+
+       drm_connector_helper_add(connector, &connector_helper_funcs);
+       ret = drm_sysfs_connector_add(connector);
+       if (ret < 0)
+               goto err_cleanup;
+
+       ret = shmob_drm_backlight_init(&sdev->connector);
+       if (ret < 0)
+               goto err_sysfs;
+
+       ret = drm_mode_connector_attach_encoder(connector, encoder);
+       if (ret < 0)
+               goto err_backlight;
+
+       connector->encoder = encoder;
+
+       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+       drm_connector_property_set_value(connector,
+               sdev->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);
+
+       return 0;
+
+err_backlight:
+       shmob_drm_backlight_exit(&sdev->connector);
+err_sysfs:
+       drm_sysfs_connector_remove(connector);
+err_cleanup:
+       drm_connector_cleanup(connector);
+       return ret;
+}
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.h b/drivers/gpu/drm/shmobile/shmob_drm_crtc.h
new file mode 100644 (file)
index 0000000..e5bd109
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * shmob_drm_crtc.h  --  SH Mobile DRM CRTCs
+ *
+ * Copyright (C) 2012 Renesas Corporation
+ *
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __SHMOB_DRM_CRTC_H__
+#define __SHMOB_DRM_CRTC_H__
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+
+struct backlight_device;
+struct shmob_drm_device;
+
+struct shmob_drm_crtc {
+       struct drm_crtc crtc;
+
+       struct drm_pending_vblank_event *event;
+       int dpms;
+
+       const struct shmob_drm_format_info *format;
+       void *cache;
+       unsigned long dma[2];
+       unsigned int line_size;
+       bool started;
+};
+
+struct shmob_drm_encoder {
+       struct drm_encoder encoder;
+       int dpms;
+};
+
+struct shmob_drm_connector {
+       struct drm_connector connector;
+       struct drm_encoder *encoder;
+
+       struct backlight_device *backlight;
+};
+
+int shmob_drm_crtc_create(struct shmob_drm_device *sdev);
+void shmob_drm_crtc_enable_vblank(struct shmob_drm_device *sdev, bool enable);
+void shmob_drm_crtc_cancel_page_flip(struct shmob_drm_crtc *scrtc,
+                                    struct drm_file *file);
+void shmob_drm_crtc_finish_page_flip(struct shmob_drm_crtc *scrtc);
+void shmob_drm_crtc_suspend(struct shmob_drm_crtc *scrtc);
+void shmob_drm_crtc_resume(struct shmob_drm_crtc *scrtc);
+
+int shmob_drm_encoder_create(struct shmob_drm_device *sdev);
+int shmob_drm_connector_create(struct shmob_drm_device *sdev,
+                              struct drm_encoder *encoder);
+
+#endif /* __SHMOB_DRM_CRTC_H__ */
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c
new file mode 100644 (file)
index 0000000..c71d493
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * shmob_drm_drv.c  --  SH Mobile DRM driver
+ *
+ * Copyright (C) 2012 Renesas Corporation
+ *
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include "shmob_drm_crtc.h"
+#include "shmob_drm_drv.h"
+#include "shmob_drm_kms.h"
+#include "shmob_drm_plane.h"
+#include "shmob_drm_regs.h"
+
+/* -----------------------------------------------------------------------------
+ * Hardware initialization
+ */
+
+static int __devinit shmob_drm_init_interface(struct shmob_drm_device *sdev)
+{
+       static const u32 ldmt1r[] = {
+               [SHMOB_DRM_IFACE_RGB8] = LDMT1R_MIFTYP_RGB8,
+               [SHMOB_DRM_IFACE_RGB9] = LDMT1R_MIFTYP_RGB9,
+               [SHMOB_DRM_IFACE_RGB12A] = LDMT1R_MIFTYP_RGB12A,
+               [SHMOB_DRM_IFACE_RGB12B] = LDMT1R_MIFTYP_RGB12B,
+               [SHMOB_DRM_IFACE_RGB16] = LDMT1R_MIFTYP_RGB16,
+               [SHMOB_DRM_IFACE_RGB18] = LDMT1R_MIFTYP_RGB18,
+               [SHMOB_DRM_IFACE_RGB24] = LDMT1R_MIFTYP_RGB24,
+               [SHMOB_DRM_IFACE_YUV422] = LDMT1R_MIFTYP_YCBCR,
+               [SHMOB_DRM_IFACE_SYS8A] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8A,
+               [SHMOB_DRM_IFACE_SYS8B] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8B,
+               [SHMOB_DRM_IFACE_SYS8C] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8C,
+               [SHMOB_DRM_IFACE_SYS8D] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8D,
+               [SHMOB_DRM_IFACE_SYS9] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS9,
+               [SHMOB_DRM_IFACE_SYS12] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS12,
+               [SHMOB_DRM_IFACE_SYS16A] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16A,
+               [SHMOB_DRM_IFACE_SYS16B] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16B,
+               [SHMOB_DRM_IFACE_SYS16C] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16C,
+               [SHMOB_DRM_IFACE_SYS18] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS18,
+               [SHMOB_DRM_IFACE_SYS24] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS24,
+       };
+
+       if (sdev->pdata->iface.interface >= ARRAY_SIZE(ldmt1r)) {
+               dev_err(sdev->dev, "invalid interface type %u\n",
+                       sdev->pdata->iface.interface);
+               return -EINVAL;
+       }
+
+       sdev->ldmt1r = ldmt1r[sdev->pdata->iface.interface];
+       return 0;
+}
+
+static int __devinit shmob_drm_setup_clocks(struct shmob_drm_device *sdev,
+                                           enum shmob_drm_clk_source clksrc)
+{
+       struct clk *clk;
+       char *clkname;
+
+       switch (clksrc) {
+       case SHMOB_DRM_CLK_BUS:
+               clkname = "bus_clk";
+               sdev->lddckr = LDDCKR_ICKSEL_BUS;
+               break;
+       case SHMOB_DRM_CLK_PERIPHERAL:
+               clkname = "peripheral_clk";
+               sdev->lddckr = LDDCKR_ICKSEL_MIPI;
+               break;
+       case SHMOB_DRM_CLK_EXTERNAL:
+               clkname = NULL;
+               sdev->lddckr = LDDCKR_ICKSEL_HDMI;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       clk = clk_get(sdev->dev, clkname);
+       if (IS_ERR(clk)) {
+               dev_err(sdev->dev, "cannot get dot clock %s\n", clkname);
+               return PTR_ERR(clk);
+       }
+
+       sdev->clock = clk;
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * DRM operations
+ */
+
+static int shmob_drm_unload(struct drm_device *dev)
+{
+       struct shmob_drm_device *sdev = dev->dev_private;
+
+       drm_kms_helper_poll_fini(dev);
+       drm_mode_config_cleanup(dev);
+       drm_vblank_cleanup(dev);
+       drm_irq_uninstall(dev);
+
+       if (sdev->clock)
+               clk_put(sdev->clock);
+
+       if (sdev->mmio)
+               iounmap(sdev->mmio);
+
+       dev->dev_private = NULL;
+       kfree(sdev);
+
+       return 0;
+}
+
+static int shmob_drm_load(struct drm_device *dev, unsigned long flags)
+{
+       struct shmob_drm_platform_data *pdata = dev->dev->platform_data;
+       struct platform_device *pdev = dev->platformdev;
+       struct shmob_drm_device *sdev;
+       struct resource *res;
+       unsigned int i;
+       int ret;
+
+       if (pdata == NULL) {
+               dev_err(dev->dev, "no platform data\n");
+               return -EINVAL;
+       }
+
+       sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
+       if (sdev == NULL) {
+               dev_err(dev->dev, "failed to allocate private data\n");
+               return -ENOMEM;
+       }
+
+       sdev->dev = &pdev->dev;
+       sdev->pdata = pdata;
+       spin_lock_init(&sdev->irq_lock);
+
+       sdev->ddev = dev;
+       dev->dev_private = sdev;
+
+       /* I/O resources and clocks */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "failed to get memory resource\n");
+               ret = -EINVAL;
+               goto done;
+       }
+
+       sdev->mmio = ioremap_nocache(res->start, resource_size(res));
+       if (sdev->mmio == NULL) {
+               dev_err(&pdev->dev, "failed to remap memory resource\n");
+               ret = -ENOMEM;
+               goto done;
+       }
+
+       ret = shmob_drm_setup_clocks(sdev, pdata->clk_source);
+       if (ret < 0)
+               goto done;
+
+       ret = shmob_drm_init_interface(sdev);
+       if (ret < 0)
+               goto done;
+
+       ret = shmob_drm_modeset_init(sdev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to initialize mode setting\n");
+               goto done;
+       }
+
+       for (i = 0; i < 4; ++i) {
+               ret = shmob_drm_plane_create(sdev, i);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "failed to create plane %u\n", i);
+                       goto done;
+               }
+       }
+
+       ret = drm_vblank_init(dev, 1);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to initialize vblank\n");
+               goto done;
+       }
+
+       ret = drm_irq_install(dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to install IRQ handler\n");
+               goto done;
+       }
+
+done:
+       if (ret)
+               shmob_drm_unload(dev);
+
+       return ret;
+}
+
+static void shmob_drm_preclose(struct drm_device *dev, struct drm_file *file)
+{
+       struct shmob_drm_device *sdev = dev->dev_private;
+
+       shmob_drm_crtc_cancel_page_flip(&sdev->crtc, file);
+}
+
+static irqreturn_t shmob_drm_irq(int irq, void *arg)
+{
+       struct drm_device *dev = arg;
+       struct shmob_drm_device *sdev = dev->dev_private;
+       unsigned long flags;
+       u32 status;
+
+       /* Acknowledge interrupts. Putting interrupt enable and interrupt flag
+        * bits in the same register is really brain-dead design and requires
+        * taking a spinlock.
+        */
+       spin_lock_irqsave(&sdev->irq_lock, flags);
+       status = lcdc_read(sdev, LDINTR);
+       lcdc_write(sdev, LDINTR, status ^ LDINTR_STATUS_MASK);
+       spin_unlock_irqrestore(&sdev->irq_lock, flags);
+
+       if (status & LDINTR_VES) {
+               drm_handle_vblank(dev, 0);
+               shmob_drm_crtc_finish_page_flip(&sdev->crtc);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int shmob_drm_enable_vblank(struct drm_device *dev, int crtc)
+{
+       struct shmob_drm_device *sdev = dev->dev_private;
+
+       shmob_drm_crtc_enable_vblank(sdev, true);
+
+       return 0;
+}
+
+static void shmob_drm_disable_vblank(struct drm_device *dev, int crtc)
+{
+       struct shmob_drm_device *sdev = dev->dev_private;
+
+       shmob_drm_crtc_enable_vblank(sdev, false);
+}
+
+static const struct file_operations shmob_drm_fops = {
+       .owner          = THIS_MODULE,
+       .open           = drm_open,
+       .release        = drm_release,
+       .unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = drm_compat_ioctl,
+#endif
+       .poll           = drm_poll,
+       .read           = drm_read,
+       .fasync         = drm_fasync,
+       .llseek         = no_llseek,
+       .mmap           = drm_gem_cma_mmap,
+};
+
+static struct drm_driver shmob_drm_driver = {
+       .driver_features        = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET,
+       .load                   = shmob_drm_load,
+       .unload                 = shmob_drm_unload,
+       .preclose               = shmob_drm_preclose,
+       .irq_handler            = shmob_drm_irq,
+       .get_vblank_counter     = drm_vblank_count,
+       .enable_vblank          = shmob_drm_enable_vblank,
+       .disable_vblank         = shmob_drm_disable_vblank,
+       .gem_free_object        = drm_gem_cma_free_object,
+       .gem_vm_ops             = &drm_gem_cma_vm_ops,
+       .dumb_create            = drm_gem_cma_dumb_create,
+       .dumb_map_offset        = drm_gem_cma_dumb_map_offset,
+       .dumb_destroy           = drm_gem_cma_dumb_destroy,
+       .fops                   = &shmob_drm_fops,
+       .name                   = "shmob-drm",
+       .desc                   = "Renesas SH Mobile DRM",
+       .date                   = "20120424",
+       .major                  = 1,
+       .minor                  = 0,
+};
+
+/* -----------------------------------------------------------------------------
+ * Power management
+ */
+
+#if CONFIG_PM_SLEEP
+static int shmob_drm_pm_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct drm_device *ddev = platform_get_drvdata(pdev);
+       struct shmob_drm_device *sdev = ddev->dev_private;
+
+       drm_kms_helper_poll_disable(ddev);
+       shmob_drm_crtc_suspend(&sdev->crtc);
+
+       return 0;
+}
+
+static int shmob_drm_pm_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct drm_device *ddev = platform_get_drvdata(pdev);
+       struct shmob_drm_device *sdev = ddev->dev_private;
+
+       mutex_lock(&sdev->ddev->mode_config.mutex);
+       shmob_drm_crtc_resume(&sdev->crtc);
+       mutex_unlock(&sdev->ddev->mode_config.mutex);
+
+       drm_kms_helper_poll_enable(sdev->ddev);
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops shmob_drm_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(shmob_drm_pm_suspend, shmob_drm_pm_resume)
+};
+
+/* -----------------------------------------------------------------------------
+ * Platform driver
+ */
+
+static int __devinit shmob_drm_probe(struct platform_device *pdev)
+{
+       return drm_platform_init(&shmob_drm_driver, pdev);
+}
+
+static int __devexit shmob_drm_remove(struct platform_device *pdev)
+{
+       drm_platform_exit(&shmob_drm_driver, pdev);
+
+       return 0;
+}
+
+static struct platform_driver shmob_drm_platform_driver = {
+       .probe          = shmob_drm_probe,
+       .remove         = __devexit_p(shmob_drm_remove),
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "shmob-drm",
+               .pm     = &shmob_drm_pm_ops,
+       },
+};
+
+module_platform_driver(shmob_drm_platform_driver);
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_DESCRIPTION("Renesas SH Mobile DRM Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.h b/drivers/gpu/drm/shmobile/shmob_drm_drv.h
new file mode 100644 (file)
index 0000000..4d46b81
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * shmob_drm.h  --  SH Mobile DRM driver
+ *
+ * Copyright (C) 2012 Renesas Corporation
+ *
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __SHMOB_DRM_DRV_H__
+#define __SHMOB_DRM_DRV_H__
+
+#include <linux/kernel.h>
+#include <linux/platform_data/shmob_drm.h>
+#include <linux/spinlock.h>
+
+#include "shmob_drm_crtc.h"
+
+struct clk;
+struct device;
+struct drm_device;
+struct sh_mobile_meram_info;
+
+struct shmob_drm_device {
+       struct device *dev;
+       const struct shmob_drm_platform_data *pdata;
+
+       void __iomem *mmio;
+       struct clk *clock;
+       struct sh_mobile_meram_info *meram;
+       u32 lddckr;
+       u32 ldmt1r;
+
+       spinlock_t irq_lock;            /* Protects hardware LDINTR register */
+
+       struct drm_device *ddev;
+
+       struct shmob_drm_crtc crtc;
+       struct shmob_drm_encoder encoder;
+       struct shmob_drm_connector connector;
+};
+
+#endif /* __SHMOB_DRM_DRV_H__ */
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_kms.c b/drivers/gpu/drm/shmobile/shmob_drm_kms.c
new file mode 100644 (file)
index 0000000..c291ee3
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * shmob_drm_kms.c  --  SH Mobile DRM Mode Setting
+ *
+ * Copyright (C) 2012 Renesas Corporation
+ *
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include <video/sh_mobile_meram.h>
+
+#include "shmob_drm_crtc.h"
+#include "shmob_drm_drv.h"
+#include "shmob_drm_kms.h"
+#include "shmob_drm_regs.h"
+
+/* -----------------------------------------------------------------------------
+ * Format helpers
+ */
+
+static const struct shmob_drm_format_info shmob_drm_format_infos[] = {
+       {
+               .fourcc = DRM_FORMAT_RGB565,
+               .bpp = 16,
+               .yuv = false,
+               .lddfr = LDDFR_PKF_RGB16,
+               .meram = SH_MOBILE_MERAM_PF_RGB,
+       }, {
+               .fourcc = DRM_FORMAT_RGB888,
+               .bpp = 24,
+               .yuv = false,
+               .lddfr = LDDFR_PKF_RGB24,
+               .meram = SH_MOBILE_MERAM_PF_RGB,
+       }, {
+               .fourcc = DRM_FORMAT_ARGB8888,
+               .bpp = 32,
+               .yuv = false,
+               .lddfr = LDDFR_PKF_ARGB32,
+               .meram = SH_MOBILE_MERAM_PF_RGB,
+       }, {
+               .fourcc = DRM_FORMAT_NV12,
+               .bpp = 12,
+               .yuv = true,
+               .lddfr = LDDFR_CC | LDDFR_YF_420,
+               .meram = SH_MOBILE_MERAM_PF_NV,
+       }, {
+               .fourcc = DRM_FORMAT_NV21,
+               .bpp = 12,
+               .yuv = true,
+               .lddfr = LDDFR_CC | LDDFR_YF_420,
+               .meram = SH_MOBILE_MERAM_PF_NV,
+       }, {
+               .fourcc = DRM_FORMAT_NV16,
+               .bpp = 16,
+               .yuv = true,
+               .lddfr = LDDFR_CC | LDDFR_YF_422,
+               .meram = SH_MOBILE_MERAM_PF_NV,
+       }, {
+               .fourcc = DRM_FORMAT_NV61,
+               .bpp = 16,
+               .yuv = true,
+               .lddfr = LDDFR_CC | LDDFR_YF_422,
+               .meram = SH_MOBILE_MERAM_PF_NV,
+       }, {
+               .fourcc = DRM_FORMAT_NV24,
+               .bpp = 24,
+               .yuv = true,
+               .lddfr = LDDFR_CC | LDDFR_YF_444,
+               .meram = SH_MOBILE_MERAM_PF_NV24,
+       }, {
+               .fourcc = DRM_FORMAT_NV42,
+               .bpp = 24,
+               .yuv = true,
+               .lddfr = LDDFR_CC | LDDFR_YF_444,
+               .meram = SH_MOBILE_MERAM_PF_NV24,
+       },
+};
+
+const struct shmob_drm_format_info *shmob_drm_format_info(u32 fourcc)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(shmob_drm_format_infos); ++i) {
+               if (shmob_drm_format_infos[i].fourcc == fourcc)
+                       return &shmob_drm_format_infos[i];
+       }
+
+       return NULL;
+}
+
+/* -----------------------------------------------------------------------------
+ * Frame buffer
+ */
+
+static struct drm_framebuffer *
+shmob_drm_fb_create(struct drm_device *dev, struct drm_file *file_priv,
+                   struct drm_mode_fb_cmd2 *mode_cmd)
+{
+       const struct shmob_drm_format_info *format;
+
+       format = shmob_drm_format_info(mode_cmd->pixel_format);
+       if (format == NULL) {
+               dev_dbg(dev->dev, "unsupported pixel format %08x\n",
+                       mode_cmd->pixel_format);
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (mode_cmd->pitches[0] & 7 || mode_cmd->pitches[0] >= 65536) {
+               dev_dbg(dev->dev, "valid pitch value %u\n",
+                       mode_cmd->pitches[0]);
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (format->yuv) {
+               unsigned int chroma_cpp = format->bpp == 24 ? 2 : 1;
+
+               if (mode_cmd->pitches[1] != mode_cmd->pitches[0] * chroma_cpp) {
+                       dev_dbg(dev->dev,
+                               "luma and chroma pitches do not match\n");
+                       return ERR_PTR(-EINVAL);
+               }
+       }
+
+       return drm_fb_cma_create(dev, file_priv, mode_cmd);
+}
+
+static const struct drm_mode_config_funcs shmob_drm_mode_config_funcs = {
+       .fb_create = shmob_drm_fb_create,
+};
+
+int shmob_drm_modeset_init(struct shmob_drm_device *sdev)
+{
+       drm_mode_config_init(sdev->ddev);
+
+       shmob_drm_crtc_create(sdev);
+       shmob_drm_encoder_create(sdev);
+       shmob_drm_connector_create(sdev, &sdev->encoder.encoder);
+
+       drm_kms_helper_poll_init(sdev->ddev);
+
+       sdev->ddev->mode_config.min_width = 0;
+       sdev->ddev->mode_config.min_height = 0;
+       sdev->ddev->mode_config.max_width = 4095;
+       sdev->ddev->mode_config.max_height = 4095;
+       sdev->ddev->mode_config.funcs = &shmob_drm_mode_config_funcs;
+
+       drm_helper_disable_unused_functions(sdev->ddev);
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_kms.h b/drivers/gpu/drm/shmobile/shmob_drm_kms.h
new file mode 100644 (file)
index 0000000..9495c91
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * shmob_drm_kms.h  --  SH Mobile DRM Mode Setting
+ *
+ * Copyright (C) 2012 Renesas Corporation
+ *
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __SHMOB_DRM_KMS_H__
+#define __SHMOB_DRM_KMS_H__
+
+#include <linux/types.h>
+
+struct drm_gem_cma_object;
+struct shmob_drm_device;
+
+struct shmob_drm_format_info {
+       u32 fourcc;
+       unsigned int bpp;
+       bool yuv;
+       u32 lddfr;
+       unsigned int meram;
+};
+
+const struct shmob_drm_format_info *shmob_drm_format_info(u32 fourcc);
+
+int shmob_drm_modeset_init(struct shmob_drm_device *sdev);
+
+#endif /* __SHMOB_DRM_KMS_H__ */
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/shmobile/shmob_drm_plane.c
new file mode 100644 (file)
index 0000000..e1eb899
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * shmob_drm_plane.c  --  SH Mobile DRM Planes
+ *
+ * Copyright (C) 2012 Renesas Corporation
+ *
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include <video/sh_mobile_meram.h>
+
+#include "shmob_drm_drv.h"
+#include "shmob_drm_kms.h"
+#include "shmob_drm_plane.h"
+#include "shmob_drm_regs.h"
+
+struct shmob_drm_plane {
+       struct drm_plane plane;
+       unsigned int index;
+       unsigned int alpha;
+
+       const struct shmob_drm_format_info *format;
+       unsigned long dma[2];
+
+       unsigned int src_x;
+       unsigned int src_y;
+       unsigned int crtc_x;
+       unsigned int crtc_y;
+       unsigned int crtc_w;
+       unsigned int crtc_h;
+};
+
+#define to_shmob_plane(p)      container_of(p, struct shmob_drm_plane, plane)
+
+static void shmob_drm_plane_compute_base(struct shmob_drm_plane *splane,
+                                        struct drm_framebuffer *fb,
+                                        int x, int y)
+{
+       struct drm_gem_cma_object *gem;
+       unsigned int bpp;
+
+       bpp = splane->format->yuv ? 8 : splane->format->bpp;
+       gem = drm_fb_cma_get_gem_obj(fb, 0);
+       splane->dma[0] = gem->paddr + fb->offsets[0]
+                      + y * fb->pitches[0] + x * bpp / 8;
+
+       if (splane->format->yuv) {
+               bpp = splane->format->bpp - 8;
+               gem = drm_fb_cma_get_gem_obj(fb, 1);
+               splane->dma[1] = gem->paddr + fb->offsets[1]
+                              + y / (bpp == 4 ? 2 : 1) * fb->pitches[1]
+                              + x * (bpp == 16 ? 2 : 1);
+       }
+}
+
+static void __shmob_drm_plane_setup(struct shmob_drm_plane *splane,
+                                   struct drm_framebuffer *fb)
+{
+       struct shmob_drm_device *sdev = splane->plane.dev->dev_private;
+       u32 format;
+
+       /* TODO: Support ROP3 mode */
+       format = LDBBSIFR_EN | (splane->alpha << LDBBSIFR_LAY_SHIFT);
+
+       switch (splane->format->fourcc) {
+       case DRM_FORMAT_RGB565:
+       case DRM_FORMAT_NV21:
+       case DRM_FORMAT_NV61:
+       case DRM_FORMAT_NV42:
+               format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW;
+               break;
+       case DRM_FORMAT_RGB888:
+       case DRM_FORMAT_NV12:
+       case DRM_FORMAT_NV16:
+       case DRM_FORMAT_NV24:
+               format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW | LDBBSIFR_SWPB;
+               break;
+       case DRM_FORMAT_ARGB8888:
+       default:
+               format |= LDBBSIFR_SWPL;
+               break;
+       }
+
+       switch (splane->format->fourcc) {
+       case DRM_FORMAT_RGB565:
+               format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB16;
+               break;
+       case DRM_FORMAT_RGB888:
+               format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24;
+               break;
+       case DRM_FORMAT_ARGB8888:
+               format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDDFR_PKF_ARGB32;
+               break;
+       case DRM_FORMAT_NV12:
+       case DRM_FORMAT_NV21:
+               format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_420;
+               break;
+       case DRM_FORMAT_NV16:
+       case DRM_FORMAT_NV61:
+               format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_422;
+               break;
+       case DRM_FORMAT_NV24:
+       case DRM_FORMAT_NV42:
+               format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_444;
+               break;
+       }
+
+#define plane_reg_dump(sdev, splane, reg) \
+       dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x 0x%08x\n", __func__, \
+               splane->index, #reg, \
+               lcdc_read(sdev, reg(splane->index)), \
+               lcdc_read(sdev, reg(splane->index) + LCDC_SIDE_B_OFFSET))
+
+       plane_reg_dump(sdev, splane, LDBnBSIFR);
+       plane_reg_dump(sdev, splane, LDBnBSSZR);
+       plane_reg_dump(sdev, splane, LDBnBLOCR);
+       plane_reg_dump(sdev, splane, LDBnBSMWR);
+       plane_reg_dump(sdev, splane, LDBnBSAYR);
+       plane_reg_dump(sdev, splane, LDBnBSACR);
+
+       lcdc_write(sdev, LDBCR, LDBCR_UPC(splane->index));
+       dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,
+               "LDBCR", lcdc_read(sdev, LDBCR));
+
+       lcdc_write(sdev, LDBnBSIFR(splane->index), format);
+
+       lcdc_write(sdev, LDBnBSSZR(splane->index),
+                  (splane->crtc_h << LDBBSSZR_BVSS_SHIFT) |
+                  (splane->crtc_w << LDBBSSZR_BHSS_SHIFT));
+       lcdc_write(sdev, LDBnBLOCR(splane->index),
+                  (splane->crtc_y << LDBBLOCR_CVLC_SHIFT) |
+                  (splane->crtc_x << LDBBLOCR_CHLC_SHIFT));
+       lcdc_write(sdev, LDBnBSMWR(splane->index),
+                  fb->pitches[0] << LDBBSMWR_BSMW_SHIFT);
+
+       shmob_drm_plane_compute_base(splane, fb, splane->src_x, splane->src_y);
+
+       lcdc_write(sdev, LDBnBSAYR(splane->index), splane->dma[0]);
+       if (splane->format->yuv)
+               lcdc_write(sdev, LDBnBSACR(splane->index), splane->dma[1]);
+
+       lcdc_write(sdev, LDBCR,
+                  LDBCR_UPF(splane->index) | LDBCR_UPD(splane->index));
+       dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,
+               "LDBCR", lcdc_read(sdev, LDBCR));
+
+       plane_reg_dump(sdev, splane, LDBnBSIFR);
+       plane_reg_dump(sdev, splane, LDBnBSSZR);
+       plane_reg_dump(sdev, splane, LDBnBLOCR);
+       plane_reg_dump(sdev, splane, LDBnBSMWR);
+       plane_reg_dump(sdev, splane, LDBnBSAYR);
+       plane_reg_dump(sdev, splane, LDBnBSACR);
+}
+
+void shmob_drm_plane_setup(struct drm_plane *plane)
+{
+       struct shmob_drm_plane *splane = to_shmob_plane(plane);
+
+       if (plane->fb == NULL || !plane->enabled)
+               return;
+
+       __shmob_drm_plane_setup(splane, plane->fb);
+}
+
+static int
+shmob_drm_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
+                      struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+                      unsigned int crtc_w, unsigned int crtc_h,
+                      uint32_t src_x, uint32_t src_y,
+                      uint32_t src_w, uint32_t src_h)
+{
+       struct shmob_drm_plane *splane = to_shmob_plane(plane);
+       struct shmob_drm_device *sdev = plane->dev->dev_private;
+       const struct shmob_drm_format_info *format;
+
+       format = shmob_drm_format_info(fb->pixel_format);
+       if (format == NULL) {
+               dev_dbg(sdev->dev, "update_plane: unsupported format %08x\n",
+                       fb->pixel_format);
+               return -EINVAL;
+       }
+
+       if (src_w >> 16 != crtc_w || src_h >> 16 != crtc_h) {
+               dev_dbg(sdev->dev, "%s: scaling not supported\n", __func__);
+               return -EINVAL;
+       }
+
+       splane->format = format;
+
+       splane->src_x = src_x >> 16;
+       splane->src_y = src_y >> 16;
+       splane->crtc_x = crtc_x;
+       splane->crtc_y = crtc_y;
+       splane->crtc_w = crtc_w;
+       splane->crtc_h = crtc_h;
+
+       __shmob_drm_plane_setup(splane, fb);
+       return 0;
+}
+
+static int shmob_drm_plane_disable(struct drm_plane *plane)
+{
+       struct shmob_drm_plane *splane = to_shmob_plane(plane);
+       struct shmob_drm_device *sdev = plane->dev->dev_private;
+
+       splane->format = NULL;
+
+       lcdc_write(sdev, LDBnBSIFR(splane->index), 0);
+       return 0;
+}
+
+static void shmob_drm_plane_destroy(struct drm_plane *plane)
+{
+       struct shmob_drm_plane *splane = to_shmob_plane(plane);
+
+       shmob_drm_plane_disable(plane);
+       drm_plane_cleanup(plane);
+       kfree(splane);
+}
+
+static const struct drm_plane_funcs shmob_drm_plane_funcs = {
+       .update_plane = shmob_drm_plane_update,
+       .disable_plane = shmob_drm_plane_disable,
+       .destroy = shmob_drm_plane_destroy,
+};
+
+static const uint32_t formats[] = {
+       DRM_FORMAT_RGB565,
+       DRM_FORMAT_RGB888,
+       DRM_FORMAT_ARGB8888,
+       DRM_FORMAT_NV12,
+       DRM_FORMAT_NV21,
+       DRM_FORMAT_NV16,
+       DRM_FORMAT_NV61,
+       DRM_FORMAT_NV24,
+       DRM_FORMAT_NV42,
+};
+
+int shmob_drm_plane_create(struct shmob_drm_device *sdev, unsigned int index)
+{
+       struct shmob_drm_plane *splane;
+       int ret;
+
+       splane = kzalloc(sizeof(*splane), GFP_KERNEL);
+       if (splane == NULL)
+               return -ENOMEM;
+
+       splane->index = index;
+       splane->alpha = 255;
+
+       ret = drm_plane_init(sdev->ddev, &splane->plane, 1,
+                            &shmob_drm_plane_funcs, formats,
+                            ARRAY_SIZE(formats), false);
+       if (ret < 0)
+               kfree(splane);
+
+       return ret;
+}
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.h b/drivers/gpu/drm/shmobile/shmob_drm_plane.h
new file mode 100644 (file)
index 0000000..99623d0
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * shmob_drm_plane.h  --  SH Mobile DRM Planes
+ *
+ * Copyright (C) 2012 Renesas Corporation
+ *
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __SHMOB_DRM_PLANE_H__
+#define __SHMOB_DRM_PLANE_H__
+
+struct shmob_drm_device;
+
+int shmob_drm_plane_create(struct shmob_drm_device *sdev, unsigned int index);
+void shmob_drm_plane_setup(struct drm_plane *plane);
+
+#endif /* __SHMOB_DRM_PLANE_H__ */
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_regs.h b/drivers/gpu/drm/shmobile/shmob_drm_regs.h
new file mode 100644 (file)
index 0000000..7923cdd
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * shmob_drm_regs.h  --  SH Mobile DRM registers
+ *
+ * Copyright (C) 2012 Renesas Corporation
+ *
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __SHMOB_DRM_REGS_H__
+#define __SHMOB_DRM_REGS_H__
+
+#include <linux/io.h>
+
+/* Register definitions */
+#define LDDCKPAT1R             0x400
+#define LDDCKPAT2R             0x404
+#define LDDCKR                 0x410
+#define LDDCKR_ICKSEL_BUS      (0 << 16)
+#define LDDCKR_ICKSEL_MIPI     (1 << 16)
+#define LDDCKR_ICKSEL_HDMI     (2 << 16)
+#define LDDCKR_ICKSEL_EXT      (3 << 16)
+#define LDDCKR_ICKSEL_MASK     (7 << 16)
+#define LDDCKR_MOSEL           (1 << 6)
+#define LDDCKSTPR              0x414
+#define LDDCKSTPR_DCKSTS       (1 << 16)
+#define LDDCKSTPR_DCKSTP       (1 << 0)
+#define LDMT1R                 0x418
+#define LDMT1R_VPOL            (1 << 28)
+#define LDMT1R_HPOL            (1 << 27)
+#define LDMT1R_DWPOL           (1 << 26)
+#define LDMT1R_DIPOL           (1 << 25)
+#define LDMT1R_DAPOL           (1 << 24)
+#define LDMT1R_HSCNT           (1 << 17)
+#define LDMT1R_DWCNT           (1 << 16)
+#define LDMT1R_IFM             (1 << 12)
+#define LDMT1R_MIFTYP_RGB8     (0x0 << 0)
+#define LDMT1R_MIFTYP_RGB9     (0x4 << 0)
+#define LDMT1R_MIFTYP_RGB12A   (0x5 << 0)
+#define LDMT1R_MIFTYP_RGB12B   (0x6 << 0)
+#define LDMT1R_MIFTYP_RGB16    (0x7 << 0)
+#define LDMT1R_MIFTYP_RGB18    (0xa << 0)
+#define LDMT1R_MIFTYP_RGB24    (0xb << 0)
+#define LDMT1R_MIFTYP_YCBCR    (0xf << 0)
+#define LDMT1R_MIFTYP_SYS8A    (0x0 << 0)
+#define LDMT1R_MIFTYP_SYS8B    (0x1 << 0)
+#define LDMT1R_MIFTYP_SYS8C    (0x2 << 0)
+#define LDMT1R_MIFTYP_SYS8D    (0x3 << 0)
+#define LDMT1R_MIFTYP_SYS9     (0x4 << 0)
+#define LDMT1R_MIFTYP_SYS12    (0x5 << 0)
+#define LDMT1R_MIFTYP_SYS16A   (0x7 << 0)
+#define LDMT1R_MIFTYP_SYS16B   (0x8 << 0)
+#define LDMT1R_MIFTYP_SYS16C   (0x9 << 0)
+#define LDMT1R_MIFTYP_SYS18    (0xa << 0)
+#define LDMT1R_MIFTYP_SYS24    (0xb << 0)
+#define LDMT1R_MIFTYP_MASK     (0xf << 0)
+#define LDMT2R                 0x41c
+#define LDMT2R_CSUP_MASK       (7 << 26)
+#define LDMT2R_CSUP_SHIFT      26
+#define LDMT2R_RSV             (1 << 25)
+#define LDMT2R_VSEL            (1 << 24)
+#define LDMT2R_WCSC_MASK       (0xff << 16)
+#define LDMT2R_WCSC_SHIFT      16
+#define LDMT2R_WCEC_MASK       (0xff << 8)
+#define LDMT2R_WCEC_SHIFT      8
+#define LDMT2R_WCLW_MASK       (0xff << 0)
+#define LDMT2R_WCLW_SHIFT      0
+#define LDMT3R                 0x420
+#define LDMT3R_RDLC_MASK       (0x3f << 24)
+#define LDMT3R_RDLC_SHIFT      24
+#define LDMT3R_RCSC_MASK       (0xff << 16)
+#define LDMT3R_RCSC_SHIFT      16
+#define LDMT3R_RCEC_MASK       (0xff << 8)
+#define LDMT3R_RCEC_SHIFT      8
+#define LDMT3R_RCLW_MASK       (0xff << 0)
+#define LDMT3R_RCLW_SHIFT      0
+#define LDDFR                  0x424
+#define LDDFR_CF1              (1 << 18)
+#define LDDFR_CF0              (1 << 17)
+#define LDDFR_CC               (1 << 16)
+#define LDDFR_YF_420           (0 << 8)
+#define LDDFR_YF_422           (1 << 8)
+#define LDDFR_YF_444           (2 << 8)
+#define LDDFR_YF_MASK          (3 << 8)
+#define LDDFR_PKF_ARGB32       (0x00 << 0)
+#define LDDFR_PKF_RGB16                (0x03 << 0)
+#define LDDFR_PKF_RGB24                (0x0b << 0)
+#define LDDFR_PKF_MASK         (0x1f << 0)
+#define LDSM1R                 0x428
+#define LDSM1R_OS              (1 << 0)
+#define LDSM2R                 0x42c
+#define LDSM2R_OSTRG           (1 << 0)
+#define LDSA1R                 0x430
+#define LDSA2R                 0x434
+#define LDMLSR                 0x438
+#define LDWBFR                 0x43c
+#define LDWBCNTR               0x440
+#define LDWBAR                 0x444
+#define LDHCNR                 0x448
+#define LDHSYNR                        0x44c
+#define LDVLNR                 0x450
+#define LDVSYNR                        0x454
+#define LDHPDR                 0x458
+#define LDVPDR                 0x45c
+#define LDPMR                  0x460
+#define LDPMR_LPS              (3 << 0)
+#define LDINTR                 0x468
+#define LDINTR_FE              (1 << 10)
+#define LDINTR_VSE             (1 << 9)
+#define LDINTR_VEE             (1 << 8)
+#define LDINTR_FS              (1 << 2)
+#define LDINTR_VSS             (1 << 1)
+#define LDINTR_VES             (1 << 0)
+#define LDINTR_STATUS_MASK     (0xff << 0)
+#define LDSR                   0x46c
+#define LDSR_MSS               (1 << 10)
+#define LDSR_MRS               (1 << 8)
+#define LDSR_AS                        (1 << 1)
+#define LDCNT1R                        0x470
+#define LDCNT1R_DE             (1 << 0)
+#define LDCNT2R                        0x474
+#define LDCNT2R_BR             (1 << 8)
+#define LDCNT2R_MD             (1 << 3)
+#define LDCNT2R_SE             (1 << 2)
+#define LDCNT2R_ME             (1 << 1)
+#define LDCNT2R_DO             (1 << 0)
+#define LDRCNTR                        0x478
+#define LDRCNTR_SRS            (1 << 17)
+#define LDRCNTR_SRC            (1 << 16)
+#define LDRCNTR_MRS            (1 << 1)
+#define LDRCNTR_MRC            (1 << 0)
+#define LDDDSR                 0x47c
+#define LDDDSR_LS              (1 << 2)
+#define LDDDSR_WS              (1 << 1)
+#define LDDDSR_BS              (1 << 0)
+#define LDHAJR                 0x4a0
+
+#define LDDWD0R                        0x800
+#define LDDWDxR_WDACT          (1 << 28)
+#define LDDWDxR_RSW            (1 << 24)
+#define LDDRDR                 0x840
+#define LDDRDR_RSR             (1 << 24)
+#define LDDRDR_DRD_MASK                (0x3ffff << 0)
+#define LDDWAR                 0x900
+#define LDDWAR_WA              (1 << 0)
+#define LDDRAR                 0x904
+#define LDDRAR_RA              (1 << 0)
+
+#define LDBCR                  0xb00
+#define LDBCR_UPC(n)           (1 << ((n) + 16))
+#define LDBCR_UPF(n)           (1 << ((n) + 8))
+#define LDBCR_UPD(n)           (1 << ((n) + 0))
+#define LDBnBSIFR(n)           (0xb20 + (n) * 0x20 + 0x00)
+#define LDBBSIFR_EN            (1 << 31)
+#define LDBBSIFR_VS            (1 << 29)
+#define LDBBSIFR_BRSEL         (1 << 28)
+#define LDBBSIFR_MX            (1 << 27)
+#define LDBBSIFR_MY            (1 << 26)
+#define LDBBSIFR_CV3           (3 << 24)
+#define LDBBSIFR_CV2           (2 << 24)
+#define LDBBSIFR_CV1           (1 << 24)
+#define LDBBSIFR_CV0           (0 << 24)
+#define LDBBSIFR_CV_MASK       (3 << 24)
+#define LDBBSIFR_LAY_MASK      (0xff << 16)
+#define LDBBSIFR_LAY_SHIFT     16
+#define LDBBSIFR_ROP3_MASK     (0xff << 16)
+#define LDBBSIFR_ROP3_SHIFT    16
+#define LDBBSIFR_AL_PL8                (3 << 14)
+#define LDBBSIFR_AL_PL1                (2 << 14)
+#define LDBBSIFR_AL_PK         (1 << 14)
+#define LDBBSIFR_AL_1          (0 << 14)
+#define LDBBSIFR_AL_MASK       (3 << 14)
+#define LDBBSIFR_SWPL          (1 << 10)
+#define LDBBSIFR_SWPW          (1 << 9)
+#define LDBBSIFR_SWPB          (1 << 8)
+#define LDBBSIFR_RY            (1 << 7)
+#define LDBBSIFR_CHRR_420      (2 << 0)
+#define LDBBSIFR_CHRR_422      (1 << 0)
+#define LDBBSIFR_CHRR_444      (0 << 0)
+#define LDBBSIFR_RPKF_ARGB32   (0x00 << 0)
+#define LDBBSIFR_RPKF_RGB16    (0x03 << 0)
+#define LDBBSIFR_RPKF_RGB24    (0x0b << 0)
+#define LDBBSIFR_RPKF_MASK     (0x1f << 0)
+#define LDBnBSSZR(n)           (0xb20 + (n) * 0x20 + 0x04)
+#define LDBBSSZR_BVSS_MASK     (0xfff << 16)
+#define LDBBSSZR_BVSS_SHIFT    16
+#define LDBBSSZR_BHSS_MASK     (0xfff << 0)
+#define LDBBSSZR_BHSS_SHIFT    0
+#define LDBnBLOCR(n)           (0xb20 + (n) * 0x20 + 0x08)
+#define LDBBLOCR_CVLC_MASK     (0xfff << 16)
+#define LDBBLOCR_CVLC_SHIFT    16
+#define LDBBLOCR_CHLC_MASK     (0xfff << 0)
+#define LDBBLOCR_CHLC_SHIFT    0
+#define LDBnBSMWR(n)           (0xb20 + (n) * 0x20 + 0x0c)
+#define LDBBSMWR_BSMWA_MASK    (0xffff << 16)
+#define LDBBSMWR_BSMWA_SHIFT   16
+#define LDBBSMWR_BSMW_MASK     (0xffff << 0)
+#define LDBBSMWR_BSMW_SHIFT    0
+#define LDBnBSAYR(n)           (0xb20 + (n) * 0x20 + 0x10)
+#define LDBBSAYR_FG1A_MASK     (0xff << 24)
+#define LDBBSAYR_FG1A_SHIFT    24
+#define LDBBSAYR_FG1R_MASK     (0xff << 16)
+#define LDBBSAYR_FG1R_SHIFT    16
+#define LDBBSAYR_FG1G_MASK     (0xff << 8)
+#define LDBBSAYR_FG1G_SHIFT    8
+#define LDBBSAYR_FG1B_MASK     (0xff << 0)
+#define LDBBSAYR_FG1B_SHIFT    0
+#define LDBnBSACR(n)           (0xb20 + (n) * 0x20 + 0x14)
+#define LDBBSACR_FG2A_MASK     (0xff << 24)
+#define LDBBSACR_FG2A_SHIFT    24
+#define LDBBSACR_FG2R_MASK     (0xff << 16)
+#define LDBBSACR_FG2R_SHIFT    16
+#define LDBBSACR_FG2G_MASK     (0xff << 8)
+#define LDBBSACR_FG2G_SHIFT    8
+#define LDBBSACR_FG2B_MASK     (0xff << 0)
+#define LDBBSACR_FG2B_SHIFT    0
+#define LDBnBSAAR(n)           (0xb20 + (n) * 0x20 + 0x18)
+#define LDBBSAAR_AP_MASK       (0xff << 24)
+#define LDBBSAAR_AP_SHIFT      24
+#define LDBBSAAR_R_MASK                (0xff << 16)
+#define LDBBSAAR_R_SHIFT       16
+#define LDBBSAAR_GY_MASK       (0xff << 8)
+#define LDBBSAAR_GY_SHIFT      8
+#define LDBBSAAR_B_MASK                (0xff << 0)
+#define LDBBSAAR_B_SHIFT       0
+#define LDBnBPPCR(n)           (0xb20 + (n) * 0x20 + 0x1c)
+#define LDBBPPCR_AP_MASK       (0xff << 24)
+#define LDBBPPCR_AP_SHIFT      24
+#define LDBBPPCR_R_MASK                (0xff << 16)
+#define LDBBPPCR_R_SHIFT       16
+#define LDBBPPCR_GY_MASK       (0xff << 8)
+#define LDBBPPCR_GY_SHIFT      8
+#define LDBBPPCR_B_MASK                (0xff << 0)
+#define LDBBPPCR_B_SHIFT       0
+#define LDBnBBGCL(n)           (0xb10 + (n) * 0x04)
+#define LDBBBGCL_BGA_MASK      (0xff << 24)
+#define LDBBBGCL_BGA_SHIFT     24
+#define LDBBBGCL_BGR_MASK      (0xff << 16)
+#define LDBBBGCL_BGR_SHIFT     16
+#define LDBBBGCL_BGG_MASK      (0xff << 8)
+#define LDBBBGCL_BGG_SHIFT     8
+#define LDBBBGCL_BGB_MASK      (0xff << 0)
+#define LDBBBGCL_BGB_SHIFT     0
+
+#define LCDC_SIDE_B_OFFSET     0x1000
+#define LCDC_MIRROR_OFFSET     0x2000
+
+static inline bool lcdc_is_banked(u32 reg)
+{
+       switch (reg) {
+       case LDMT1R:
+       case LDMT2R:
+       case LDMT3R:
+       case LDDFR:
+       case LDSM1R:
+       case LDSA1R:
+       case LDSA2R:
+       case LDMLSR:
+       case LDWBFR:
+       case LDWBCNTR:
+       case LDWBAR:
+       case LDHCNR:
+       case LDHSYNR:
+       case LDVLNR:
+       case LDVSYNR:
+       case LDHPDR:
+       case LDVPDR:
+       case LDHAJR:
+               return true;
+       default:
+               return reg >= LDBnBBGCL(0) && reg <= LDBnBPPCR(3);
+       }
+}
+
+static inline void lcdc_write_mirror(struct shmob_drm_device *sdev, u32 reg,
+                                    u32 data)
+{
+       iowrite32(data, sdev->mmio + reg + LCDC_MIRROR_OFFSET);
+}
+
+static inline void lcdc_write(struct shmob_drm_device *sdev, u32 reg, u32 data)
+{
+       iowrite32(data, sdev->mmio + reg);
+       if (lcdc_is_banked(reg))
+               iowrite32(data, sdev->mmio + reg + LCDC_SIDE_B_OFFSET);
+}
+
+static inline u32 lcdc_read(struct shmob_drm_device *sdev, u32 reg)
+{
+       return ioread32(sdev->mmio + reg);
+}
+
+static inline int lcdc_wait_bit(struct shmob_drm_device *sdev, u32 reg,
+                               u32 mask, u32 until)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(5);
+
+       while ((lcdc_read(sdev, reg) & mask) != until) {
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+               cpu_relax();
+       }
+
+       return 0;
+}
+
+#endif /* __SHMOB_DRM_REGS_H__ */
index 4c2d836a0893f36f91247a5ce38d6cfed883faa8..40bf468c46c27b492bb00f48d671a36f53d0f86f 100644 (file)
@@ -41,11 +41,8 @@ static int udl_parse_vendor_descriptor(struct drm_device *dev,
        total_len = usb_get_descriptor(usbdev, 0x5f, /* vendor specific */
                                    0, desc, MAX_VENDOR_DESCRIPTOR_SIZE);
        if (total_len > 5) {
-               DRM_INFO("vendor descriptor length:%x data:%02x %02x %02x %02x" \
-                       "%02x %02x %02x %02x %02x %02x %02x\n",
-                       total_len, desc[0],
-                       desc[1], desc[2], desc[3], desc[4], desc[5], desc[6],
-                       desc[7], desc[8], desc[9], desc[10]);
+               DRM_INFO("vendor descriptor length:%x data:%*ph\n",
+                       total_len, 11, desc);
 
                if ((desc[0] != total_len) || /* descriptor length */
                    (desc[1] != 0x5f) ||   /* vendor descriptor type */
index 4d9edead01acdbcb900a3fdca87d5ed08cdab682..3e47f7570861e64e7607864546dd595f0c4153ec 100644 (file)
@@ -437,7 +437,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
                DRM_ERROR("Failed allocating a device private struct.\n");
                return -ENOMEM;
        }
-       memset(dev_priv, 0, sizeof(*dev_priv));
 
        pci_set_master(dev->pdev);
 
index c50724bd30f6e052e2f80e6f823379241944ff60..54743943d8b328320de41e231763b3878c4a4744 100644 (file)
@@ -483,7 +483,6 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
        }
 
        /* only need to do this once */
-       memset(cmd, 0, fifo_size);
        cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN);
        cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header));
 
index 617d87ae2b1a51d207d7c3e637ee6f7197b7d854..316ce64e5590bfeb033afca2c36d998c45b49b36 100644 (file)
@@ -590,6 +590,7 @@ struct drm_connector {
        int video_latency[2];   /* [0]: progressive, [1]: interlaced */
        int audio_latency[2];
        int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */
+       unsigned bad_edid_counter;
 };
 
 /**
@@ -1032,7 +1033,7 @@ 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, int block);
+extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid);
 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,
diff --git a/include/drm/drm_fb_cma_helper.h b/include/drm/drm_fb_cma_helper.h
new file mode 100644 (file)
index 0000000..76c7098
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __DRM_FB_CMA_HELPER_H__
+#define __DRM_FB_CMA_HELPER_H__
+
+struct drm_fbdev_cma;
+struct drm_gem_cma_object;
+
+struct drm_framebuffer;
+struct drm_device;
+struct drm_file;
+struct drm_mode_fb_cmd2;
+
+struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev,
+       unsigned int preferred_bpp, unsigned int num_crtc,
+       unsigned int max_conn_count);
+void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma);
+
+void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma);
+void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma);
+
+struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev,
+       struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd);
+
+struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb,
+       unsigned int plane);
+
+#endif
+
index bdf0152cbbe95b2747f0736366f520eabb193ea9..fac7235281f11c8526e4559b6897497bbd54c2cc 100644 (file)
 #define DRM_FORMAT_NV21                fourcc_code('N', 'V', '2', '1') /* 2x2 subsampled Cb:Cr plane */
 #define DRM_FORMAT_NV16                fourcc_code('N', 'V', '1', '6') /* 2x1 subsampled Cr:Cb plane */
 #define DRM_FORMAT_NV61                fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */
+#define DRM_FORMAT_NV24                fourcc_code('N', 'V', '2', '4') /* non-subsampled Cr:Cb plane */
+#define DRM_FORMAT_NV42                fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */
 
 /* 2 non contiguous plane YCbCr */
 #define DRM_FORMAT_NV12M       fourcc_code('N', 'M', '1', '2') /* 2x2 subsampled Cr:Cb plane */
diff --git a/include/drm/drm_gem_cma_helper.h b/include/drm/drm_gem_cma_helper.h
new file mode 100644 (file)
index 0000000..f0f6b1a
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef __DRM_GEM_CMA_HELPER_H__
+#define __DRM_GEM_CMA_HELPER_H__
+
+struct drm_gem_cma_object {
+       struct drm_gem_object base;
+       dma_addr_t paddr;
+       void *vaddr;
+};
+
+static inline struct drm_gem_cma_object *
+to_drm_gem_cma_obj(struct drm_gem_object *gem_obj)
+{
+       return container_of(gem_obj, struct drm_gem_cma_object, base);
+}
+
+/* free gem object. */
+void drm_gem_cma_free_object(struct drm_gem_object *gem_obj);
+
+/* create memory region for drm framebuffer. */
+int drm_gem_cma_dumb_create(struct drm_file *file_priv,
+               struct drm_device *drm, struct drm_mode_create_dumb *args);
+
+/* map memory region for drm framebuffer to user space. */
+int drm_gem_cma_dumb_map_offset(struct drm_file *file_priv,
+               struct drm_device *drm, uint32_t handle, uint64_t *offset);
+
+/* set vm_flags and we can change the vm attribute to other one at here. */
+int drm_gem_cma_mmap(struct file *filp, struct vm_area_struct *vma);
+
+/*
+ * destroy memory region allocated.
+ *     - a gem handle and physical memory region pointed by a gem object
+ *     would be released by drm_gem_handle_delete().
+ */
+int drm_gem_cma_dumb_destroy(struct drm_file *file_priv,
+               struct drm_device *drm, unsigned int handle);
+
+/* allocate physical memory. */
+struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm,
+               unsigned int size);
+
+extern const struct vm_operations_struct drm_gem_cma_vm_ops;
+
+#endif /* __DRM_GEM_CMA_HELPER_H__ */
diff --git a/include/linux/platform_data/shmob_drm.h b/include/linux/platform_data/shmob_drm.h
new file mode 100644 (file)
index 0000000..7c686d3
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * shmob_drm.h  --  SH Mobile DRM driver
+ *
+ * Copyright (C) 2012 Renesas Corporation
+ *
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __SHMOB_DRM_H__
+#define __SHMOB_DRM_H__
+
+#include <linux/kernel.h>
+
+#include <drm/drm_mode.h>
+
+struct sh_mobile_meram_cfg;
+struct sh_mobile_meram_info;
+
+enum shmob_drm_clk_source {
+       SHMOB_DRM_CLK_BUS,
+       SHMOB_DRM_CLK_PERIPHERAL,
+       SHMOB_DRM_CLK_EXTERNAL,
+};
+
+enum shmob_drm_interface {
+       SHMOB_DRM_IFACE_RGB8,           /* 24bpp, 8:8:8 */
+       SHMOB_DRM_IFACE_RGB9,           /* 18bpp, 9:9 */
+       SHMOB_DRM_IFACE_RGB12A,         /* 24bpp, 12:12 */
+       SHMOB_DRM_IFACE_RGB12B,         /* 12bpp */
+       SHMOB_DRM_IFACE_RGB16,          /* 16bpp */
+       SHMOB_DRM_IFACE_RGB18,          /* 18bpp */
+       SHMOB_DRM_IFACE_RGB24,          /* 24bpp */
+       SHMOB_DRM_IFACE_YUV422,         /* 16bpp */
+       SHMOB_DRM_IFACE_SYS8A,          /* 24bpp, 8:8:8 */
+       SHMOB_DRM_IFACE_SYS8B,          /* 18bpp, 8:8:2 */
+       SHMOB_DRM_IFACE_SYS8C,          /* 18bpp, 2:8:8 */
+       SHMOB_DRM_IFACE_SYS8D,          /* 16bpp, 8:8 */
+       SHMOB_DRM_IFACE_SYS9,           /* 18bpp, 9:9 */
+       SHMOB_DRM_IFACE_SYS12,          /* 24bpp, 12:12 */
+       SHMOB_DRM_IFACE_SYS16A,         /* 16bpp */
+       SHMOB_DRM_IFACE_SYS16B,         /* 18bpp, 16:2 */
+       SHMOB_DRM_IFACE_SYS16C,         /* 18bpp, 2:16 */
+       SHMOB_DRM_IFACE_SYS18,          /* 18bpp */
+       SHMOB_DRM_IFACE_SYS24,          /* 24bpp */
+};
+
+struct shmob_drm_backlight_data {
+       const char *name;
+       int max_brightness;
+       int (*get_brightness)(void);
+       int (*set_brightness)(int brightness);
+};
+
+struct shmob_drm_panel_data {
+       unsigned int width_mm;          /* Panel width in mm */
+       unsigned int height_mm;         /* Panel height in mm */
+       struct drm_mode_modeinfo mode;
+};
+
+struct shmob_drm_sys_interface_data {
+       unsigned int read_latch:6;
+       unsigned int read_setup:8;
+       unsigned int read_cycle:8;
+       unsigned int read_strobe:8;
+       unsigned int write_setup:8;
+       unsigned int write_cycle:8;
+       unsigned int write_strobe:8;
+       unsigned int cs_setup:3;
+       unsigned int vsync_active_high:1;
+       unsigned int vsync_dir_input:1;
+};
+
+#define SHMOB_DRM_IFACE_FL_DWPOL (1 << 0) /* Rising edge dot clock data latch */
+#define SHMOB_DRM_IFACE_FL_DIPOL (1 << 1) /* Active low display enable */
+#define SHMOB_DRM_IFACE_FL_DAPOL (1 << 2) /* Active low display data */
+#define SHMOB_DRM_IFACE_FL_HSCNT (1 << 3) /* Disable HSYNC during VBLANK */
+#define SHMOB_DRM_IFACE_FL_DWCNT (1 << 4) /* Disable dotclock during blanking */
+
+struct shmob_drm_interface_data {
+       enum shmob_drm_interface interface;
+       struct shmob_drm_sys_interface_data sys;
+       unsigned int clk_div;
+       unsigned int flags;
+};
+
+struct shmob_drm_platform_data {
+       enum shmob_drm_clk_source clk_source;
+       struct shmob_drm_interface_data iface;
+       struct shmob_drm_panel_data panel;
+       struct shmob_drm_backlight_data backlight;
+       const struct sh_mobile_meram_cfg *meram;
+};
+
+#endif /* __SHMOB_DRM_H__ */
This page took 0.088525 seconds and 5 git commands to generate.