Update video driver to MCG's latest code: 1)Topza support 2)Error conceal 3)Context...
authorYan Zhang <yan.y.zhang@intel.com>
Wed, 15 Aug 2012 08:37:50 +0000 (16:37 +0800)
committerYan Zhang <yan.y.zhang@intel.com>
Fri, 17 Aug 2012 06:48:07 +0000 (14:48 +0800)
Signed-off-by: Yan Zhang <yan.y.zhang@intel.com>
24 files changed:
drivers/staging/mrst/Makefile
drivers/staging/mrst/drv/psb_drm.h
drivers/staging/mrst/drv/psb_drv.c
drivers/staging/mrst/drv/psb_drv.h
drivers/staging/mrst/imgv/lnc_topaz.c [new file with mode: 0644]
drivers/staging/mrst/imgv/lnc_topaz.h [new file with mode: 0644]
drivers/staging/mrst/imgv/lnc_topaz_hw_reg.h [new file with mode: 0644]
drivers/staging/mrst/imgv/lnc_topazinit.c [new file with mode: 0644]
drivers/staging/mrst/imgv/pnw_topaz.c
drivers/staging/mrst/imgv/pnw_topaz.h
drivers/staging/mrst/imgv/pnw_topaz_hw_reg.h
drivers/staging/mrst/imgv/pnw_topazinit.c
drivers/staging/mrst/imgv/psb_buffer.c
drivers/staging/mrst/imgv/psb_fence.c
drivers/staging/mrst/imgv/psb_mmu.c
drivers/staging/mrst/imgv/psb_msvdx.c
drivers/staging/mrst/imgv/psb_msvdx.h
drivers/staging/mrst/imgv/psb_msvdx_ec.c [new file with mode: 0644]
drivers/staging/mrst/imgv/psb_msvdx_ec.h [new file with mode: 0644]
drivers/staging/mrst/imgv/psb_msvdxinit.c
drivers/staging/mrst/imgv/psb_ttm_fence.c
drivers/staging/mrst/imgv/psb_ttm_glue.c
drivers/staging/mrst/imgv/psb_ttm_placement_user.c
drivers/staging/mrst/imgv/psb_ttm_userobj_api.h

index d3860f9..d5b5b81 100644 (file)
@@ -198,6 +198,9 @@ medfield_gfx-y += \
        $(IMGVDIR)/psb_buffer.o \
        $(IMGVDIR)/psb_fence.o \
        $(IMGVDIR)/psb_mmu.o \
+       $(IMGVDIR)/lnc_topaz.o \
+       $(IMGVDIR)/lnc_topazinit.o \
+       $(IMGVDIR)/psb_msvdx_ec.o \
        $(IMGVDIR)/psb_msvdx.o \
        $(IMGVDIR)/psb_msvdxinit.o \
        $(IMGVDIR)/psb_ttm_fence.o \
index 1b1521e..4312b56 100644 (file)
@@ -61,6 +61,9 @@
 #define TTM_PL_RAR               TTM_PL_PRIV2
 #define TTM_PL_FLAG_RAR          TTM_PL_FLAG_PRIV2       
 
+#define DRM_PSB_MEM_MMU_TILING TTM_PL_PRIV3
+#define DRM_PSB_FLAG_MEM_MMU_TILING TTM_PL_FLAG_PRIV3
+
 typedef int32_t psb_fixed;
 typedef uint32_t psb_ufixed;
 
@@ -277,20 +280,24 @@ typedef enum {
        LNC_VIDEO_DEVICE_INFO,
        LNC_VIDEO_GETPARAM_RAR_INFO,
        LNC_VIDEO_GETPARAM_CI_INFO,
+#if 1 //TODO:del it with usr space update
        LNC_VIDEO_GETPARAM_RAR_HANDLER_OFFSET,
+#endif
        LNC_VIDEO_FRAME_SKIP,
        IMG_VIDEO_DECODE_STATUS,
        IMG_VIDEO_NEW_CONTEXT,
        IMG_VIDEO_RM_CONTEXT,
+#if 0 //TODO:add it with usr space update
+       IMG_VIDEO_UPDATE_CONTEXT,
+#endif
        IMG_VIDEO_MB_ERROR,
        IMG_VIDEO_SET_DISPLAYING_FRAME,
        IMG_VIDEO_GET_DISPLAYING_FRAME,
        IMG_VIDEO_GET_HDMI_STATE,
        IMG_VIDEO_SET_HDMI_STATE,
        PNW_VIDEO_QUERY_ENTRY,
-#ifdef HDMI_MODE_SETTING
-       OTM_HDMI_SET_HDMI_MODE_VIC
-#endif
+       IMG_DISPLAY_SET_WIDI_EXT_STATE,
+       IMG_VIDEO_IED_STATE
 } lnc_getparam_key_t;
 
 struct drm_lnc_video_getparam_arg {
@@ -642,14 +649,15 @@ struct drm_psb_getpageaddrs_arg {
        unsigned long gtt_offset;
 };
 
-
 #define MAX_SLICES_PER_PICTURE 72
+struct  psb_msvdx_mb_region {
+       uint32_t start;
+       uint32_t end;
+};
+
 typedef struct drm_psb_msvdx_decode_status {
-       uint32_t fw_status;
-       uint32_t num_error_slice;
-       int32_t start_error_mb_list[MAX_SLICES_PER_PICTURE];
-       int32_t end_error_mb_list[MAX_SLICES_PER_PICTURE];
-       int32_t slice_missing_or_error[MAX_SLICES_PER_PICTURE];
+       uint32_t num_region;
+       struct psb_msvdx_mb_region mb_regions[MAX_SLICES_PER_PICTURE];
 } drm_psb_msvdx_decode_status_t;
 
 /* Controlling the kernel modesetting buffers */
index 0824469..8ff6c79 100644 (file)
@@ -82,6 +82,9 @@ int drm_psb_topaz_clockgating = 0;
 static int PanelID = TMD_6X10_VID;
 char HDMI_EDID[HDMI_MONITOR_NAME_LENGTH];
 
+int hdmi_state;
+int drm_psb_msvdx_tiling;
+
 static int psb_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
 
 MODULE_PARM_DESC(debug, "Enable debug output");
@@ -1067,6 +1070,9 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
        dev_priv->dev = dev;
        bdev = &dev_priv->bdev;
 
+       hdmi_state = 0;
+       dev_priv->bhdmiconnected = false;
+
        ret = psb_ttm_global_init(dev_priv);
        if (unlikely(ret != 0))
                goto out_err;
index 3e5b3d8..c1efb55 100644 (file)
@@ -142,7 +142,9 @@ enum panel_type {
 #define PSB_NUM_VALIDATE_BUFFERS 2048
 
 #define PSB_MEM_MMU_START       0x00000000
+#define PSB_MEM_RAR_START       0xD0000000
 #define PSB_MEM_TT_START        0xE0000000
+#define PSB_MEM_MMU_TILING_START       0xB0000000
 
 #define PSB_GL3_CACHE_CTL      0x2100
 #define PSB_GL3_CACHE_STAT     0x2108
@@ -335,6 +337,27 @@ struct psb_msvdx_cmd_queue {
        void *cmd;
        unsigned long cmd_size;
        uint32_t sequence;
+       uint32_t msvdx_tile;
+       uint32_t host_be_opp_enabled;
+       uint32_t deblock_cmd_offset;
+};
+
+/* Currently defined profiles */
+enum VAProfile {
+       VAProfileMPEG2Simple            = 0,
+       VAProfileMPEG2Main              = 1,
+       VAProfileMPEG4Simple            = 2,
+       VAProfileMPEG4AdvancedSimple    = 3,
+       VAProfileMPEG4Main              = 4,
+       VAProfileH264Baseline           = 5,
+       VAProfileH264Main               = 6,
+       VAProfileH264High               = 7,
+       VAProfileVC1Simple              = 8,
+       VAProfileVC1Main                = 9,
+       VAProfileVC1Advanced            = 10,
+       VAProfileH263Baseline           = 11,
+       VAProfileJPEGBaseline           = 12,
+       VAProfileH264ConstrainedBaseline = 13
 };
 
 /* Currently defined entrypoints */
@@ -348,6 +371,8 @@ enum VAEntrypoint {
        VAEntrypointEncPicture  = 7     /* pictuer encode, JPEG, etc */
 };
 
+#define VA_RT_FORMAT_PROTECTED 0x80000000
+
 struct psb_video_ctx {
        struct list_head head;
        struct file *filp; /* DRM device file pointer */
@@ -937,6 +962,8 @@ struct drm_psb_private {
 
        uint32_t hdmi_audio_interrupt_mask;
 
+       /*hdmi connected status */
+       bool bhdmiconnected;
        bool dpms_on_off;
        struct mutex dpms_mutex;
 
@@ -1345,19 +1372,40 @@ static inline void REGISTER_WRITE8(struct drm_device *dev,
 
 #endif
 
+#define PSB_ALPL(_val, _base)                  \
+  (((_val) >> (_base ## _ALIGNSHIFT)) << (_base ## _SHIFT))
+#define PSB_ALPLM(_val, _base)                 \
+  ((((_val) >> (_base ## _ALIGNSHIFT)) << (_base ## _SHIFT)) & (_base ## _MASK))
+
+#define IS_POULSBO(dev) 0  /* (((dev)->pci_device == 0x8108) || \
+                              ((dev)->pci_device == 0x8109)) */
+
+#define IS_MRST(dev) (((dev)->pci_device & 0xfff8) == 0x4100)
 #define IS_PENWELL(dev) 0 /* FIXME */
 
+/* Will revisit it after CLOVER TRAIL PO. */
+/* pciid: CLV A0 = 0X8C7, CLV B0 = 0X8C8-0X8CB, CLV+ A0/B0 0X8CC-0X8CF.*/
 #define IS_MDFLD_OLD(dev) (((dev)->pci_device & 0xfff8) == 0x0130)
 #define IS_CTP(dev) (((dev->pci_device & 0xffff) == 0x08c0) || \
                     ((dev->pci_device & 0xffff) == 0x08c7) ||  \
                     ((dev->pci_device & 0xffff) == 0x08c8))
 
+#define IS_MRFL(dev) ((dev->pci_device & 0xFFFC) == 0x1180)
+
+#define IS_CTP_NEED_WA(dev) ((dev->pci_device & 0xffff) == 0x08c8)
+
 #define IS_MDFLD(dev) (IS_CTP(dev) || IS_MDFLD_OLD(dev))
+#define IS_MID(dev) (IS_MRST(dev) || IS_MDFLD(dev))
+
+#define IS_MSVDX(dev) (IS_MRST(dev) || IS_MDFLD(dev))
+#define IS_TOPAZ(dev) ((IS_MRST(dev) && (((dev)->pci_device & 0xfffc) != PCI_ID_TOPAZ_DISABLED)) || IS_MDFLD(dev))
 
 #define IS_D0(dev) (((dev)->pdev->revision >= 0xc) || \
                (((dev)->pci_device & 0xffff) == 0x08c7) || \
                (((dev)->pci_device & 0xffff) == 0x08c8))
 
+#define IS_MSVDX_MEM_TILE(dev) ((IS_MRFL(dev)))
+
 extern int drm_psb_cpurelax;
 extern int drm_psb_udelaydivider;
 extern int drm_psb_udelaymultiplier;
diff --git a/drivers/staging/mrst/imgv/lnc_topaz.c b/drivers/staging/mrst/imgv/lnc_topaz.c
new file mode 100644 (file)
index 0000000..52bade3
--- /dev/null
@@ -0,0 +1,763 @@
+/**
+ * file lnc_topaz.c
+ * TOPAZ I/O operations and IRQ handling
+ *
+ */
+
+/**************************************************************************
+ *
+ * Copyright (c) 2007 Intel Corporation, Hillsboro, OR, USA
+ * Copyright (c) Imagination Technologies Limited, UK
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ **************************************************************************/
+
+/* include headers */
+/* #define DRM_DEBUG_CODE 2 */
+#include <drm/drmP.h>
+
+#include "psb_drv.h"
+#include "psb_drm.h"
+#include "lnc_topaz.h"
+#include "psb_powermgmt.h"
+#include "lnc_topaz_hw_reg.h"
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <asm/intel-mid.h>
+
+#define TOPAZ_RM_MULTI_MTX_WRITE
+
+/* static function define */
+static int lnc_topaz_deliver_command(struct drm_device *dev,
+                                    struct ttm_buffer_object *cmd_buffer,
+                                    unsigned long cmd_offset,
+                                    unsigned long cmd_size,
+                                    void **topaz_cmd, uint32_t sequence,
+                                    int copy_cmd);
+static int lnc_topaz_send(struct drm_device *dev, void *cmd,
+                         unsigned long cmd_size, uint32_t sync_seq);
+static int lnc_mtx_send(struct drm_psb_private *dev_priv, const void *cmd);
+static int lnc_topaz_dequeue_send(struct drm_device *dev);
+static int lnc_topaz_save_command(struct drm_device *dev, void *cmd,
+                                 unsigned long cmd_size, uint32_t sequence);
+
+IMG_BOOL lnc_topaz_interrupt(IMG_VOID *pvData)
+{
+       struct drm_device *dev;
+       struct drm_psb_private *dev_priv;
+       uint32_t clr_flag;
+       struct topaz_private *topaz_priv;
+       uint32_t topaz_stat;
+       uint32_t cur_seq;
+
+       if (pvData == IMG_NULL) {
+               DRM_ERROR("ERROR: TOPAZ %s, Invalid params\n", __func__);
+               return IMG_FALSE;
+       }
+
+       if (!ospm_power_is_hw_on(OSPM_VIDEO_ENC_ISLAND)) {
+               DRM_ERROR("ERROR: interrupt arrived but HW is power off\n");
+               return IMG_FALSE;
+       }
+
+       dev = (struct drm_device *)pvData;
+       dev_priv = (struct drm_psb_private *) dev->dev_private;
+       topaz_priv = dev_priv->topaz_private;
+
+       topaz_priv->topaz_hw_busy = REG_READ(0x20D0) & (0x1 << 11);
+
+       TOPAZ_READ32(TOPAZ_CR_IMG_TOPAZ_INTSTAT, &topaz_stat);
+       clr_flag = lnc_topaz_queryirq(dev);
+
+       lnc_topaz_clearirq(dev, clr_flag);
+
+       /* ignore non-SYNC interrupts */
+       if ((CCB_CTRL_SEQ(dev_priv) & 0x8000) == 0)
+               return IMG_TRUE;
+
+       cur_seq = *(uint32_t *)topaz_priv->topaz_sync_addr;
+
+       PSB_DEBUG_IRQ("TOPAZ:Got SYNC IRQ,sync seq:0x%08x (MTX) vs 0x%08x\n",
+                     cur_seq, dev_priv->sequence[LNC_ENGINE_ENCODE]);
+
+       psb_fence_handler(dev, LNC_ENGINE_ENCODE);
+
+       /* save frame skip flag for query */
+       topaz_priv->frame_skip = CCB_CTRL_FRAMESKIP(dev_priv);
+
+       topaz_priv->topaz_busy = 1;
+       lnc_topaz_dequeue_send(dev);
+
+       if (drm_topaz_pmpolicy != PSB_PMPOLICY_NOPM)
+               schedule_delayed_work(&dev_priv->scheduler.topaz_suspend_wq, 0);
+
+       return IMG_TRUE;
+}
+
+static int lnc_submit_encode_cmdbuf(struct drm_device *dev,
+                                   struct ttm_buffer_object *cmd_buffer,
+                                   unsigned long cmd_offset, unsigned long cmd_size,
+                                   struct ttm_fence_object *fence)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       unsigned long irq_flags;
+       int ret = 0;
+       void *cmd;
+       uint32_t tmp;
+       uint32_t sequence = dev_priv->sequence[LNC_ENGINE_ENCODE];
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+
+       PSB_DEBUG_GENERAL("TOPAZ: command submit\n");
+
+       PSB_DEBUG_GENERAL("TOPAZ: topaz busy = %d\n", topaz_priv->topaz_busy);
+
+       if (dev_priv->last_topaz_ctx != dev_priv->topaz_ctx) {
+               /* todo: save current context into topaz_priv->current_ctx
+                * and reload dev_priv->topaz_ctx context
+                */
+               PSB_DEBUG_GENERAL("TOPAZ: context switch\n");
+               dev_priv->last_topaz_ctx = dev_priv->topaz_ctx;
+       }
+
+#if 0 // Not support MRST platform anymore
+       /* FIXME: workaround for HSD 3469585
+        *        disable DRAM Self Refresh Mode
+        *        by resetting DUNIT.DPMC0
+        */
+       if (IS_MRST(dev)) {
+               uint32_t ui32_reg_value = 0;
+               ui32_reg_value = intel_mid_msgbus_read32_raw((0xD0 << 24) |
+                       (0x1 << 16) | (0x4 << 8) | 0xF0);
+               intel_mid_msgbus_write32_raw((0xE0 << 24) | (0x1 << 16) |
+                       (0x4 << 8) | 0xF0, ui32_reg_value & (~(0x1 << 7)));
+       }
+#endif
+
+       if (topaz_priv->topaz_fw_loaded == 0) {
+               /* #.# load fw to driver */
+               PSB_DEBUG_INIT("TOPAZ: load /lib/firmware/topaz_fw.bin\n");
+               ret = topaz_init_fw(dev);
+               if (ret != 0) {
+                       /* FIXME: find a proper return value */
+                       DRM_ERROR("TOPAX:load /lib/firmware/topaz_fw.bin fail,"
+                                 "ensure udevd is configured correctly!\n");
+
+                       return -EFAULT;
+               }
+               topaz_priv->topaz_fw_loaded = 1;
+       }
+
+       tmp = atomic_cmpxchg(&dev_priv->topaz_mmu_invaldc, 1, 0);
+       if (tmp == 1)
+               topaz_mmu_flushcache(dev_priv);
+
+       /* # schedule watchdog */
+       /* psb_schedule_watchdog(dev_priv); */
+
+       /* # spin lock irq save [msvdx_lock] */
+       spin_lock_irqsave(&topaz_priv->topaz_lock, irq_flags);
+
+       /* # if topaz need to reset, reset it */
+       if (topaz_priv->topaz_needs_reset) {
+               /* #.# reset it */
+               spin_unlock_irqrestore(&topaz_priv->topaz_lock, irq_flags);
+               PSB_DEBUG_GENERAL("TOPAZ: needs reset.\n");
+
+               if (lnc_topaz_reset(dev_priv)) {
+                       ret = -EBUSY;
+                       DRM_ERROR("TOPAZ: reset failed.\n");
+                       return ret;
+               }
+
+               PSB_DEBUG_GENERAL("TOPAZ: reset ok.\n");
+
+               /* #.# upload firmware */
+               if (topaz_setup_fw(dev, topaz_priv->topaz_cur_codec)) {
+                       DRM_ERROR("TOPAZ: upload FW to HW failed\n");
+                       return -EBUSY;
+               }
+
+               spin_lock_irqsave(&topaz_priv->topaz_lock, irq_flags);
+       }
+
+       if (!topaz_priv->topaz_busy) {
+               /* # direct map topaz command if topaz is free */
+               PSB_DEBUG_GENERAL("TOPAZ:direct send command,sequence %08x \n",
+                                 sequence);
+
+               topaz_priv->topaz_busy = 1;
+               spin_unlock_irqrestore(&topaz_priv->topaz_lock, irq_flags);
+
+               ret = lnc_topaz_deliver_command(dev, cmd_buffer, cmd_offset,
+                                               cmd_size, NULL, sequence, 0);
+
+               if (ret) {
+                       DRM_ERROR("TOPAZ: failed to extract cmd...\n");
+                       return ret;
+               }
+       } else {
+               PSB_DEBUG_GENERAL("TOPAZ: queue command,sequence %08x \n",
+                                 sequence);
+               cmd = NULL;
+
+               spin_unlock_irqrestore(&topaz_priv->topaz_lock, irq_flags);
+
+               ret = lnc_topaz_deliver_command(dev, cmd_buffer, cmd_offset,
+                                               cmd_size, &cmd, sequence, 1);
+               if (cmd == NULL || ret) {
+                       DRM_ERROR("TOPAZ: map command for save fialed\n");
+                       return ret;
+               }
+
+               ret = lnc_topaz_save_command(dev, cmd, cmd_size, sequence);
+               if (ret)
+                       DRM_ERROR("TOPAZ: save command failed\n");
+       }
+
+       return ret;
+}
+
+static int lnc_topaz_save_command(struct drm_device *dev, void *cmd,
+                                 unsigned long cmd_size, uint32_t sequence)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       struct lnc_topaz_cmd_queue *topaz_cmd;
+       unsigned long irq_flags;
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+
+       PSB_DEBUG_GENERAL("TOPAZ: queue command,sequence: %08x..\n",
+                         sequence);
+
+       topaz_cmd = kzalloc(sizeof(struct lnc_topaz_cmd_queue),
+                           GFP_KERNEL);
+       if (topaz_cmd == NULL) {
+               mutex_unlock(&topaz_priv->topaz_mutex);
+               DRM_ERROR("TOPAZ: out of memory....\n");
+               return -ENOMEM;
+       }
+
+       topaz_cmd->cmd = cmd;
+       topaz_cmd->cmd_size = cmd_size;
+       topaz_cmd->sequence = sequence;
+
+       spin_lock_irqsave(&topaz_priv->topaz_lock, irq_flags);
+       list_add_tail(&topaz_cmd->head, &topaz_priv->topaz_queue);
+       if (!topaz_priv->topaz_busy) {
+               /* topaz_priv->topaz_busy = 1; */
+               PSB_DEBUG_GENERAL("TOPAZ: need immediate dequeue...\n");
+               lnc_topaz_dequeue_send(dev);
+               PSB_DEBUG_GENERAL("TOPAZ: after dequeue command\n");
+       }
+
+       spin_unlock_irqrestore(&topaz_priv->topaz_lock, irq_flags);
+
+       return 0;
+}
+
+
+int lnc_cmdbuf_video(struct drm_file *priv,
+                    struct list_head *validate_list,
+                    uint32_t fence_type,
+                    struct drm_psb_cmdbuf_arg *arg,
+                    struct ttm_buffer_object *cmd_buffer,
+                    struct psb_ttm_fence_rep *fence_arg)
+{
+       struct drm_device *dev = priv->minor->dev;
+       struct ttm_fence_object *fence = NULL;
+       int ret;
+
+       ret = lnc_submit_encode_cmdbuf(dev, cmd_buffer, arg->cmdbuf_offset,
+                                      arg->cmdbuf_size, fence);
+       if (ret)
+               return ret;
+
+       /* workaround for interrupt issue */
+       psb_fence_or_sync(priv, LNC_ENGINE_ENCODE, fence_type, arg->fence_flags,
+                         validate_list, fence_arg, &fence);
+
+       if (fence)
+               ttm_fence_object_unref(&fence);
+
+       spin_lock(&cmd_buffer->bdev->fence_lock);
+       if (cmd_buffer->sync_obj != NULL)
+               ttm_fence_sync_obj_unref(&cmd_buffer->sync_obj);
+       spin_unlock(&cmd_buffer->bdev->fence_lock);
+
+       return 0;
+}
+
+static int lnc_topaz_sync(struct drm_device *dev, uint32_t sync_seq)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       uint32_t sync_cmd[3];
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+
+#if 0
+       struct ttm_fence_device *fdev = &dev_priv->fdev;
+       struct ttm_fence_class_manager *fc =
+                               &fdev->fence_class[LNC_ENGINE_ENCODE];
+       unsigned long irq_flags;
+#endif
+#if LNC_TOPAZ_NO_IRQ
+       uint32_t *sync_p = (uint32_t *)topaz_priv->topaz_sync_addr;
+       int count = 10000;
+       uint32_t cur_seq;
+#endif
+
+       /* insert a SYNC command here */
+       topaz_priv->topaz_sync_cmd_seq = (1 << 15) |
+                                        topaz_priv->topaz_cmd_seq++;
+       sync_cmd[0] = 1 | (MTX_CMDID_SYNC << 1) | (3 << 8) |
+                     (topaz_priv->topaz_sync_cmd_seq << 16);
+       sync_cmd[1] = topaz_priv->topaz_sync_offset;
+       sync_cmd[2] = sync_seq;
+
+       PSB_DEBUG_GENERAL("TOPAZ:MTX_CMDID_SYNC: size(3),cmd seq (0x%04x),"
+                         "sync_seq (0x%08x)\n",
+                         topaz_priv->topaz_sync_cmd_seq, sync_seq);
+
+       if (drm_topaz_sbuswa)
+               TOPAZ_WAIT_UNTIL_IDLE;
+
+       lnc_mtx_send(dev_priv, sync_cmd);
+
+#if LNC_TOPAZ_NO_IRQ /* workaround for interrupt issue */
+       /* # poll topaz register for certain times */
+       while (count && *sync_p != sync_seq) {
+               DRM_UDELAY(100);
+               --count;
+       }
+       if ((count == 0) && (*sync_p != sync_seq)) {
+               DRM_ERROR("TOPAZ: wait sycn timeout (0x%08x),actual 0x%08x\n",
+                         sync_seq, *sync_p);
+               return -EBUSY;
+       }
+       PSB_DEBUG_GENERAL("TOPAZ: SYNC done, seq=0x%08x\n", *sync_p);
+
+       topaz_priv->topaz_busy = 0;
+
+       /* XXX: check psb_fence_handler is suitable for topaz */
+       cur_seq = *sync_p;
+#if 0
+       write_lock_irqsave(&fc->lock, irq_flags);
+       ttm_fence_handler(fdev, LNC_ENGINE_ENCODE,
+                         cur_seq,
+                         _PSB_FENCE_TYPE_EXE, 0);
+       write_unlock_irqrestore(&fc->lock, irq_flags);
+#endif
+#endif
+       return 0;
+}
+
+int
+lnc_topaz_deliver_command(struct drm_device *dev,
+                         struct ttm_buffer_object *cmd_buffer,
+                         unsigned long cmd_offset, unsigned long cmd_size,
+                         void **topaz_cmd, uint32_t sequence,
+                         int copy_cmd)
+{
+       unsigned long cmd_page_offset = cmd_offset & ~PAGE_MASK;
+       struct ttm_bo_kmap_obj cmd_kmap;
+       bool is_iomem;
+       int ret;
+       unsigned char *cmd_start, *tmp;
+
+       ret = ttm_bo_kmap(cmd_buffer, cmd_offset >> PAGE_SHIFT, 2,
+                         &cmd_kmap);
+       if (ret) {
+               DRM_ERROR("TOPAZ: drm_bo_kmap failed: %d\n", ret);
+               return ret;
+       }
+       cmd_start = (unsigned char *) ttm_kmap_obj_virtual(&cmd_kmap,
+                       &is_iomem) + cmd_page_offset;
+
+       if (copy_cmd) {
+               PSB_DEBUG_GENERAL("TOPAZ: queue commands\n");
+               tmp = kzalloc(cmd_size, GFP_KERNEL);
+               if (tmp == NULL) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               memcpy(tmp, cmd_start, cmd_size);
+               *topaz_cmd = tmp;
+       } else {
+               PSB_DEBUG_GENERAL("TOPAZ: directly send the command\n");
+               ret = lnc_topaz_send(dev, cmd_start, cmd_size, sequence);
+               if (ret) {
+                       DRM_ERROR("TOPAZ: commit commands failed.\n");
+                       ret = -EINVAL;
+               }
+       }
+
+out:
+       PSB_DEBUG_GENERAL("TOPAZ:cmd_size(%ld), sequence(%d) copy_cmd(%d)\n",
+                         cmd_size, sequence, copy_cmd);
+
+       ttm_bo_kunmap(&cmd_kmap);
+
+       return ret;
+}
+
+int
+lnc_topaz_send(struct drm_device *dev, void *cmd,
+              unsigned long cmd_size, uint32_t sync_seq)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       int ret = 0;
+       unsigned char *command = (unsigned char *) cmd;
+       struct topaz_cmd_header *cur_cmd_header;
+       uint32_t cur_cmd_size, cur_cmd_id;
+       uint32_t codec;
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+
+       PSB_DEBUG_GENERAL("TOPAZ: send the command in the buffer one by one\n");
+
+       while (cmd_size > 0) {
+               cur_cmd_header = (struct topaz_cmd_header *) command;
+               cur_cmd_size = cur_cmd_header->size * 4;
+               cur_cmd_id = cur_cmd_header->id;
+
+               switch (cur_cmd_id) {
+               case MTX_CMDID_SW_NEW_CODEC:
+                       codec = *((uint32_t *) cmd + 1);
+
+                       PSB_DEBUG_GENERAL("TOPAZ: setup new codec %s (%d)\n",
+                                         codec_to_string(codec), codec);
+                       if (topaz_setup_fw(dev, codec)) {
+                               DRM_ERROR("TOPAZ: upload FW to HW failed\n");
+                               return -EBUSY;
+                       }
+
+                       topaz_priv->topaz_cur_codec = codec;
+                       break;
+
+               case MTX_CMDID_SW_ENTER_LOWPOWER:
+                       PSB_DEBUG_GENERAL("TOPAZ: enter lowpower.... \n");
+                       PSB_DEBUG_GENERAL("XXX: implement it\n");
+                       break;
+
+               case MTX_CMDID_SW_LEAVE_LOWPOWER:
+                       PSB_DEBUG_GENERAL("TOPAZ: leave lowpower... \n");
+                       PSB_DEBUG_GENERAL("XXX: implement it\n");
+                       break;
+
+                       /* ordinary commmand */
+               case MTX_CMDID_START_PIC:
+                       /* XXX: specially handle START_PIC hw command */
+                       CCB_CTRL_SET_QP(dev_priv,
+                                       *(command + cur_cmd_size - 4));
+                       /* strip the QP parameter (it's software arg) */
+                       cur_cmd_header->size--;
+               default:
+                       cur_cmd_header->seq = 0x7fff &
+                                             topaz_priv->topaz_cmd_seq++;
+
+                       PSB_DEBUG_GENERAL("TOPAZ: %s: size(%d),"
+                                         " seq (0x%04x)\n",
+                                         cmd_to_string(cur_cmd_id),
+                                         cur_cmd_size, cur_cmd_header->seq);
+
+                       if (drm_topaz_sbuswa && cur_cmd_id != \
+                           MTX_CMDID_START_PIC)
+                               TOPAZ_WAIT_UNTIL_IDLE;
+
+                       ret = lnc_mtx_send(dev_priv, command);
+                       if (ret) {
+                               DRM_ERROR("TOPAZ: error -- ret(%d)\n", ret);
+                               goto out;
+                       }
+                       break;
+               }
+
+               command += cur_cmd_size;
+               cmd_size -= cur_cmd_size;
+       }
+       lnc_topaz_sync(dev, sync_seq);
+out:
+       return ret;
+}
+
+static int lnc_mtx_send(struct drm_psb_private *dev_priv, const void *cmd)
+{
+       struct topaz_cmd_header *cur_cmd_header =
+               (struct topaz_cmd_header *) cmd;
+       uint32_t cmd_size = cur_cmd_header->size;
+       uint32_t read_index, write_index;
+       const uint32_t *cmd_pointer = (uint32_t *) cmd;
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+
+       int ret = 0;
+
+       /* <msvdx does> # enable all clock */
+
+       write_index = topaz_priv->topaz_cmd_windex;
+       if (write_index + cmd_size + 1 > topaz_priv->topaz_ccb_size) {
+               int free_space = topaz_priv->topaz_ccb_size - write_index;
+
+               PSB_DEBUG_GENERAL("TOPAZ: -------will wrap CCB write point.\n");
+               if (free_space > 0) {
+                       struct topaz_cmd_header pad_cmd;
+
+                       pad_cmd.id = MTX_CMDID_NULL;
+                       pad_cmd.size = free_space;
+                       pad_cmd.seq = 0x7fff & topaz_priv->topaz_cmd_seq;
+
+                       PSB_DEBUG_GENERAL("TOPAZ: MTX_CMDID_NULL:"
+                                         " size(%d),seq (0x%04x)\n",
+                                         pad_cmd.size, pad_cmd.seq);
+
+#ifndef TOPAZ_RM_MULTI_MTX_WRITE
+                       TOPAZ_BEGIN_CCB(dev_priv);
+                       TOPAZ_OUT_CCB(dev_priv, pad_cmd.val);
+#else
+                       topaz_write_mtx_mem(dev_priv,
+                                           topaz_priv->topaz_ccb_buffer_addr
+                                           + topaz_priv->topaz_cmd_windex * 4,
+                                           pad_cmd.val);
+                       topaz_priv->topaz_cmd_windex++;
+#endif
+                       TOPAZ_END_CCB(dev_priv, 1);
+
+                       POLL_WB_SEQ(dev_priv, pad_cmd.seq);
+                       ++topaz_priv->topaz_cmd_seq;
+               }
+               POLL_WB_RINDEX(dev_priv, 0);
+               if (ret == 0)
+                       topaz_priv->topaz_cmd_windex = 0;
+               else {
+                       DRM_ERROR("TOPAZ: poll rindex timeout\n");
+                       return ret; /* HW may hang, need reset */
+               }
+               PSB_DEBUG_GENERAL("TOPAZ: -------wrap CCB was done.\n");
+       }
+
+       read_index = CCB_CTRL_RINDEX(dev_priv);/* temperily use CCB CTRL */
+       write_index = topaz_priv->topaz_cmd_windex;
+
+       PSB_DEBUG_GENERAL("TOPAZ: write index(%d), read index(%d,WB=%d)\n",
+                         write_index, read_index, WB_CCB_CTRL_RINDEX(dev_priv));
+
+#ifndef TOPAZ_RM_MULTI_MTX_WRITE
+       TOPAZ_BEGIN_CCB(dev_priv);
+       while (cmd_size > 0) {
+               TOPAZ_OUT_CCB(dev_priv, *cmd_pointer++);
+               --cmd_size;
+       }
+#else
+       while (cmd_size > 0) {
+               topaz_write_mtx_mem(
+                       dev_priv,
+                       topaz_priv->topaz_ccb_buffer_addr
+                       + topaz_priv->topaz_cmd_windex * 4,
+                       *cmd_pointer++);
+               topaz_priv->topaz_cmd_windex++;
+               --cmd_size;
+       }
+#endif
+       TOPAZ_END_CCB(dev_priv, 1);
+
+#if 0
+       DRM_UDELAY(1000);
+       lnc_topaz_clearirq(dev,
+                          lnc_topaz_queryirq(dev));
+       LNC_TRACEL("TOPAZ: after clear, query again\n");
+       lnc_topaz_queryirq(dev_priv);
+#endif
+
+       return ret;
+}
+
+int lnc_topaz_dequeue_send(struct drm_device *dev)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       struct lnc_topaz_cmd_queue *topaz_cmd = NULL;
+       int ret;
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+
+       PSB_DEBUG_GENERAL("TOPAZ: dequeue command and send it to topaz\n");
+
+       if (list_empty(&topaz_priv->topaz_queue)) {
+               topaz_priv->topaz_busy = 0;
+               return 0;
+       }
+
+       topaz_cmd = list_first_entry(&topaz_priv->topaz_queue,
+                                    struct lnc_topaz_cmd_queue, head);
+
+       PSB_DEBUG_GENERAL("TOPAZ: queue has id %08x\n", topaz_cmd->sequence);
+       ret = lnc_topaz_send(dev, topaz_cmd->cmd, topaz_cmd->cmd_size,
+                            topaz_cmd->sequence);
+       if (ret) {
+               DRM_ERROR("TOPAZ: lnc_topaz_send failed.\n");
+               ret = -EINVAL;
+       }
+
+       list_del(&topaz_cmd->head);
+       kfree(topaz_cmd->cmd);
+       kfree(topaz_cmd
+            );
+
+       return ret;
+}
+
+void topaz_mtx_kick(struct drm_psb_private *dev_priv, uint32_t kick_count)
+{
+       PSB_DEBUG_GENERAL("TOPAZ: kick mtx count(%d).\n", kick_count);
+       MTX_WRITE32(MTX_CR_MTX_KICK, kick_count);
+}
+
+int lnc_check_topaz_idle(struct drm_device *dev)
+{
+       struct drm_psb_private *dev_priv =
+               (struct drm_psb_private *)dev->dev_private;
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+
+       if (topaz_priv->topaz_fw_loaded == 0)
+               return 0;
+
+       if (topaz_priv->topaz_busy)
+               return -EBUSY;
+
+       if (topaz_priv->topaz_hw_busy) {
+               PSB_DEBUG_PM("TOPAZ: %s, HW is busy\n", __func__);
+               return -EBUSY;
+       }
+
+       return 0; /* we think it is idle */
+}
+
+int lnc_video_frameskip(struct drm_device *dev, uint64_t user_pointer)
+{
+       struct drm_psb_private *dev_priv =
+               (struct drm_psb_private *)dev->dev_private;
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+       int ret;
+
+       ret = copy_to_user((void __user *)((unsigned long)user_pointer),
+                          &topaz_priv->frame_skip, sizeof(topaz_priv->frame_skip));
+
+       if (ret)
+               return -EFAULT;
+
+       return 0;
+}
+
+static void lnc_topaz_flush_cmd_queue(struct topaz_private *topaz_priv)
+{
+       struct lnc_topaz_cmd_queue *entry, *next;
+
+       /* remind to reset topaz */
+       topaz_priv->topaz_needs_reset = 1;
+
+       if (list_empty(&topaz_priv->topaz_queue)) {
+               topaz_priv->topaz_busy = 0;
+               return;
+       }
+
+       /* flush all command in queue */
+       list_for_each_entry_safe(entry, next,
+                                &topaz_priv->topaz_queue,
+                                head) {
+               list_del(&entry->head);
+               kfree(entry->cmd);
+               kfree(entry);
+       }
+
+       return;
+}
+
+void lnc_topaz_handle_timeout(struct ttm_fence_device *fdev)
+{
+       struct drm_psb_private *dev_priv =
+               container_of(fdev, struct drm_psb_private, fdev);
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+
+       lnc_topaz_flush_cmd_queue(topaz_priv);
+}
+
+inline int psb_try_power_down_topaz(struct drm_device *dev)
+{
+       ospm_apm_power_down_topaz(dev);
+       return 0;
+}
+
+void lnc_map_topaz_reg(struct drm_device *dev)
+{
+       unsigned long resource_start;
+       struct drm_psb_private *dev_priv =
+               (struct drm_psb_private *)dev->dev_private;
+
+       resource_start = pci_resource_start(dev->pdev, PSB_MMIO_RESOURCE);
+
+       if (IS_TOPAZ(dev)) {
+               dev_priv->topaz_reg =
+                       ioremap(resource_start + LNC_TOPAZ_OFFSET,
+                               LNC_TOPAZ_SIZE);
+               if (!dev_priv->topaz_reg)
+                       DRM_ERROR("failed to map TOPAZ register address\n");
+       }
+
+       return;
+}
+
+void lnc_unmap_topaz_reg(struct drm_device *dev)
+{
+       struct drm_psb_private *dev_priv =
+               (struct drm_psb_private *)dev->dev_private;
+
+       if (IS_TOPAZ(dev)) {
+               if (dev_priv->topaz_reg) {
+                       iounmap(dev_priv->topaz_reg);
+                       dev_priv->topaz_reg = NULL;
+               }
+       }
+
+       return;
+}
+
+
+void lnc_topaz_enableirq(struct drm_device *dev)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       /* uint32_t ier = dev_priv->vdc_irq_mask | _LNC_IRQ_TOPAZ_FLAG; */
+
+       PSB_DEBUG_IRQ("TOPAZ: enable IRQ\n");
+
+       TOPAZ_WRITE32(TOPAZ_CR_IMG_TOPAZ_INTENAB,
+                     F_ENCODE(1, TOPAZ_CR_IMG_TOPAZ_MAS_INTEN) |
+                     /* F_ENCODE(1, TOPAZ_CR_IMG_TOPAZ_INTEN_MVEA) | */
+                     F_ENCODE(1, TOPAZ_CR_IMG_TOPAZ_INTEN_MMU_FAULT) |
+                     F_ENCODE(1, TOPAZ_CR_IMG_TOPAZ_INTEN_MTX) |
+                     F_ENCODE(1, TOPAZ_CR_IMG_TOPAZ_INTEN_MTX_HALT));
+
+       /* write in sysirq.c */
+       /* PSB_WVDC32(ier, PSB_INT_ENABLE_R); /\* essential *\/ */
+}
+
+void lnc_topaz_disableirq(struct drm_device *dev)
+{
+
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       /* uint32_t ier = dev_priv->vdc_irq_mask & (~_LNC_IRQ_TOPAZ_FLAG); */
+
+       PSB_DEBUG_INIT("TOPAZ: disable IRQ\n");
+
+       TOPAZ_WRITE32(TOPAZ_CR_IMG_TOPAZ_INTENAB, 0);
+
+       /* write in sysirq.c */
+       /* PSB_WVDC32(ier, PSB_INT_ENABLE_R); /\* essential *\/ */
+}
+
diff --git a/drivers/staging/mrst/imgv/lnc_topaz.h b/drivers/staging/mrst/imgv/lnc_topaz.h
new file mode 100644 (file)
index 0000000..64dc3b5
--- /dev/null
@@ -0,0 +1,153 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2007 Intel Corporation, Hillsboro, OR, USA
+ * Copyright (c) Imagination Technologies Limited, UK
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ **************************************************************************/
+
+#ifndef _LNC_TOPAZ_H_
+#define _LNC_TOPAZ_H_
+
+#include "psb_drv.h"
+#include "img_types.h"
+
+#define LNC_TOPAZ_NO_IRQ 0
+#define TOPAZ_MTX_REG_SIZE (34 * 4 + 183 * 4)
+/*Must be euqal to  IMG_CODEC_NUM */
+#define LNC_IMG_CODEC_NUM_MAX (11)
+
+extern int drm_topaz_pmpolicy;
+
+
+/* XXX: it's a copy of msvdx cmd queue. should have some change? */
+struct lnc_topaz_cmd_queue {
+       struct list_head head;
+       void *cmd;
+       unsigned long cmd_size;
+       uint32_t sequence;
+};
+
+
+/* define structure */
+/* firmware file's info head */
+struct topaz_fwinfo {
+       unsigned int ver: 16;
+       unsigned int codec: 16;
+
+       unsigned int text_size;
+       unsigned int data_size;
+       unsigned int data_location;
+};
+
+/* firmware data array define  */
+struct topaz_codec_fw {
+       uint32_t ver;
+       uint32_t codec;
+
+       uint32_t text_size;
+       uint32_t data_size;
+       uint32_t data_location;
+
+       struct ttm_buffer_object *text;
+       struct ttm_buffer_object *data;
+};
+
+struct topaz_private {
+       unsigned int pmstate;
+       struct sysfs_dirent *sysfs_pmstate;
+       int frame_skip;
+
+       void *topaz_mtx_reg_state;
+       struct ttm_buffer_object *topaz_mtx_data_mem;
+       uint32_t topaz_cur_codec;
+       uint32_t cur_mtx_data_size;
+       int topaz_needs_reset;
+
+       /*
+        *topaz command queue
+        */
+       spinlock_t topaz_lock;
+       struct mutex topaz_mutex;
+       struct list_head topaz_queue;
+       int topaz_busy;         /* 0 means topaz is free */
+       int topaz_fw_loaded;
+
+       /* topaz ccb data */
+       /* XXX: should the addr stored by 32 bits? more compatible way?? */
+       uint32_t topaz_ccb_buffer_addr;
+       uint32_t topaz_ccb_ctrl_addr;
+       uint32_t topaz_ccb_size;
+       uint32_t topaz_cmd_windex;
+       uint16_t topaz_cmd_seq;
+
+       uint32_t stored_initial_qp;
+       uint32_t topaz_dash_access_ctrl;
+
+       struct ttm_buffer_object *topaz_bo; /* 4K->2K/2K for writeback/sync */
+       struct ttm_bo_kmap_obj topaz_bo_kmap;
+       void *topaz_ccb_wb;
+       uint32_t topaz_wb_offset;
+       uint32_t *topaz_sync_addr;
+       uint32_t topaz_sync_offset;
+       uint32_t topaz_sync_cmd_seq;
+       uint32_t topaz_mtx_saved;
+
+       /* firmware */
+       struct topaz_codec_fw topaz_fw[LNC_IMG_CODEC_NUM_MAX];
+
+       uint32_t topaz_hw_busy;
+};
+
+/* external function declare */
+/*lnc_topaz.c*/
+extern int lnc_cmdbuf_video(struct drm_file *priv,
+                           struct list_head *validate_list,
+                           uint32_t fence_type,
+                           struct drm_psb_cmdbuf_arg *arg,
+                           struct ttm_buffer_object *cmd_buffer,
+                           struct psb_ttm_fence_rep *fence_arg);
+
+extern IMG_BOOL lnc_topaz_interrupt(IMG_VOID *pvData);
+
+/* lnc_topazinit.c*/
+extern int lnc_wait_topaz_idle(struct drm_device *dev);
+extern int lnc_check_topaz_idle(struct drm_device *dev);
+extern void lnc_unmap_topaz_reg(struct drm_device *dev);
+extern void lnc_map_topaz_reg(struct drm_device *dev);
+
+extern int lnc_topaz_restore_mtx_state(struct drm_device *dev);
+
+extern int lnc_topaz_init(struct drm_device *dev);
+extern int lnc_topaz_uninit(struct drm_device *dev);
+
+extern void lnc_topaz_handle_timeout(struct ttm_fence_device *fdev);
+
+extern void lnc_topaz_enableirq(struct drm_device *dev);
+extern void lnc_topaz_disableirq(struct drm_device *dev);
+
+extern int lnc_topaz_save_mtx_state(struct drm_device *dev);
+
+#define TOPAZ_NEW_PMSTATE(drm_dev, topaz_priv, new_state)              \
+do { \
+       topaz_priv->pmstate = new_state;                                \
+       sysfs_notify_dirent(topaz_priv->sysfs_pmstate);                 \
+       PSB_DEBUG_PM("TOPAZ: %s\n",                                     \
+               (new_state == PSB_PMSTATE_POWERUP) ? "powerup"          \
+               : ((new_state == PSB_PMSTATE_POWERDOWN) ? "powerdown"   \
+                       : "clockgated"));                               \
+} while (0)
+
+#endif /* _LNC_TOPAZ_H_ */
diff --git a/drivers/staging/mrst/imgv/lnc_topaz_hw_reg.h b/drivers/staging/mrst/imgv/lnc_topaz_hw_reg.h
new file mode 100644 (file)
index 0000000..4033ca6
--- /dev/null
@@ -0,0 +1,790 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2007 Intel Corporation, Hillsboro, OR, USA
+ * Copyright (c) Imagination Technologies Limited, UK
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ **************************************************************************/
+
+#ifndef _LNC_TOPAZ_HW_REG_H_
+#define _LNC_TOPAZ_HW_REG_H_
+
+#ifdef _PNW_TOPAZ_HW_REG_H_
+#error "pnw_topaz_hw_reg.h shouldn't be included"
+#endif
+
+#include "psb_drv.h"
+#include "img_types.h"
+#include "lnc_topaz.h"
+
+#define LNC_TOPAZ_NO_IRQ 0
+#define TOPAZ_MTX_REG_SIZE (34 * 4 + 183 * 4)
+
+extern int drm_topaz_pmpolicy;
+
+/*
+ * MACROS to insert values into fields within a word. The basename of the
+ * field must have MASK_BASENAME and SHIFT_BASENAME constants.
+ */
+#define MM_WRITE32(base, offset, value)  \
+do {                                  \
+       *((unsigned long *)((unsigned char *)(dev_priv->topaz_reg)      \
+                               + base + offset)) = value;              \
+} while (0)
+
+#define MM_READ32(base, offset, pointer) \
+do {                                   \
+       *(pointer) = *((unsigned long *)((unsigned char *)(dev_priv->topaz_reg)\
+                                               + base + offset));      \
+} while (0)
+
+#define F_MASK(basename)  (MASK_##basename)
+#define F_SHIFT(basename) (SHIFT_##basename)
+
+#define F_ENCODE(val, basename)  \
+       (((val) << (F_SHIFT(basename))) & (F_MASK(basename)))
+
+/* MVEA macro */
+#define MVEA_START 0x03000
+
+#define MVEA_WRITE32(offset, value) MM_WRITE32(MVEA_START, offset, value)
+#define MVEA_READ32(offset, pointer) MM_READ32(MVEA_START, offset, pointer);
+
+#define F_MASK_MVEA(basename)  (MASK_MVEA_##basename)  /*     MVEA    */
+#define F_SHIFT_MVEA(basename) (SHIFT_MVEA_##basename) /*     MVEA    */
+#define F_ENCODE_MVEA(val, basename)  \
+       (((val)<<(F_SHIFT_MVEA(basename)))&(F_MASK_MVEA(basename)))
+
+/* VLC macro */
+#define TOPAZ_VLC_START 0x05000
+
+/* TOPAZ macro */
+#define TOPAZ_START 0x02000
+
+#define TOPAZ_WRITE32(offset, value) MM_WRITE32(TOPAZ_START, offset, value)
+#define TOPAZ_READ32(offset, pointer) MM_READ32(TOPAZ_START, offset, pointer)
+
+#define F_MASK_TOPAZ(basename)  (MASK_TOPAZ_##basename)
+#define F_SHIFT_TOPAZ(basename) (SHIFT_TOPAZ_##basename)
+#define F_ENCODE_TOPAZ(val, basename) \
+       (((val)<<(F_SHIFT_TOPAZ(basename)))&(F_MASK_TOPAZ(basename)))
+
+/* MTX macro */
+#define MTX_START 0x0
+
+#define MTX_WRITE32(offset, value) MM_WRITE32(MTX_START, offset, value)
+#define MTX_READ32(offset, pointer) MM_READ32(MTX_START, offset, pointer)
+
+/* DMAC macro */
+#define DMAC_START 0x0f000
+
+#define DMAC_WRITE32(offset, value) MM_WRITE32(DMAC_START, offset, value)
+#define DMAC_READ32(offset, pointer) MM_READ32(DMAC_START, offset, pointer)
+
+#define F_MASK_DMAC(basename)  (MASK_DMAC_##basename)
+#define F_SHIFT_DMAC(basename) (SHIFT_DMAC_##basename)
+#define F_ENCODE_DMAC(val, basename)  \
+       (((val)<<(F_SHIFT_DMAC(basename)))&(F_MASK_DMAC(basename)))
+
+
+/* Register CR_IMG_TOPAZ_INTENAB */
+#define TOPAZ_CR_IMG_TOPAZ_INTENAB  0x0008
+#define MASK_TOPAZ_CR_IMG_TOPAZ_INTEN_MVEA 0x00000001
+#define SHIFT_TOPAZ_CR_IMG_TOPAZ_INTEN_MVEA 0
+#define REGNUM_TOPAZ_CR_IMG_TOPAZ_INTEN_MVEA 0x0008
+
+#define MASK_TOPAZ_CR_IMG_TOPAZ_MAS_INTEN 0x80000000
+#define SHIFT_TOPAZ_CR_IMG_TOPAZ_MAS_INTEN 31
+#define REGNUM_TOPAZ_CR_IMG_TOPAZ_MAS_INTEN 0x0008
+
+#define MASK_TOPAZ_CR_IMG_TOPAZ_INTEN_MMU_FAULT 0x00000008
+#define SHIFT_TOPAZ_CR_IMG_TOPAZ_INTEN_MMU_FAULT 3
+#define REGNUM_TOPAZ_CR_IMG_TOPAZ_INTEN_MMU_FAULT 0x0008
+
+#define MASK_TOPAZ_CR_IMG_TOPAZ_INTEN_MTX 0x00000002
+#define SHIFT_TOPAZ_CR_IMG_TOPAZ_INTEN_MTX 1
+#define REGNUM_TOPAZ_CR_IMG_TOPAZ_INTEN_MTX 0x0008
+
+#define MASK_TOPAZ_CR_IMG_TOPAZ_INTEN_MTX_HALT 0x00000004
+#define SHIFT_TOPAZ_CR_IMG_TOPAZ_INTEN_MTX_HALT 2
+#define REGNUM_TOPAZ_CR_IMG_TOPAZ_INTEN_MTX_HALT 0x0008
+
+#define TOPAZ_CR_IMG_TOPAZ_INTCLEAR 0x000C
+#define MASK_TOPAZ_CR_IMG_TOPAZ_INTCLR_MVEA 0x00000001
+#define SHIFT_TOPAZ_CR_IMG_TOPAZ_INTCLR_MVEA 0
+#define REGNUM_TOPAZ_CR_IMG_TOPAZ_INTCLR_MVEA 0x000C
+
+#define TOPAZ_CR_IMG_TOPAZ_INTSTAT  0x0004
+#define MASK_TOPAZ_CR_IMG_TOPAZ_INTS_MVEA 0x00000001
+#define SHIFT_TOPAZ_CR_IMG_TOPAZ_INTS_MVEA 0
+#define REGNUM_TOPAZ_CR_IMG_TOPAZ_INTS_MVEA 0x0004
+
+#define MTX_CCBCTRL_ROFF               0
+#define MTX_CCBCTRL_COMPLETE           4
+#define MTX_CCBCTRL_CCBSIZE            8
+#define MTX_CCBCTRL_QP                 12
+#define MTX_CCBCTRL_FRAMESKIP          20
+#define MTX_CCBCTRL_INITQP             24
+
+#define TOPAZ_CR_MMU_STATUS         0x001C
+#define MASK_TOPAZ_CR_MMU_PF_N_RW   0x00000001
+#define SHIFT_TOPAZ_CR_MMU_PF_N_RW  0
+#define REGNUM_TOPAZ_CR_MMU_PF_N_RW 0x001C
+
+#define MASK_TOPAZ_CR_IMG_TOPAZ_INTCLR_MMU_FAULT 0x00000008
+#define SHIFT_TOPAZ_CR_IMG_TOPAZ_INTCLR_MMU_FAULT 3
+#define REGNUM_TOPAZ_CR_IMG_TOPAZ_INTCLR_MMU_FAULT 0x000C
+
+#define TOPAZ_CR_MMU_MEM_REQ        0x0020
+#define MASK_TOPAZ_CR_MEM_REQ_STAT_READS 0x000000FF
+#define SHIFT_TOPAZ_CR_MEM_REQ_STAT_READS 0
+#define REGNUM_TOPAZ_CR_MEM_REQ_STAT_READS 0x0020
+
+#define MASK_TOPAZ_CR_IMG_TOPAZ_INTCLR_MTX 0x00000002
+#define SHIFT_TOPAZ_CR_IMG_TOPAZ_INTCLR_MTX 1
+#define REGNUM_TOPAZ_CR_IMG_TOPAZ_INTCLR_MTX 0x000C
+
+#define MASK_TOPAZ_CR_IMG_TOPAZ_INTCLR_MTX_HALT 0x00000004
+#define SHIFT_TOPAZ_CR_IMG_TOPAZ_INTCLR_MTX_HALT 2
+#define REGNUM_TOPAZ_CR_IMG_TOPAZ_INTCLR_MTX_HALT 0x000C
+
+#define MTX_CR_MTX_KICK             0x0080
+#define MASK_MTX_MTX_KICK           0x0000FFFF
+#define SHIFT_MTX_MTX_KICK          0
+#define REGNUM_MTX_MTX_KICK         0x0080
+
+#define MTX_DATA_MEM_BASE              0x82880000
+
+#define MTX_CR_MTX_RAM_ACCESS_CONTROL 0x0108
+#define MASK_MTX_MTX_MCMR           0x00000001
+#define SHIFT_MTX_MTX_MCMR          0
+#define REGNUM_MTX_MTX_MCMR         0x0108
+
+#define MASK_MTX_MTX_MCMID          0x0FF00000
+#define SHIFT_MTX_MTX_MCMID         20
+#define REGNUM_MTX_MTX_MCMID        0x0108
+
+#define MASK_MTX_MTX_MCM_ADDR       0x000FFFFC
+#define SHIFT_MTX_MTX_MCM_ADDR      2
+#define REGNUM_MTX_MTX_MCM_ADDR     0x0108
+
+#define MTX_CR_MTX_RAM_ACCESS_STATUS 0x010C
+#define MASK_MTX_MTX_MTX_MCM_STAT   0x00000001
+#define SHIFT_MTX_MTX_MTX_MCM_STAT  0
+#define REGNUM_MTX_MTX_MTX_MCM_STAT 0x010C
+
+#define MASK_MTX_MTX_MCMAI          0x00000002
+#define SHIFT_MTX_MTX_MCMAI         1
+#define REGNUM_MTX_MTX_MCMAI        0x0108
+
+#define MTX_CR_MTX_RAM_ACCESS_DATA_TRANSFER 0x0104
+
+#define MVEA_CR_MVEA_BUSY           0x0018
+#define MVEA_CR_MVEA_DMACMDFIFO_WAIT 0x001C
+#define MVEA_CR_MVEA_DMACMDFIFO_STATUS 0x0020
+
+#define MVEA_CR_IMG_MVEA_SRST       0x0000
+#define MASK_MVEA_CR_IMG_MVEA_SPE_SOFT_RESET 0x00000001
+#define SHIFT_MVEA_CR_IMG_MVEA_SPE_SOFT_RESET 0
+#define REGNUM_MVEA_CR_IMG_MVEA_SPE_SOFT_RESET 0x0000
+
+#define MASK_MVEA_CR_IMG_MVEA_IPE_SOFT_RESET 0x00000002
+#define SHIFT_MVEA_CR_IMG_MVEA_IPE_SOFT_RESET 1
+#define REGNUM_MVEA_CR_IMG_MVEA_IPE_SOFT_RESET 0x0000
+
+#define MASK_MVEA_CR_IMG_MVEA_CMPRS_SOFT_RESET 0x00000004
+#define SHIFT_MVEA_CR_IMG_MVEA_CMPRS_SOFT_RESET 2
+#define REGNUM_MVEA_CR_IMG_MVEA_CMPRS_SOFT_RESET 0x0000
+
+#define MASK_MVEA_CR_IMG_MVEA_JMCOMP_SOFT_RESET 0x00000008
+#define SHIFT_MVEA_CR_IMG_MVEA_JMCOMP_SOFT_RESET 3
+#define REGNUM_MVEA_CR_IMG_MVEA_JMCOMP_SOFT_RESET 0x0000
+
+#define MASK_MVEA_CR_IMG_MVEA_CMC_SOFT_RESET 0x00000010
+#define SHIFT_MVEA_CR_IMG_MVEA_CMC_SOFT_RESET 4
+#define REGNUM_MVEA_CR_IMG_MVEA_CMC_SOFT_RESET 0x0000
+
+#define MASK_MVEA_CR_IMG_MVEA_DCF_SOFT_RESET 0x00000020
+#define SHIFT_MVEA_CR_IMG_MVEA_DCF_SOFT_RESET 5
+#define REGNUM_MVEA_CR_IMG_MVEA_DCF_SOFT_RESET 0x0000
+
+#define TOPAZ_CR_IMG_TOPAZ_CORE_ID  0x03C0
+#define TOPAZ_CR_IMG_TOPAZ_CORE_REV 0x03D0
+
+#define TOPAZ_MTX_PC           (0x00000005)
+#define PC_START_ADDRESS       (0x80900000)
+
+#define TOPAZ_CR_TOPAZ_AUTO_CLK_GATE 0x0014
+#define MASK_TOPAZ_CR_TOPAZ_VLC_AUTO_CLK_GATE 0x00000001
+#define SHIFT_TOPAZ_CR_TOPAZ_VLC_AUTO_CLK_GATE 0
+#define REGNUM_TOPAZ_CR_TOPAZ_VLC_AUTO_CLK_GATE 0x0014
+
+#define MASK_TOPAZ_CR_TOPAZ_DB_AUTO_CLK_GATE 0x00000002
+#define SHIFT_TOPAZ_CR_TOPAZ_DB_AUTO_CLK_GATE 1
+#define REGNUM_TOPAZ_CR_TOPAZ_DB_AUTO_CLK_GATE 0x0014
+
+#define MASK_TOPAZ_CR_TOPAZ_MTX_MAN_CLK_GATE 0x00000002
+#define SHIFT_TOPAZ_CR_TOPAZ_MTX_MAN_CLK_GATE 1
+#define REGNUM_TOPAZ_CR_TOPAZ_MTX_MAN_CLK_GATE 0x0010
+
+#define        MTX_CORE_CR_MTX_REGISTER_READ_WRITE_DATA_OFFSET 0x000000F8
+#define        MTX_CORE_CR_MTX_REGISTER_READ_WRITE_REQUEST_OFFSET 0x000000FC
+#define        MTX_CORE_CR_MTX_REGISTER_READ_WRITE_REQUEST_MTX_RNW_MASK 0x00010000
+#define        MTX_CORE_CR_MTX_REGISTER_READ_WRITE_REQUEST_MTX_DREADY_MASK 0x80000000
+
+#define        TOPAZ_CORE_CR_MTX_DEBUG_OFFSET  0x0000003C
+
+#define MASK_TOPAZ_CR_MTX_DBG_IS_SLAVE 0x00000004
+#define SHIFT_TOPAZ_CR_MTX_DBG_IS_SLAVE 2
+#define REGNUM_TOPAZ_CR_MTX_DBG_IS_SLAVE 0x003C
+
+#define MASK_TOPAZ_CR_MTX_DBG_GPIO_OUT 0x00000018
+#define SHIFT_TOPAZ_CR_MTX_DBG_GPIO_OUT 3
+#define REGNUM_TOPAZ_CR_MTX_DBG_GPIO_OUT 0x003C
+
+#define        MTX_CORE_CR_MTX_RAM_ACCESS_CONTROL_OFFSET 0x00000108
+
+#define TOPAZ_CR_MMU_CONTROL0       0x0024
+#define MASK_TOPAZ_CR_MMU_BYPASS    0x00000800
+#define SHIFT_TOPAZ_CR_MMU_BYPASS   11
+#define REGNUM_TOPAZ_CR_MMU_BYPASS  0x0024
+
+#define TOPAZ_CR_MMU_DIR_LIST_BASE(X) (0x0030 + (4 * (X)))
+#define MASK_TOPAZ_CR_MMU_DIR_LIST_BASE_ADDR 0xFFFFF000
+#define SHIFT_TOPAZ_CR_MMU_DIR_LIST_BASE_ADDR 12
+#define REGNUM_TOPAZ_CR_MMU_DIR_LIST_BASE_ADDR 0x0030
+
+#define MASK_TOPAZ_CR_MMU_INVALDC   0x00000008
+#define SHIFT_TOPAZ_CR_MMU_INVALDC  3
+#define REGNUM_TOPAZ_CR_MMU_INVALDC 0x0024
+
+#define MASK_TOPAZ_CR_MMU_FLUSH     0x00000004
+#define SHIFT_TOPAZ_CR_MMU_FLUSH    2
+#define REGNUM_TOPAZ_CR_MMU_FLUSH   0x0024
+
+#define TOPAZ_CR_MMU_BANK_INDEX     0x0038
+#define MASK_TOPAZ_CR_MMU_BANK_N_INDEX_M(i) (0x00000003 << (8 + ((i) * 2)))
+#define SHIFT_TOPAZ_CR_MMU_BANK_N_INDEX_M(i) (8 + ((i) * 2))
+#define REGNUM_TOPAZ_CR_MMU_BANK_N_INDEX_M(i) 0x0038
+
+#define TOPAZ_CR_TOPAZ_MAN_CLK_GATE 0x0010
+#define MASK_TOPAZ_CR_TOPAZ_MVEA_MAN_CLK_GATE 0x00000001
+#define SHIFT_TOPAZ_CR_TOPAZ_MVEA_MAN_CLK_GATE 0
+#define REGNUM_TOPAZ_CR_TOPAZ_MVEA_MAN_CLK_GATE 0x0010
+
+#define MTX_CORE_CR_MTX_TXRPT_OFFSET 0x0000000c
+#define TXRPT_WAITONKICK_VALUE 0x8ade0000
+
+#define MTX_CORE_CR_MTX_ENABLE_MTX_TOFF_MASK 0x00000002
+
+#define MTX_CORE_CR_MTX_ENABLE_OFFSET 0x00000000
+#define        MTX_CORE_CR_MTX_ENABLE_MTX_ENABLE_MASK 0x00000001
+
+#define MASK_TOPAZ_CR_IMG_TOPAZ_INTS_MTX 0x00000002
+#define SHIFT_TOPAZ_CR_IMG_TOPAZ_INTS_MTX 1
+#define REGNUM_TOPAZ_CR_IMG_TOPAZ_INTS_MTX 0x0004
+
+#define        MTX_CORE_CR_MTX_SOFT_RESET_OFFSET 0x00000200
+#define        MTX_CORE_CR_MTX_SOFT_RESET_MTX_RESET_MASK 0x00000001
+
+#define MTX_CR_MTX_SYSC_CDMAA       0x0344
+#define MASK_MTX_CDMAA_ADDRESS      0x03FFFFFC
+#define SHIFT_MTX_CDMAA_ADDRESS     2
+#define REGNUM_MTX_CDMAA_ADDRESS    0x0344
+
+#define MTX_CR_MTX_SYSC_CDMAC       0x0340
+#define MASK_MTX_LENGTH             0x0000FFFF
+#define SHIFT_MTX_LENGTH            0
+#define REGNUM_MTX_LENGTH           0x0340
+
+#define MASK_MTX_BURSTSIZE          0x07000000
+#define SHIFT_MTX_BURSTSIZE         24
+#define REGNUM_MTX_BURSTSIZE        0x0340
+
+#define MASK_MTX_RNW                0x00020000
+#define SHIFT_MTX_RNW               17
+#define REGNUM_MTX_RNW              0x0340
+
+#define MASK_MTX_ENABLE             0x00010000
+#define SHIFT_MTX_ENABLE            16
+#define REGNUM_MTX_ENABLE           0x0340
+
+#define MASK_MTX_LENGTH             0x0000FFFF
+#define SHIFT_MTX_LENGTH            0
+#define REGNUM_MTX_LENGTH           0x0340
+
+#define TOPAZ_CR_IMG_TOPAZ_SRST     0x0000
+#define MASK_TOPAZ_CR_IMG_TOPAZ_MVEA_SOFT_RESET 0x00000001
+#define SHIFT_TOPAZ_CR_IMG_TOPAZ_MVEA_SOFT_RESET 0
+#define REGNUM_TOPAZ_CR_IMG_TOPAZ_MVEA_SOFT_RESET 0x0000
+
+#define MASK_TOPAZ_CR_IMG_TOPAZ_VLC_SOFT_RESET 0x00000008
+#define SHIFT_TOPAZ_CR_IMG_TOPAZ_VLC_SOFT_RESET 3
+#define REGNUM_TOPAZ_CR_IMG_TOPAZ_VLC_SOFT_RESET 0x0000
+
+#define MASK_TOPAZ_CR_IMG_TOPAZ_MTX_SOFT_RESET 0x00000002
+#define SHIFT_TOPAZ_CR_IMG_TOPAZ_MTX_SOFT_RESET 1
+#define REGNUM_TOPAZ_CR_IMG_TOPAZ_MTX_SOFT_RESET 0x0000
+
+#define MVEA_CR_MVEA_AUTO_CLOCK_GATING 0x0024
+#define MASK_MVEA_CR_MVEA_SPE_AUTO_CLK_GATE 0x00000001
+#define SHIFT_MVEA_CR_MVEA_SPE_AUTO_CLK_GATE 0
+#define REGNUM_MVEA_CR_MVEA_SPE_AUTO_CLK_GATE 0x0024
+
+#define MASK_MVEA_CR_MVEA_IPE_AUTO_CLK_GATE 0x00000002
+#define SHIFT_MVEA_CR_MVEA_IPE_AUTO_CLK_GATE 1
+#define REGNUM_MVEA_CR_MVEA_IPE_AUTO_CLK_GATE 0x0024
+
+#define MASK_MVEA_CR_MVEA_CMPRS_AUTO_CLK_GATE 0x00000004
+#define SHIFT_MVEA_CR_MVEA_CMPRS_AUTO_CLK_GATE 2
+#define REGNUM_MVEA_CR_MVEA_CMPRS_AUTO_CLK_GATE 0x0024
+
+#define MASK_MVEA_CR_MVEA_JMCOMP_AUTO_CLK_GATE 0x00000008
+#define SHIFT_MVEA_CR_MVEA_JMCOMP_AUTO_CLK_GATE 3
+#define REGNUM_MVEA_CR_MVEA_JMCOMP_AUTO_CLK_GATE 0x0024
+
+#define TOPAZ_CR_IMG_TOPAZ_DMAC_MODE 0x0040
+#define MASK_TOPAZ_CR_DMAC_MASTER_MODE 0x00000001
+#define SHIFT_TOPAZ_CR_DMAC_MASTER_MODE 0
+#define REGNUM_TOPAZ_CR_DMAC_MASTER_MODE 0x0040
+
+#define MTX_CR_MTX_SYSC_CDMAT       0x0350
+#define MASK_MTX_TRANSFERDATA       0xFFFFFFFF
+#define SHIFT_MTX_TRANSFERDATA      0
+#define REGNUM_MTX_TRANSFERDATA     0x0350
+
+#define IMG_SOC_DMAC_IRQ_STAT(X)    (0x000C + (32 * (X)))
+#define MASK_IMG_SOC_TRANSFER_FIN   0x00020000
+#define SHIFT_IMG_SOC_TRANSFER_FIN  17
+#define REGNUM_IMG_SOC_TRANSFER_FIN 0x000C
+
+#define IMG_SOC_DMAC_COUNT(X)       (0x0004 + (32 * (X)))
+#define MASK_IMG_SOC_CNT            0x0000FFFF
+#define SHIFT_IMG_SOC_CNT           0
+#define REGNUM_IMG_SOC_CNT          0x0004
+
+#define MASK_IMG_SOC_EN             0x00010000
+#define SHIFT_IMG_SOC_EN            16
+#define REGNUM_IMG_SOC_EN           0x0004
+
+#define MASK_IMG_SOC_LIST_EN        0x00040000
+#define SHIFT_IMG_SOC_LIST_EN       18
+#define REGNUM_IMG_SOC_LIST_EN      0x0004
+
+#define IMG_SOC_DMAC_PER_HOLD(X)    (0x0018 + (32 * (X)))
+#define MASK_IMG_SOC_PER_HOLD       0x0000007F
+#define SHIFT_IMG_SOC_PER_HOLD      0
+#define REGNUM_IMG_SOC_PER_HOLD     0x0018
+
+#define IMG_SOC_DMAC_SETUP(X)       (0x0000 + (32 * (X)))
+#define MASK_IMG_SOC_START_ADDRESS  0xFFFFFFF
+#define SHIFT_IMG_SOC_START_ADDRESS 0
+#define REGNUM_IMG_SOC_START_ADDRESS 0x0000
+
+#define MASK_IMG_SOC_BSWAP          0x40000000
+#define SHIFT_IMG_SOC_BSWAP         30
+#define REGNUM_IMG_SOC_BSWAP        0x0004
+
+#define MASK_IMG_SOC_PW             0x18000000
+#define SHIFT_IMG_SOC_PW            27
+#define REGNUM_IMG_SOC_PW           0x0004
+
+#define MASK_IMG_SOC_DIR            0x04000000
+#define SHIFT_IMG_SOC_DIR           26
+#define REGNUM_IMG_SOC_DIR          0x0004
+
+#define MASK_IMG_SOC_PI             0x03000000
+#define SHIFT_IMG_SOC_PI            24
+#define REGNUM_IMG_SOC_PI           0x0004
+#define IMG_SOC_PI_1           0x00000002
+#define IMG_SOC_PI_2           0x00000001
+#define IMG_SOC_PI_4           0x00000000
+
+#define MASK_IMG_SOC_TRANSFER_IEN   0x20000000
+#define SHIFT_IMG_SOC_TRANSFER_IEN  29
+#define REGNUM_IMG_SOC_TRANSFER_IEN 0x0004
+
+#define DMAC_VALUE_COUNT(BSWAP, PW, DIR, PERIPH_INCR, COUNT)        \
+       ((((BSWAP) << SHIFT_IMG_SOC_BSWAP) & MASK_IMG_SOC_BSWAP)|       \
+               (((PW) << SHIFT_IMG_SOC_PW) & MASK_IMG_SOC_PW)|         \
+               (((DIR) << SHIFT_IMG_SOC_DIR) & MASK_IMG_SOC_DIR)|      \
+               (((PERIPH_INCR) << SHIFT_IMG_SOC_PI) & MASK_IMG_SOC_PI)| \
+               (((COUNT) << SHIFT_IMG_SOC_CNT) & MASK_IMG_SOC_CNT))
+
+#define IMG_SOC_DMAC_PERIPH(X)      (0x0008 + (32 * (X)))
+#define MASK_IMG_SOC_EXT_SA         0x0000000F
+#define SHIFT_IMG_SOC_EXT_SA        0
+#define REGNUM_IMG_SOC_EXT_SA       0x0008
+
+#define MASK_IMG_SOC_ACC_DEL        0xE0000000
+#define SHIFT_IMG_SOC_ACC_DEL       29
+#define REGNUM_IMG_SOC_ACC_DEL      0x0008
+
+#define MASK_IMG_SOC_INCR           0x08000000
+#define SHIFT_IMG_SOC_INCR          27
+#define REGNUM_IMG_SOC_INCR         0x0008
+
+#define MASK_IMG_SOC_BURST          0x07000000
+#define SHIFT_IMG_SOC_BURST         24
+#define REGNUM_IMG_SOC_BURST        0x0008
+
+#define DMAC_VALUE_PERIPH_PARAM(ACC_DEL, INCR, BURST)             \
+((((ACC_DEL) << SHIFT_IMG_SOC_ACC_DEL) & MASK_IMG_SOC_ACC_DEL)|        \
+(((INCR) << SHIFT_IMG_SOC_INCR) & MASK_IMG_SOC_INCR)|             \
+(((BURST) << SHIFT_IMG_SOC_BURST) & MASK_IMG_SOC_BURST))
+
+#define IMG_SOC_DMAC_PERIPHERAL_ADDR(X) (0x0014 + (32 * (X)))
+#define MASK_IMG_SOC_ADDR           0x007FFFFF
+#define SHIFT_IMG_SOC_ADDR          0
+#define REGNUM_IMG_SOC_ADDR         0x0014
+
+#define SHIFT_TOPAZ_VEC_BUSY        11
+#define MASK_TOPAZ_VEC_BUSY         (0x1<<SHIFT_TOPAZ_VEC_BUSY)
+
+#define TOPAZ_MTX_TXRPT_OFFSET         0xc
+#define TOPAZ_GUNIT_GVD_PSMI_GFX_OFFSET 0x20D0
+
+#define TOPAZ_GUNIT_READ32(offset)  ioread32(dev_priv->vdc_reg + offset)
+#define TOPAZ_READ_BITS(val, basename) \
+               (((val)&MASK_TOPAZ_##basename)>>SHIFT_TOPAZ_##basename)
+
+#define TOPAZ_WAIT_UNTIL_IDLE \
+    do { \
+       uint8_t tmp_poll_number = 0;\
+       uint32_t tmp_reg; \
+       if (topaz_priv->topaz_cmd_windex == WB_CCB_CTRL_RINDEX(dev_priv)) { \
+               tmp_reg = TOPAZ_GUNIT_READ32(TOPAZ_GUNIT_GVD_PSMI_GFX_OFFSET);\
+               if (0 != TOPAZ_READ_BITS(tmp_reg, VEC_BUSY)) { \
+                       MTX_READ32(TOPAZ_MTX_TXRPT_OFFSET, &tmp_reg);\
+                       while ((tmp_reg != 0x8ade0000) && \
+                              (tmp_poll_number++ < 10)) \
+                               MTX_READ32(0xc, &tmp_reg); \
+                       PSB_DEBUG_GENERAL(      \
+                         "TOPAZ: TXRPT reg remain: %x,poll %d times.\n",\
+                         tmp_reg, tmp_poll_number);\
+               } \
+       } \
+    } while (0)
+
+/* **************** DMAC define **************** */
+enum  DMAC_eBSwap {
+       DMAC_BSWAP_NO_SWAP = 0x0,/* !< No byte swapping will be performed. */
+       DMAC_BSWAP_REVERSE = 0x1,/* !< Byte order will be reversed. */
+};
+
+enum DMAC_ePW {
+       DMAC_PWIDTH_32_BIT = 0x0,/* !< Peripheral width 32-bit. */
+       DMAC_PWIDTH_16_BIT = 0x1,/* !< Peripheral width 16-bit. */
+       DMAC_PWIDTH_8_BIT = 0x2,/* !< Peripheral width 8-bit. */
+};
+
+enum DMAC_eAccDel {
+       DMAC_ACC_DEL_0 = 0x0,   /* !< Access delay zero clock cycles */
+       DMAC_ACC_DEL_256 = 0x1, /* !< Access delay 256 clock cycles */
+       DMAC_ACC_DEL_512 = 0x2, /* !< Access delay 512 clock cycles */
+       DMAC_ACC_DEL_768 = 0x3, /* !< Access delay 768 clock cycles */
+       DMAC_ACC_DEL_1024 = 0x4,/* !< Access delay 1024 clock cycles */
+       DMAC_ACC_DEL_1280 = 0x5,/* !< Access delay 1280 clock cycles */
+       DMAC_ACC_DEL_1536 = 0x6,/* !< Access delay 1536 clock cycles */
+       DMAC_ACC_DEL_1792 = 0x7,/* !< Access delay 1792 clock cycles */
+};
+
+enum  DMAC_eBurst {
+       DMAC_BURST_0 = 0x0,     /* !< burst size of 0 */
+       DMAC_BURST_1 = 0x1,     /* !< burst size of 1 */
+       DMAC_BURST_2 = 0x2,     /* !< burst size of 2 */
+       DMAC_BURST_3 = 0x3,     /* !< burst size of 3 */
+       DMAC_BURST_4 = 0x4,     /* !< burst size of 4 */
+       DMAC_BURST_5 = 0x5,     /* !< burst size of 5 */
+       DMAC_BURST_6 = 0x6,     /* !< burst size of 6 */
+       DMAC_BURST_7 = 0x7,     /* !< burst size of 7 */
+};
+
+/* codecs topaz supports,shared with user space driver */
+enum drm_lnc_topaz_codec {
+       IMG_CODEC_JPEG = 0,
+       IMG_CODEC_H264_NO_RC,
+       IMG_CODEC_H264_VBR,
+       IMG_CODEC_H264_CBR,
+       IMG_CODEC_H264_VCM,
+       IMG_CODEC_H263_NO_RC,
+       IMG_CODEC_H263_VBR,
+       IMG_CODEC_H263_CBR,
+       IMG_CODEC_MPEG4_NO_RC,
+       IMG_CODEC_MPEG4_VBR,
+       IMG_CODEC_MPEG4_CBR,
+       IMG_CODEC_NUM
+};
+
+/* commands for topaz,shared with user space driver */
+enum drm_lnc_topaz_cmd {
+       MTX_CMDID_NULL = 0,
+       MTX_CMDID_DO_HEADER = 1,
+       MTX_CMDID_ENCODE_SLICE = 2,
+       MTX_CMDID_WRITEREG = 3,
+       MTX_CMDID_START_PIC = 4,
+       MTX_CMDID_END_PIC = 5,
+       MTX_CMDID_SYNC = 6,
+       MTX_CMDID_ENCODE_ONE_ROW = 7,
+       MTX_CMDID_FLUSH = 8,
+       MTX_CMDID_SW_LEAVE_LOWPOWER = 0x7c,
+       MTX_CMDID_SW_ENTER_LOWPOWER = 0x7e,
+       MTX_CMDID_SW_NEW_CODEC = 0x7f
+};
+
+struct topaz_cmd_header {
+       union {
+               struct {
+                       unsigned long enable_interrupt: 1;
+                       unsigned long id: 7;
+                       unsigned long size: 8;
+                       unsigned long seq: 16;
+               };
+               uint32_t val;
+       };
+};
+
+/* lnc_topazinit.c */
+int lnc_topaz_reset(struct drm_psb_private *dev_priv);
+int topaz_init_fw(struct drm_device *dev);
+int topaz_setup_fw(struct drm_device *dev, enum drm_lnc_topaz_codec codec);
+int topaz_wait_for_register(struct drm_psb_private *dev_priv,
+                           uint32_t addr, uint32_t value,
+                           uint32_t enable);
+void topaz_write_mtx_mem(struct drm_psb_private *dev_priv,
+                        uint32_t byte_addr, uint32_t val);
+uint32_t topaz_read_mtx_mem(struct drm_psb_private *dev_priv,
+                           uint32_t byte_addr);
+void topaz_write_mtx_mem_multiple_setup(struct drm_psb_private *dev_priv,
+                                       uint32_t addr);
+void topaz_write_mtx_mem_multiple(struct drm_psb_private *dev_priv,
+                                 uint32_t val);
+void topaz_mmu_flushcache(struct drm_psb_private *dev_priv);
+
+void topaz_mtx_kick(struct drm_psb_private *dev_priv, uint32_t kick_cout);
+
+uint32_t psb_get_default_pd_addr(struct psb_mmu_driver *driver);
+
+/* macros to get/set CCB control data */
+#define WB_CCB_CTRL_RINDEX(dev_priv) \
+(*((uint32_t *)((struct topaz_private *)dev_priv->topaz_private)->topaz_ccb_wb))
+
+#define WB_CCB_CTRL_SEQ(dev_priv) \
+(*((uint32_t *)((struct topaz_private *)dev_priv->topaz_private)->topaz_ccb_wb\
+       + 1))
+
+#define POLL_WB_RINDEX(dev_priv, value)                                \
+do {                                                           \
+       int i;                                                  \
+       for (i = 0; i < 10000; i++) {                           \
+               if (WB_CCB_CTRL_RINDEX(dev_priv) == value)      \
+                       break;                                  \
+               else                                            \
+                       DRM_UDELAY(100);                        \
+       }                                                       \
+       if (WB_CCB_CTRL_RINDEX(dev_priv) != value) {            \
+               DRM_ERROR("TOPAZ: poll rindex timeout\n");      \
+               ret = -EBUSY;                                   \
+       }                                                       \
+} while (0)
+
+#define POLL_WB_SEQ(dev_priv, value)                           \
+do {                                                           \
+       int i;                                                  \
+       for (i = 0; i < 10000; i++) {                           \
+               if (CCB_CTRL_SEQ(dev_priv) == value)    \
+                       break;                                  \
+               else                                            \
+                       DRM_UDELAY(1000);                       \
+       }                                                       \
+       if (CCB_CTRL_SEQ(dev_priv) != value) {          \
+               DRM_ERROR("TOPAZ:poll mtxseq timeout,0x%08x(mtx) vs 0x%08x\n",\
+                       WB_CCB_CTRL_SEQ(dev_priv), value);              \
+               ret = -EBUSY;                                   \
+       }                                                       \
+} while (0)
+
+#define CCB_CTRL_RINDEX(dev_priv)                      \
+       topaz_read_mtx_mem(dev_priv,                    \
+       ((struct topaz_private *)dev_priv->topaz_private)->topaz_ccb_ctrl_addr \
+                       + MTX_CCBCTRL_ROFF)
+
+#define CCB_CTRL_RINDEX(dev_priv)                      \
+       topaz_read_mtx_mem(dev_priv,                    \
+       ((struct topaz_private *)dev_priv->topaz_private)->topaz_ccb_ctrl_addr \
+                       + MTX_CCBCTRL_ROFF)
+
+#define CCB_CTRL_QP(dev_priv)                                          \
+       topaz_read_mtx_mem(dev_priv,                                    \
+       ((struct topaz_private *)dev_priv->topaz_private)->topaz_ccb_ctrl_addr \
+                       + MTX_CCBCTRL_QP)
+
+#define CCB_CTRL_SEQ(dev_priv)                                         \
+       topaz_read_mtx_mem(dev_priv,                                    \
+       ((struct topaz_private *)dev_priv->topaz_private)->topaz_ccb_ctrl_addr \
+                       + MTX_CCBCTRL_COMPLETE)
+
+#define CCB_CTRL_FRAMESKIP(dev_priv)                              \
+       topaz_read_mtx_mem(dev_priv,                               \
+       ((struct topaz_private *)dev_priv->topaz_private)->topaz_ccb_ctrl_addr \
+                       + MTX_CCBCTRL_FRAMESKIP)
+
+#define CCB_CTRL_SET_QP(dev_priv, qp)                                  \
+       topaz_write_mtx_mem(dev_priv,                                   \
+       ((struct topaz_private *)dev_priv->topaz_private)->topaz_ccb_ctrl_addr \
+                       + MTX_CCBCTRL_QP, qp)
+
+#define CCB_CTRL_SET_INITIALQP(dev_priv, qp)                       \
+       topaz_write_mtx_mem(dev_priv,                               \
+       ((struct topaz_private *)dev_priv->topaz_private)->topaz_ccb_ctrl_addr \
+                       + MTX_CCBCTRL_INITQP, qp)
+
+
+#define TOPAZ_BEGIN_CCB(dev_priv)                                      \
+       topaz_write_mtx_mem_multiple_setup(dev_priv,                    \
+   ((struct topaz_private *)dev_priv->topaz_private)->topaz_ccb_buffer_addr + \
+   ((struct topaz_private *)dev_priv->topaz_private)->topaz_cmd_windex * 4)
+
+#define TOPAZ_OUT_CCB(dev_priv, cmd)                                   \
+do {                                                                   \
+       topaz_write_mtx_mem_multiple(dev_priv, cmd);                    \
+       ((struct topaz_private *)dev_priv->topaz_private)->topaz_cmd_windex++; \
+} while (0)
+
+#define TOPAZ_END_CCB(dev_priv, kick_count)    \
+       topaz_mtx_kick(dev_priv, 1);
+
+static inline char *cmd_to_string(int cmd_id)
+{
+       switch (cmd_id) {
+       case MTX_CMDID_START_PIC:
+               return "MTX_CMDID_START_PIC";
+       case MTX_CMDID_END_PIC:
+               return "MTX_CMDID_END_PIC";
+       case MTX_CMDID_DO_HEADER:
+               return "MTX_CMDID_DO_HEADER";
+       case MTX_CMDID_ENCODE_SLICE:
+               return "MTX_CMDID_ENCODE_SLICE";
+       case MTX_CMDID_SYNC:
+               return "MTX_CMDID_SYNC";
+
+       default:
+               return "Undefined command";
+
+       }
+}
+
+static inline char *codec_to_string(int codec)
+{
+       switch (codec) {
+       case IMG_CODEC_H264_NO_RC:
+               return "H264_NO_RC";
+       case IMG_CODEC_H264_VBR:
+               return "H264_VBR";
+       case IMG_CODEC_H264_CBR:
+               return "H264_CBR";
+       case IMG_CODEC_H263_NO_RC:
+               return "H263_NO_RC";
+       case IMG_CODEC_H263_VBR:
+               return "H263_VBR";
+       case IMG_CODEC_H263_CBR:
+               return "H263_CBR";
+       case IMG_CODEC_MPEG4_NO_RC:
+               return "MPEG4_NO_RC";
+       case IMG_CODEC_MPEG4_VBR:
+               return "MPEG4_VBR";
+       case IMG_CODEC_MPEG4_CBR:
+               return "MPEG4_CBR";
+       case IMG_CODEC_H264_VCM:
+               return "H264_VCM";
+       default:
+               return "Undefined codec";
+       }
+}
+
+static inline void lnc_topaz_clearirq(struct drm_device *dev,
+                                     uint32_t clear_topaz)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+
+       PSB_DEBUG_INIT("TOPAZ: clear IRQ\n");
+       if (clear_topaz != 0)
+               TOPAZ_WRITE32(TOPAZ_CR_IMG_TOPAZ_INTCLEAR, clear_topaz);
+
+       /* PSB_WVDC32(_LNC_IRQ_TOPAZ_FLAG, PSB_INT_IDENTITY_R); */
+}
+
+static inline uint32_t lnc_topaz_queryirq(struct drm_device *dev)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       uint32_t val, /* iir, */ clear = 0;
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+
+       TOPAZ_READ32(TOPAZ_CR_IMG_TOPAZ_INTSTAT, &val);
+       /* iir = PSB_RVDC32(PSB_INT_IDENTITY_R); */
+
+       (void) topaz_priv;
+
+       if ((val == 0) /* && (iir == 0) */) {/* no interrupt */
+               PSB_DEBUG_GENERAL("TOPAZ: no interrupt,IIR=TOPAZ_INTSTAT=0\n");
+               return 0;
+       }
+
+       PSB_DEBUG_IRQ("TOPAZ:TOPAZ_INTSTAT=0x%08x\n", val);
+
+       if (val & (1 << 31))
+               PSB_DEBUG_IRQ("TOPAZ:IRQ pin activated,cmd seq=0x%04x,"
+                             "sync seq: 0x%08x vs 0x%08x (MTX)\n",
+                             CCB_CTRL_SEQ(dev_priv),
+                             dev_priv->sequence[LNC_ENGINE_ENCODE],
+                             *(uint32_t *)topaz_priv->topaz_sync_addr);
+       else
+               PSB_DEBUG_IRQ("TOPAZ:IRQ pin not activated,cmd seq=0x%04x,"
+                             "sync seq: 0x%08x vs 0x%08x (MTX)\n",
+                             CCB_CTRL_SEQ(dev_priv),
+                             dev_priv->sequence[LNC_ENGINE_ENCODE],
+                             *(uint32_t *)topaz_priv->topaz_sync_addr);
+
+       if (val & 0x8) {
+               uint32_t mmu_status, mmu_req;
+
+               TOPAZ_READ32(TOPAZ_CR_MMU_STATUS, &mmu_status);
+               TOPAZ_READ32(TOPAZ_CR_MMU_MEM_REQ, &mmu_req);
+
+               PSB_DEBUG_IRQ("TOPAZ: detect a page fault interrupt, "
+                             "address=0x%08x,mem req=0x%08x\n",
+                             mmu_status, mmu_req);
+               clear |= F_ENCODE(1, TOPAZ_CR_IMG_TOPAZ_INTCLR_MMU_FAULT);
+       }
+
+       if (val & 0x4) {
+               PSB_DEBUG_IRQ("TOPAZ: detect a MTX_HALT interrupt\n");
+               clear |= F_ENCODE(1, TOPAZ_CR_IMG_TOPAZ_INTCLR_MTX_HALT);
+       }
+
+       if (val & 0x2) {
+               PSB_DEBUG_IRQ("TOPAZ: detect a MTX interrupt\n");
+               clear |= F_ENCODE(1, TOPAZ_CR_IMG_TOPAZ_INTCLR_MTX);
+       }
+
+       if (val & 0x1) {
+               PSB_DEBUG_IRQ("TOPAZ: detect a MVEA interrupt\n");
+               clear |= F_ENCODE(1, TOPAZ_CR_IMG_TOPAZ_INTCLR_MVEA);
+       }
+
+       return clear;
+}
+
+#endif /* _LNC_TOPAZ_H_ */
diff --git a/drivers/staging/mrst/imgv/lnc_topazinit.c b/drivers/staging/mrst/imgv/lnc_topazinit.c
new file mode 100644 (file)
index 0000000..de2c684
--- /dev/null
@@ -0,0 +1,2063 @@
+/**
+ * file lnc_topazinit.c
+ * TOPAZ initialization and mtx-firmware upload
+ *
+ */
+
+/**************************************************************************
+ *
+ * Copyright (c) 2007 Intel Corporation, Hillsboro, OR, USA
+ * Copyright (c) Imagination Technologies Limited, UK
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ **************************************************************************/
+
+/* NOTE: (READ BEFORE REFINE CODE)
+ * 1. The FIRMWARE's SIZE is measured by byte, we have to pass the size
+ * measured by word to DMAC.
+ *
+ *
+ *
+ */
+
+/* include headers */
+
+/* #define DRM_DEBUG_CODE 2 */
+
+#include <linux/firmware.h>
+
+#include <drm/drmP.h>
+#include <drm/drm.h>
+
+#include "psb_drv.h"
+#include "lnc_topaz.h"
+#include "lnc_topaz_hw_reg.h"
+#include "psb_powermgmt.h"
+
+/* WARNING: this define is very important */
+#define RAM_SIZE (1024 * 24)
+
+/* register default values
+ * THIS HEADER IS ONLY INCLUDE ONCE*/
+static unsigned long topaz_default_regs[183][3] = {
+       {MVEA_START, 0x00000000, 0x00000000},
+       {MVEA_START, 0x00000004, 0x00000400},
+       {MVEA_START, 0x00000008, 0x00000000},
+       {MVEA_START, 0x0000000C, 0x00000000},
+       {MVEA_START, 0x00000010, 0x00000000},
+       {MVEA_START, 0x00000014, 0x00000000},
+       {MVEA_START, 0x00000018, 0x00000000},
+       {MVEA_START, 0x0000001C, 0x00000000},
+       {MVEA_START, 0x00000020, 0x00000120},
+       {MVEA_START, 0x00000024, 0x00000000},
+       {MVEA_START, 0x00000028, 0x00000000},
+       {MVEA_START, 0x00000100, 0x00000000},
+       {MVEA_START, 0x00000104, 0x00000000},
+       {MVEA_START, 0x00000108, 0x00000000},
+       {MVEA_START, 0x0000010C, 0x00000000},
+       {MVEA_START, 0x0000011C, 0x00000001},
+       {MVEA_START, 0x0000012C, 0x00000000},
+       {MVEA_START, 0x00000180, 0x00000000},
+       {MVEA_START, 0x00000184, 0x00000000},
+       {MVEA_START, 0x00000188, 0x00000000},
+       {MVEA_START, 0x0000018C, 0x00000000},
+       {MVEA_START, 0x00000190, 0x00000000},
+       {MVEA_START, 0x00000194, 0x00000000},
+       {MVEA_START, 0x00000198, 0x00000000},
+       {MVEA_START, 0x0000019C, 0x00000000},
+       {MVEA_START, 0x000001A0, 0x00000000},
+       {MVEA_START, 0x000001A4, 0x00000000},
+       {MVEA_START, 0x000001A8, 0x00000000},
+       {MVEA_START, 0x000001AC, 0x00000000},
+       {MVEA_START, 0x000001B0, 0x00000000},
+       {MVEA_START, 0x000001B4, 0x00000000},
+       {MVEA_START, 0x000001B8, 0x00000000},
+       {MVEA_START, 0x000001BC, 0x00000000},
+       {MVEA_START, 0x000001F8, 0x00000000},
+       {MVEA_START, 0x000001FC, 0x00000000},
+       {MVEA_START, 0x00000200, 0x00000000},
+       {MVEA_START, 0x00000204, 0x00000000},
+       {MVEA_START, 0x00000208, 0x00000000},
+       {MVEA_START, 0x0000020C, 0x00000000},
+       {MVEA_START, 0x00000210, 0x00000000},
+       {MVEA_START, 0x00000220, 0x00000001},
+       {MVEA_START, 0x00000224, 0x0000001F},
+       {MVEA_START, 0x00000228, 0x00000100},
+       {MVEA_START, 0x0000022C, 0x00001F00},
+       {MVEA_START, 0x00000230, 0x00000101},
+       {MVEA_START, 0x00000234, 0x00001F1F},
+       {MVEA_START, 0x00000238, 0x00001F01},
+       {MVEA_START, 0x0000023C, 0x0000011F},
+       {MVEA_START, 0x00000240, 0x00000200},
+       {MVEA_START, 0x00000244, 0x00001E00},
+       {MVEA_START, 0x00000248, 0x00000002},
+       {MVEA_START, 0x0000024C, 0x0000001E},
+       {MVEA_START, 0x00000250, 0x00000003},
+       {MVEA_START, 0x00000254, 0x0000001D},
+       {MVEA_START, 0x00000258, 0x00001F02},
+       {MVEA_START, 0x0000025C, 0x00000102},
+       {MVEA_START, 0x00000260, 0x0000011E},
+       {MVEA_START, 0x00000264, 0x00000000},
+       {MVEA_START, 0x00000268, 0x00000000},
+       {MVEA_START, 0x0000026C, 0x00000000},
+       {MVEA_START, 0x00000270, 0x00000000},
+       {MVEA_START, 0x00000274, 0x00000000},
+       {MVEA_START, 0x00000278, 0x00000000},
+       {MVEA_START, 0x00000280, 0x00008000},
+       {MVEA_START, 0x00000284, 0x00000000},
+       {MVEA_START, 0x00000288, 0x00000000},
+       {MVEA_START, 0x0000028C, 0x00000000},
+       {MVEA_START, 0x00000314, 0x00000000},
+       {MVEA_START, 0x00000318, 0x00000000},
+       {MVEA_START, 0x0000031C, 0x00000000},
+       {MVEA_START, 0x00000320, 0x00000000},
+       {MVEA_START, 0x00000324, 0x00000000},
+       {MVEA_START, 0x00000348, 0x00000000},
+       {MVEA_START, 0x00000380, 0x00000000},
+       {MVEA_START, 0x00000384, 0x00000000},
+       {MVEA_START, 0x00000388, 0x00000000},
+       {MVEA_START, 0x0000038C, 0x00000000},
+       {MVEA_START, 0x00000390, 0x00000000},
+       {MVEA_START, 0x00000394, 0x00000000},
+       {MVEA_START, 0x00000398, 0x00000000},
+       {MVEA_START, 0x0000039C, 0x00000000},
+       {MVEA_START, 0x000003A0, 0x00000000},
+       {MVEA_START, 0x000003A4, 0x00000000},
+       {MVEA_START, 0x000003A8, 0x00000000},
+       {MVEA_START, 0x000003B0, 0x00000000},
+       {MVEA_START, 0x000003B4, 0x00000000},
+       {MVEA_START, 0x000003B8, 0x00000000},
+       {MVEA_START, 0x000003BC, 0x00000000},
+       {MVEA_START, 0x000003D4, 0x00000000},
+       {MVEA_START, 0x000003D8, 0x00000000},
+       {MVEA_START, 0x000003DC, 0x00000000},
+       {MVEA_START, 0x000003E0, 0x00000000},
+       {MVEA_START, 0x000003E4, 0x00000000},
+       {MVEA_START, 0x000003EC, 0x00000000},
+       {MVEA_START, 0x000002D0, 0x00000000},
+       {MVEA_START, 0x000002D4, 0x00000000},
+       {MVEA_START, 0x000002D8, 0x00000000},
+       {MVEA_START, 0x000002DC, 0x00000000},
+       {MVEA_START, 0x000002E0, 0x00000000},
+       {MVEA_START, 0x000002E4, 0x00000000},
+       {MVEA_START, 0x000002E8, 0x00000000},
+       {MVEA_START, 0x000002EC, 0x00000000},
+       {MVEA_START, 0x000002F0, 0x00000000},
+       {MVEA_START, 0x000002F4, 0x00000000},
+       {MVEA_START, 0x000002F8, 0x00000000},
+       {MVEA_START, 0x000002FC, 0x00000000},
+       {MVEA_START, 0x00000300, 0x00000000},
+       {MVEA_START, 0x00000304, 0x00000000},
+       {MVEA_START, 0x00000308, 0x00000000},
+       {MVEA_START, 0x0000030C, 0x00000000},
+       {MVEA_START, 0x00000290, 0x00000000},
+       {MVEA_START, 0x00000294, 0x00000000},
+       {MVEA_START, 0x00000298, 0x00000000},
+       {MVEA_START, 0x0000029C, 0x00000000},
+       {MVEA_START, 0x000002A0, 0x00000000},
+       {MVEA_START, 0x000002A4, 0x00000000},
+       {MVEA_START, 0x000002A8, 0x00000000},
+       {MVEA_START, 0x000002AC, 0x00000000},
+       {MVEA_START, 0x000002B0, 0x00000000},
+       {MVEA_START, 0x000002B4, 0x00000000},
+       {MVEA_START, 0x000002B8, 0x00000000},
+       {MVEA_START, 0x000002BC, 0x00000000},
+       {MVEA_START, 0x000002C0, 0x00000000},
+       {MVEA_START, 0x000002C4, 0x00000000},
+       {MVEA_START, 0x000002C8, 0x00000000},
+       {MVEA_START, 0x000002CC, 0x00000000},
+       {MVEA_START, 0x00000080, 0x00000000},
+       {MVEA_START, 0x00000084, 0x80705700},
+       {MVEA_START, 0x00000088, 0x00000000},
+       {MVEA_START, 0x0000008C, 0x00000000},
+       {MVEA_START, 0x00000090, 0x00000000},
+       {MVEA_START, 0x00000094, 0x00000000},
+       {MVEA_START, 0x00000098, 0x00000000},
+       {MVEA_START, 0x0000009C, 0x00000000},
+       {MVEA_START, 0x000000A0, 0x00000000},
+       {MVEA_START, 0x000000A4, 0x00000000},
+       {MVEA_START, 0x000000A8, 0x00000000},
+       {MVEA_START, 0x000000AC, 0x00000000},
+       {MVEA_START, 0x000000B0, 0x00000000},
+       {MVEA_START, 0x000000B4, 0x00000000},
+       {MVEA_START, 0x000000B8, 0x00000000},
+       {MVEA_START, 0x000000BC, 0x00000000},
+       {MVEA_START, 0x000000C0, 0x00000000},
+       {MVEA_START, 0x000000C4, 0x00000000},
+       {MVEA_START, 0x000000C8, 0x00000000},
+       {MVEA_START, 0x000000CC, 0x00000000},
+       {MVEA_START, 0x000000D0, 0x00000000},
+       {MVEA_START, 0x000000D4, 0x00000000},
+       {MVEA_START, 0x000000D8, 0x00000000},
+       {MVEA_START, 0x000000DC, 0x00000000},
+       {MVEA_START, 0x000000E0, 0x00000000},
+       {MVEA_START, 0x000000E4, 0x00000000},
+       {MVEA_START, 0x000000E8, 0x00000000},
+       {MVEA_START, 0x000000EC, 0x00000000},
+       {MVEA_START, 0x000000F0, 0x00000000},
+       {MVEA_START, 0x000000F4, 0x00000000},
+       {MVEA_START, 0x000000F8, 0x00000000},
+       {MVEA_START, 0x000000FC, 0x00000000},
+       {TOPAZ_VLC_START, 0x00000000, 0x00000000},
+       {TOPAZ_VLC_START, 0x00000004, 0x00000000},
+       {TOPAZ_VLC_START, 0x00000008, 0x00000000},
+       {TOPAZ_VLC_START, 0x0000000C, 0x00000000},
+       {TOPAZ_VLC_START, 0x00000010, 0x00000000},
+       {TOPAZ_VLC_START, 0x00000014, 0x00000000},
+       {TOPAZ_VLC_START, 0x0000001C, 0x00000000},
+       {TOPAZ_VLC_START, 0x00000020, 0x00000000},
+       {TOPAZ_VLC_START, 0x00000024, 0x00000000},
+       {TOPAZ_VLC_START, 0x0000002C, 0x00000000},
+       {TOPAZ_VLC_START, 0x00000034, 0x00000000},
+       {TOPAZ_VLC_START, 0x00000038, 0x00000000},
+       {TOPAZ_VLC_START, 0x0000003C, 0x00000000},
+       {TOPAZ_VLC_START, 0x00000040, 0x00000000},
+       {TOPAZ_VLC_START, 0x00000044, 0x00000000},
+       {TOPAZ_VLC_START, 0x00000048, 0x00000000},
+       {TOPAZ_VLC_START, 0x0000004C, 0x00000000},
+       {TOPAZ_VLC_START, 0x00000050, 0x00000000},
+       {TOPAZ_VLC_START, 0x00000054, 0x00000000},
+       {TOPAZ_VLC_START, 0x00000058, 0x00000000},
+       {TOPAZ_VLC_START, 0x0000005C, 0x00000000},
+       {TOPAZ_VLC_START, 0x00000060, 0x00000000},
+       {TOPAZ_VLC_START, 0x00000064, 0x00000000},
+       {TOPAZ_VLC_START, 0x00000068, 0x00000000},
+       {TOPAZ_VLC_START, 0x0000006C, 0x00000000}
+};
+
+#define FIRMWARE_NAME "topaz_fw.bin"
+
+/* static function define */
+static int topaz_upload_fw(struct drm_device *dev,
+                          enum drm_lnc_topaz_codec codec);
+static inline void topaz_set_default_regs(struct drm_psb_private
+               *dev_priv);
+
+#define UPLOAD_FW_BY_DMA 1
+
+#if UPLOAD_FW_BY_DMA
+static void topaz_dma_transfer(struct drm_psb_private *dev_priv,
+                              uint32_t channel, uint32_t src_phy_addr,
+                              uint32_t offset, uint32_t dst_addr,
+                              uint32_t byte_num, uint32_t is_increment,
+                              uint32_t is_write);
+#else
+static void topaz_mtx_upload_by_register(struct drm_device *dev,
+               uint32_t mtx_mem, uint32_t addr,
+               uint32_t size,
+               struct ttm_buffer_object *buf);
+#endif
+
+static void topaz_write_core_reg(struct drm_psb_private *dev_priv,
+                                uint32_t reg, const uint32_t val);
+static void topaz_read_core_reg(struct drm_psb_private *dev_priv,
+                               uint32_t reg, uint32_t *ret_val);
+static void get_mtx_control_from_dash(struct drm_psb_private *dev_priv);
+static void release_mtx_control_from_dash(struct drm_psb_private
+               *dev_priv);
+static void topaz_mmu_hwsetup(struct drm_psb_private *dev_priv);
+static void mtx_dma_read(struct drm_device *dev, uint32_t source_addr,
+                        uint32_t size);
+static void mtx_dma_write(struct drm_device *dev);
+
+
+#define DEBUG_FUNCTION 0
+
+#if  DEBUG_FUNCTION
+static int topaz_test_null(struct drm_device *dev, uint32_t seq);
+static int topaz_test_sync(struct drm_device *dev, uint32_t seq,
+                          uint32_t sync_seq);
+static void topaz_mmu_test(struct drm_device *dev, uint32_t sync_value);
+static void topaz_save_default_regs(struct drm_psb_private *dev_priv,
+                                   uint32_t *data);
+static void topaz_restore_default_regs(struct drm_psb_private *dev_priv,
+                                      uint32_t *data);
+static int topaz_test_sync_manual_alloc_page(struct drm_device *dev,
+               uint32_t seq,
+               uint32_t sync_seq,
+               uint32_t offset);
+static int topaz_test_sync_tt_test(struct drm_device *dev,
+                                  uint32_t seq,
+                                  uint32_t sync_seq);
+#endif
+
+uint32_t topaz_read_mtx_mem(struct drm_psb_private *dev_priv,
+                           uint32_t byte_addr)
+{
+       uint32_t read_val;
+       uint32_t reg, bank_size, ram_bank_size, ram_id;
+
+       TOPAZ_READ32(0x3c, &reg);
+       reg = 0x0a0a0606;
+       bank_size = (reg & 0xF0000) >> 16;
+
+       ram_bank_size = (uint32_t)(1 << (bank_size + 2));
+       ram_id = (byte_addr - MTX_DATA_MEM_BASE) / ram_bank_size;
+
+       MTX_WRITE32(MTX_CR_MTX_RAM_ACCESS_CONTROL,
+                   F_ENCODE(0x18 + ram_id, MTX_MTX_MCMID) |
+                   F_ENCODE(byte_addr >> 2, MTX_MTX_MCM_ADDR) |
+                   F_ENCODE(1, MTX_MTX_MCMR));
+
+       /* ?? poll this reg? */
+       topaz_wait_for_register(dev_priv,
+                               MTX_START + MTX_CR_MTX_RAM_ACCESS_STATUS,
+                               1, 1);
+
+       MTX_READ32(MTX_CR_MTX_RAM_ACCESS_DATA_TRANSFER, &read_val);
+
+       return read_val;
+}
+
+void topaz_write_mtx_mem(struct drm_psb_private *dev_priv,
+                        uint32_t byte_addr, uint32_t val)
+{
+       uint32_t ram_id = 0;
+       uint32_t reg, bank_size, ram_bank_size;
+
+       TOPAZ_READ32(0x3c, &reg);
+
+       /* PSB_DEBUG_GENERAL ("TOPAZ: DEBUG REG(%x)\n", reg); */
+       reg = 0x0a0a0606;
+
+       bank_size = (reg & 0xF0000) >> 16;
+
+       ram_bank_size = (uint32_t)(1 << (bank_size + 2));
+       ram_id = (byte_addr - MTX_DATA_MEM_BASE) / ram_bank_size;
+
+       MTX_WRITE32(MTX_CR_MTX_RAM_ACCESS_CONTROL,
+                   F_ENCODE(0x18 + ram_id, MTX_MTX_MCMID) |
+                   F_ENCODE(byte_addr >> 2, MTX_MTX_MCM_ADDR));
+
+       MTX_WRITE32(MTX_CR_MTX_RAM_ACCESS_DATA_TRANSFER, val);
+
+       /* ?? poll this reg? */
+       topaz_wait_for_register(dev_priv,
+                               MTX_START + MTX_CR_MTX_RAM_ACCESS_STATUS,
+                               1, 1);
+
+       return;
+}
+
+void topaz_write_mtx_mem_multiple_setup(struct drm_psb_private *dev_priv,
+                                       uint32_t byte_addr)
+{
+       uint32_t ram_id = 0;
+       uint32_t reg, bank_size, ram_bank_size;
+
+       TOPAZ_READ32(0x3c, &reg);
+
+       reg = 0x0a0a0606;
+
+       bank_size = (reg & 0xF0000) >> 16;
+
+       ram_bank_size = (uint32_t)(1 << (bank_size + 2));
+       ram_id = (byte_addr - MTX_DATA_MEM_BASE) / ram_bank_size;
+
+       MTX_WRITE32(MTX_CR_MTX_RAM_ACCESS_CONTROL,
+                   F_ENCODE(0x18 + ram_id, MTX_MTX_MCMID) |
+                   F_ENCODE(1, MTX_MTX_MCMAI) |
+                   F_ENCODE(byte_addr >> 2, MTX_MTX_MCM_ADDR));
+}
+
+void topaz_write_mtx_mem_multiple(struct drm_psb_private *dev_priv,
+                                 uint32_t val)
+{
+       MTX_WRITE32(MTX_CR_MTX_RAM_ACCESS_DATA_TRANSFER, val);
+}
+
+
+int topaz_wait_for_register(struct drm_psb_private *dev_priv,
+                           uint32_t addr, uint32_t value, uint32_t mask)
+{
+       uint32_t tmp;
+       uint32_t count = 10000;
+
+       /* # poll topaz register for certain times */
+       while (count) {
+               /* #.# read */
+               MM_READ32(addr, 0, &tmp);
+
+               if (value == (tmp & mask))
+                       return 0;
+
+               /* #.# delay and loop */
+               DRM_UDELAY(100);
+               --count;
+       }
+
+       /* # now waiting is timeout, return 1 indicat failed */
+       /* XXX: testsuit means a timeout 10000 */
+
+       DRM_ERROR("TOPAZ:time out to poll addr(0x%x) expected value(0x%08x), "
+                 "actual 0x%08x (0x%08x & 0x%08x)\n",
+                 addr, value, tmp & mask, tmp, mask);
+
+       return -EBUSY;
+
+}
+
+static ssize_t psb_topaz_pmstate_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct drm_device *drm_dev = dev_get_drvdata(dev);
+       struct drm_psb_private *dev_priv;
+       struct topaz_private *topaz_priv;
+       unsigned int pmstate;
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       if (drm_dev == NULL)
+               return 0;
+
+       dev_priv = drm_dev->dev_private;
+       topaz_priv = dev_priv->topaz_private;
+       pmstate = topaz_priv->pmstate;
+
+       pmstate = topaz_priv->pmstate;
+       spin_lock_irqsave(&topaz_priv->topaz_lock, flags);
+       ret = snprintf(buf, 32, "%s\n",
+                      (pmstate == PSB_PMSTATE_POWERUP) ? "powerup"
+                      : ((pmstate == PSB_PMSTATE_POWERDOWN) ? "powerdown"
+                         : "clockgated"));
+       spin_unlock_irqrestore(&topaz_priv->topaz_lock, flags);
+
+       return ret;
+}
+
+static DEVICE_ATTR(topaz_pmstate, 0444, psb_topaz_pmstate_show, NULL);
+
+
+/* this function finish the first part of initialization, the rest
+ * should be done in topaz_setup_fw
+ */
+int lnc_topaz_init(struct drm_device *dev)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       struct ttm_bo_device *bdev = &dev_priv->bdev;
+       uint32_t core_id, core_rev;
+       int ret = 0, n;
+       bool is_iomem;
+       struct topaz_private *topaz_priv;
+       void *topaz_bo_virt;
+
+       PSB_DEBUG_GENERAL("TOPAZ: init topaz data structures\n");
+       topaz_priv = kmalloc(sizeof(struct topaz_private), GFP_KERNEL);
+       if (topaz_priv == NULL)
+               return -1;
+
+       dev_priv->topaz_private = topaz_priv;
+       memset(topaz_priv, 0, sizeof(struct topaz_private));
+
+       /* get device --> drm_device --> drm_psb_private --> topaz_priv
+        * for psb_topaz_pmstate_show: topaz_pmpolicy
+        * if not pci_set_drvdata, can't get drm_device from device
+        */
+       pci_set_drvdata(dev->pdev, dev);
+       if (device_create_file(&dev->pdev->dev,
+                              &dev_attr_topaz_pmstate))
+               DRM_ERROR("TOPAZ: could not create sysfs file\n");
+       topaz_priv->sysfs_pmstate = sysfs_get_dirent(
+                                           dev->pdev->dev.kobj.sd,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
+                                           NULL,
+#endif
+                                           "topaz_pmstate");
+
+       topaz_priv = dev_priv->topaz_private;
+
+       /* # initialize comand topaz queueing [msvdx_queue] */
+       INIT_LIST_HEAD(&topaz_priv->topaz_queue);
+       /* # init mutex? CHECK: mutex usage [msvdx_mutex] */
+       mutex_init(&topaz_priv->topaz_mutex);
+       /* # spin lock init? CHECK spin lock usage [msvdx_lock] */
+       spin_lock_init(&topaz_priv->topaz_lock);
+
+       /* # topaz status init. [msvdx_busy] */
+       topaz_priv->topaz_busy = 0;
+       topaz_priv->topaz_cmd_seq = 0;
+       topaz_priv->topaz_fw_loaded = 0;
+       /* FIXME: workaround since JPEG firmware is not ready */
+       topaz_priv->topaz_cur_codec = 1;
+       topaz_priv->cur_mtx_data_size = 0;
+       topaz_priv->topaz_hw_busy = 1;
+
+       topaz_priv->topaz_mtx_reg_state = kmalloc(TOPAZ_MTX_REG_SIZE,
+                                         GFP_KERNEL);
+       if (topaz_priv->topaz_mtx_reg_state == NULL) {
+               DRM_ERROR("TOPAZ: failed to allocate space "
+                         "for mtx register\n");
+               return -1;
+       }
+
+       /* # gain write back structure,we may only need 32+4=40DW */
+       ret = ttm_buffer_object_create(bdev, 4096,
+                                      ttm_bo_type_kernel,
+                                      DRM_PSB_FLAG_MEM_MMU | TTM_PL_FLAG_NO_EVICT,
+                                      0, 0, 0, NULL, &(topaz_priv->topaz_bo));
+       if (ret != 0) {
+               DRM_ERROR("TOPAZ: failed to allocate topaz BO.\n");
+               return ret;
+       }
+
+       ret = ttm_bo_kmap(topaz_priv->topaz_bo, 0,
+                         topaz_priv->topaz_bo->num_pages,
+                         &topaz_priv->topaz_bo_kmap);
+       if (ret) {
+               DRM_ERROR("TOPAZ: map topaz BO bo failed......\n");
+               ttm_bo_unref(&topaz_priv->topaz_bo);
+               return ret;
+       }
+
+       topaz_bo_virt = ttm_kmap_obj_virtual(&topaz_priv->topaz_bo_kmap,
+                                            &is_iomem);
+       topaz_priv->topaz_ccb_wb = (void *) topaz_bo_virt;
+       topaz_priv->topaz_wb_offset = topaz_priv->topaz_bo->offset;
+       topaz_priv->topaz_sync_addr = (uint32_t *)(topaz_bo_virt
+                                     + 2048);
+       topaz_priv->topaz_sync_offset = topaz_priv->topaz_wb_offset
+                                       + 2048;
+       PSB_DEBUG_GENERAL("TOPAZ: alloc BO for WriteBack and SYNC\n");
+       PSB_DEBUG_GENERAL("TOPAZ: WB offset=0x%08x\n",
+                         topaz_priv->topaz_wb_offset);
+       PSB_DEBUG_GENERAL("TOPAZ: SYNC offset=0x%08x\n",
+                         topaz_priv->topaz_sync_offset);
+
+       *(topaz_priv->topaz_sync_addr) =  ~0; /* reset sync seq */
+
+       /* # reset topaz */
+       MVEA_WRITE32(MVEA_CR_IMG_MVEA_SRST,
+                    F_ENCODE(1, MVEA_CR_IMG_MVEA_SPE_SOFT_RESET) |
+                    F_ENCODE(1, MVEA_CR_IMG_MVEA_IPE_SOFT_RESET) |
+                    F_ENCODE(1, MVEA_CR_IMG_MVEA_CMPRS_SOFT_RESET) |
+                    F_ENCODE(1, MVEA_CR_IMG_MVEA_JMCOMP_SOFT_RESET) |
+                    F_ENCODE(1, MVEA_CR_IMG_MVEA_CMC_SOFT_RESET) |
+                    F_ENCODE(1, MVEA_CR_IMG_MVEA_DCF_SOFT_RESET));
+
+       MVEA_WRITE32(MVEA_CR_IMG_MVEA_SRST,
+                    F_ENCODE(0, MVEA_CR_IMG_MVEA_SPE_SOFT_RESET) |
+                    F_ENCODE(0, MVEA_CR_IMG_MVEA_IPE_SOFT_RESET) |
+                    F_ENCODE(0, MVEA_CR_IMG_MVEA_CMPRS_SOFT_RESET) |
+                    F_ENCODE(0, MVEA_CR_IMG_MVEA_JMCOMP_SOFT_RESET) |
+                    F_ENCODE(0, MVEA_CR_IMG_MVEA_CMC_SOFT_RESET) |
+                    F_ENCODE(0, MVEA_CR_IMG_MVEA_DCF_SOFT_RESET));
+
+       /* # set up MMU */
+       topaz_mmu_hwsetup(dev_priv);
+
+       PSB_DEBUG_GENERAL("TOPAZ: defer firmware loading to the place"
+                         "when receiving user space commands\n");
+
+#if 0 /* can't load FW here */
+       /* #.# load fw to driver */
+       PSB_DEBUG_GENERAL("TOPAZ: will init firmware\n");
+       ret = topaz_init_fw(dev);
+       if (ret != 0)
+               return -1;
+
+       topaz_setup_fw(dev, IMG_CODEC_MPEG4_NO_RC);/* just for test */
+#endif
+       /* <msvdx does> # minimal clock */
+
+       /* <msvdx does> # return 0 */
+       TOPAZ_READ32(TOPAZ_CR_IMG_TOPAZ_CORE_ID, &core_id);
+       TOPAZ_READ32(TOPAZ_CR_IMG_TOPAZ_CORE_REV, &core_rev);
+
+       PSB_DEBUG_GENERAL("TOPAZ: core_id(%x) core_rev(%x)\n",
+                         core_id, core_rev);
+
+       /* create firmware storage */
+       for (n = 1; n < IMG_CODEC_NUM; ++n) {
+               /* #.# malloc DRM object for fw storage */
+               ret = ttm_buffer_object_create(bdev, 12 * 4096,
+                                              ttm_bo_type_kernel,
+                                              DRM_PSB_FLAG_MEM_MMU | TTM_PL_FLAG_NO_EVICT,
+                                              0, 0, 0, NULL, &topaz_priv->topaz_fw[n].text);
+               if (ret) {
+                       DRM_ERROR("Failed to allocate firmware.\n");
+                       goto out;
+               }
+
+               /* #.# malloc DRM object for fw storage */
+               ret = ttm_buffer_object_create(bdev, 12 * 4096,
+                                              ttm_bo_type_kernel,
+                                              DRM_PSB_FLAG_MEM_MMU | TTM_PL_FLAG_NO_EVICT,
+                                              0, 0, 0, NULL, &topaz_priv->topaz_fw[n].data);
+               if (ret) {
+                       DRM_ERROR("Failed to allocate firmware.\n");
+                       goto out;
+               }
+       }
+
+       ret = ttm_buffer_object_create(bdev,
+                                      12 * 4096,
+                                      ttm_bo_type_kernel,
+                                      DRM_PSB_FLAG_MEM_MMU |
+                                      TTM_PL_FLAG_NO_EVICT,
+                                      0, 0, 0, NULL,
+                                      &topaz_priv->topaz_mtx_data_mem);
+       if (ret) {
+               DRM_ERROR("TOPAZ: failed to allocate ttm buffer for "
+                         "mtx data save\n");
+               goto out;
+       }
+       topaz_priv->cur_mtx_data_size = 0;
+
+       if (drm_psb_topaz_clockgating == 0) {
+               PSB_DEBUG_INIT("TOPAZ:old clock gating disable = 0x%08x\n",
+                              PSB_RVDC32(PSB_TOPAZ_CLOCKGATING));
+
+               PSB_DEBUG_INIT("TOPAZ:reset to disable clock gating\n");
+
+               PSB_WVDC32(0x00011fff, PSB_TOPAZ_CLOCKGATING);
+
+               PSB_DEBUG_INIT("MSDVX:new clock gating disable = 0x%08x\n",
+                              PSB_RVDC32(PSB_TOPAZ_CLOCKGATING));
+       }
+
+       return 0;
+
+out:
+       for (n = 1; n < IMG_CODEC_NUM; ++n) {
+               if (topaz_priv->topaz_fw[n].text != NULL)
+                       ttm_bo_unref(&topaz_priv->topaz_fw[n].text);
+               if (topaz_priv->topaz_fw[n].data != NULL)
+                       ttm_bo_unref(&topaz_priv->topaz_fw[n].data);
+       }
+
+       if (topaz_priv->topaz_mtx_data_mem != NULL)
+               ttm_bo_unref(&topaz_priv->topaz_mtx_data_mem);
+
+       return ret;
+}
+
+int lnc_topaz_uninit(struct drm_device *dev)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+       int n;
+
+       /* flush MMU */
+       PSB_DEBUG_GENERAL("XXX: need to flush mmu cache here??\n");
+       /* topaz_mmu_flushcache (dev_priv); */
+
+       /* # reset TOPAZ chip */
+       lnc_topaz_reset(dev_priv);
+
+       if (NULL == topaz_priv) {
+               DRM_ERROR("TOPAZ: topaz_priv is NULL!\n");
+               return -1;
+       }
+       /* release resources */
+       /* # release write back memory */
+       topaz_priv->topaz_ccb_wb = NULL;
+
+       /* release mtx register save space */
+       kfree(topaz_priv->topaz_mtx_reg_state);
+
+       /* release mtx data memory save space */
+       if (topaz_priv->topaz_mtx_data_mem)
+               ttm_bo_unref(&topaz_priv->topaz_mtx_data_mem);
+
+       /* # release firmware storage */
+       for (n = 1; n < IMG_CODEC_NUM; ++n) {
+               if (topaz_priv->topaz_fw[n].text != NULL)
+                       ttm_bo_unref(&topaz_priv->topaz_fw[n].text);
+               if (topaz_priv->topaz_fw[n].data != NULL)
+                       ttm_bo_unref(&topaz_priv->topaz_fw[n].data);
+       }
+
+       ttm_bo_kunmap(&topaz_priv->topaz_bo_kmap);
+       ttm_bo_unref(&topaz_priv->topaz_bo);
+
+       if (topaz_priv) {
+               pci_set_drvdata(dev->pdev, NULL);
+               device_remove_file(&dev->pdev->dev, &dev_attr_topaz_pmstate);
+               sysfs_put(topaz_priv->sysfs_pmstate);
+               topaz_priv->sysfs_pmstate = NULL;
+
+               kfree(topaz_priv);
+               dev_priv->topaz_private = NULL;
+       }
+
+       return 0;
+}
+
+int lnc_topaz_reset(struct drm_psb_private *dev_priv)
+{
+       struct topaz_private *topaz_priv;
+
+       topaz_priv = dev_priv->topaz_private;
+       topaz_priv->topaz_busy = 0;
+       topaz_priv->topaz_cmd_seq = 0;
+       topaz_priv->cur_mtx_data_size = 0;
+       topaz_priv->topaz_cmd_windex = 0;
+       topaz_priv->topaz_needs_reset = 0;
+
+       /* # reset topaz */
+       MVEA_WRITE32(MVEA_CR_IMG_MVEA_SRST,
+                    F_ENCODE(1, MVEA_CR_IMG_MVEA_SPE_SOFT_RESET) |
+                    F_ENCODE(1, MVEA_CR_IMG_MVEA_IPE_SOFT_RESET) |
+                    F_ENCODE(1, MVEA_CR_IMG_MVEA_CMPRS_SOFT_RESET) |
+                    F_ENCODE(1, MVEA_CR_IMG_MVEA_JMCOMP_SOFT_RESET) |
+                    F_ENCODE(1, MVEA_CR_IMG_MVEA_CMC_SOFT_RESET) |
+                    F_ENCODE(1, MVEA_CR_IMG_MVEA_DCF_SOFT_RESET));
+
+       MVEA_WRITE32(MVEA_CR_IMG_MVEA_SRST,
+                    F_ENCODE(0, MVEA_CR_IMG_MVEA_SPE_SOFT_RESET) |
+                    F_ENCODE(0, MVEA_CR_IMG_MVEA_IPE_SOFT_RESET) |
+                    F_ENCODE(0, MVEA_CR_IMG_MVEA_CMPRS_SOFT_RESET) |
+                    F_ENCODE(0, MVEA_CR_IMG_MVEA_JMCOMP_SOFT_RESET) |
+                    F_ENCODE(0, MVEA_CR_IMG_MVEA_CMC_SOFT_RESET) |
+                    F_ENCODE(0, MVEA_CR_IMG_MVEA_DCF_SOFT_RESET));
+
+       /* # set up MMU */
+       topaz_mmu_hwsetup(dev_priv);
+
+       return 0;
+}
+
+/* read firmware bin file and load all data into driver */
+int topaz_init_fw(struct drm_device *dev)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       const struct firmware *raw = NULL;
+       unsigned char *ptr;
+       int ret = 0;
+       int n;
+       struct topaz_fwinfo *cur_fw;
+       int cur_size;
+       struct topaz_codec_fw *cur_codec;
+       struct ttm_buffer_object **cur_drm_obj;
+       struct ttm_bo_kmap_obj tmp_kmap;
+       bool is_iomem;
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+
+       topaz_priv->stored_initial_qp = 0;
+
+       /* # get firmware */
+       ret = request_firmware(&raw, FIRMWARE_NAME, &dev->pdev->dev);
+       if (ret != 0) {
+               DRM_ERROR("TOPAZ: request_firmware failed: %d\n", ret);
+               return ret;
+       }
+
+       PSB_DEBUG_GENERAL("TOPAZ: opened firmware\n");
+
+       if ((raw == NULL) || (raw->size < sizeof(struct topaz_fwinfo))) {
+               DRM_ERROR("TOPAZ: firmware file is not correct size.\n");
+               goto out;
+       }
+
+       ptr = (unsigned char *) raw->data;
+
+       if (!ptr) {
+               DRM_ERROR("TOPAZ: failed to load firmware.\n");
+               goto out;
+       }
+
+       /* # load fw from file */
+       PSB_DEBUG_GENERAL("TOPAZ: load firmware.....\n");
+       cur_fw = NULL;
+       /* didn't use the first element */
+       for (n = 1; n < IMG_CODEC_NUM; ++n) {
+               cur_fw = (struct topaz_fwinfo *) ptr;
+
+               cur_codec = &topaz_priv->topaz_fw[cur_fw->codec];
+               cur_codec->ver = cur_fw->ver;
+               cur_codec->codec = cur_fw->codec;
+               cur_codec->text_size = cur_fw->text_size;
+               cur_codec->data_size = cur_fw->data_size;
+               cur_codec->data_location = cur_fw->data_location;
+
+               PSB_DEBUG_GENERAL("TOPAZ: load firemware %s.\n",
+                                 codec_to_string(cur_fw->codec));
+
+               /* #.# handle text section */
+               ptr += sizeof(struct topaz_fwinfo);
+               cur_drm_obj = &cur_codec->text;
+               cur_size = cur_fw->text_size;
+
+               /* #.# fill DRM object with firmware data */
+               ret = ttm_bo_kmap(*cur_drm_obj, 0, (*cur_drm_obj)->num_pages,
+                                 &tmp_kmap);
+               if (ret) {
+                       PSB_DEBUG_GENERAL("drm_bo_kmap failed: %d\n", ret);
+                       ttm_bo_unref(cur_drm_obj);
+                       *cur_drm_obj = NULL;
+                       goto out;
+               }
+
+               memcpy(ttm_kmap_obj_virtual(&tmp_kmap, &is_iomem), ptr,
+                      cur_size);
+
+               ttm_bo_kunmap(&tmp_kmap);
+
+               /* #.# handle data section */
+               ptr += cur_fw->text_size;
+               cur_drm_obj = &cur_codec->data;
+               cur_size = cur_fw->data_size;
+
+               /* #.# fill DRM object with firmware data */
+               ret = ttm_bo_kmap(*cur_drm_obj, 0, (*cur_drm_obj)->num_pages,
+                                 &tmp_kmap);
+               if (ret) {
+                       PSB_DEBUG_GENERAL("drm_bo_kmap failed: %d\n", ret);
+                       ttm_bo_unref(cur_drm_obj);
+                       *cur_drm_obj = NULL;
+                       goto out;
+               }
+
+               memcpy(ttm_kmap_obj_virtual(&tmp_kmap, &is_iomem), ptr,
+                      cur_size);
+
+               ttm_bo_kunmap(&tmp_kmap);
+
+               /* #.# validate firmware */
+
+               /* #.# update ptr */
+               ptr += cur_fw->data_size;
+       }
+
+       release_firmware(raw);
+
+       PSB_DEBUG_GENERAL("TOPAZ: return from firmware init\n");
+
+       return 0;
+
+out:
+       if (raw) {
+               PSB_DEBUG_GENERAL("release firmware....\n");
+               release_firmware(raw);
+       }
+
+       return -1;
+}
+
+/* setup fw when start a new context */
+int topaz_setup_fw(struct drm_device *dev, enum drm_lnc_topaz_codec codec)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       uint32_t mem_size = RAM_SIZE; /* follow DDK */
+       uint32_t verify_pc;
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+
+#if 0
+       if (codec == topaz_priv->topaz_current_codec) {
+               LNC_TRACEL("TOPAZ: reuse previous codec\n");
+               return 0;
+       }
+#endif
+
+       /* XXX: need to rest topaz? */
+       PSB_DEBUG_GENERAL("XXX: should reset topaz when context change?\n");
+
+       /* XXX: interrupt enable shouldn't be enable here,
+        * this funtion is called when interrupt is enable,
+        * but here, we've no choice since we have to call setup_fw by
+        * manual */
+       /* # upload firmware, clear interruputs and start the firmware
+        * -- from  hostutils.c in TestSuits*/
+
+       /* # reset MVEA */
+       MVEA_WRITE32(MVEA_CR_IMG_MVEA_SRST,
+                    F_ENCODE(1, MVEA_CR_IMG_MVEA_SPE_SOFT_RESET) |
+                    F_ENCODE(1, MVEA_CR_IMG_MVEA_IPE_SOFT_RESET) |
+                    F_ENCODE(1, MVEA_CR_IMG_MVEA_CMPRS_SOFT_RESET) |
+                    F_ENCODE(1, MVEA_CR_IMG_MVEA_JMCOMP_SOFT_RESET) |
+                    F_ENCODE(1, MVEA_CR_IMG_MVEA_CMC_SOFT_RESET) |
+                    F_ENCODE(1, MVEA_CR_IMG_MVEA_DCF_SOFT_RESET));
+
+       MVEA_WRITE32(MVEA_CR_IMG_MVEA_SRST,
+                    F_ENCODE(0, MVEA_CR_IMG_MVEA_SPE_SOFT_RESET) |
+                    F_ENCODE(0, MVEA_CR_IMG_MVEA_IPE_SOFT_RESET) |
+                    F_ENCODE(0, MVEA_CR_IMG_MVEA_CMPRS_SOFT_RESET) |
+                    F_ENCODE(0, MVEA_CR_IMG_MVEA_JMCOMP_SOFT_RESET) |
+                    F_ENCODE(0, MVEA_CR_IMG_MVEA_CMC_SOFT_RESET) |
+                    F_ENCODE(0, MVEA_CR_IMG_MVEA_DCF_SOFT_RESET));
+
+
+       topaz_mmu_hwsetup(dev_priv);
+
+#if !LNC_TOPAZ_NO_IRQ
+       psb_irq_uninstall_islands(dev, OSPM_VIDEO_ENC_ISLAND);
+#endif
+
+       PSB_DEBUG_GENERAL("TOPAZ: will setup firmware....\n");
+
+       topaz_set_default_regs(dev_priv);
+
+       /* # reset mtx */
+       TOPAZ_WRITE32(TOPAZ_CR_IMG_TOPAZ_SRST,
+                     F_ENCODE(1, TOPAZ_CR_IMG_TOPAZ_MVEA_SOFT_RESET) |
+                     F_ENCODE(1, TOPAZ_CR_IMG_TOPAZ_MTX_SOFT_RESET) |
+                     F_ENCODE(1, TOPAZ_CR_IMG_TOPAZ_VLC_SOFT_RESET));
+
+       TOPAZ_WRITE32(TOPAZ_CR_IMG_TOPAZ_SRST, 0x0);
+
+       /* # upload fw by drm */
+       PSB_DEBUG_GENERAL("TOPAZ: will upload firmware\n");
+
+       topaz_upload_fw(dev, codec);
+#if 0
+       /* allocate the space for context save & restore if needed */
+       if (topaz_priv->topaz_mtx_data_mem == NULL) {
+               ret = ttm_buffer_object_create(bdev,
+                                              topaz_priv->cur_mtx_data_size * 4,
+                                              ttm_bo_type_kernel,
+                                              DRM_PSB_FLAG_MEM_MMU |
+                                              TTM_PL_FLAG_NO_EVICT,
+                                              0, 0, 0, NULL,
+                                              &topaz_priv->topaz_mtx_data_mem);
+               if (ret) {
+                       DRM_ERROR("TOPAZ: failed to allocate ttm buffer for "
+                                 "mtx data save\n");
+                       return -1;
+               }
+       }
+       PSB_DEBUG_GENERAL("TOPAZ: after upload fw ....\n");
+#endif
+
+       /* XXX: In power save mode, need to save the complete data memory
+        * and restore it. MTX_FWIF.c record the data size  */
+       PSB_DEBUG_GENERAL("TOPAZ:in power save mode need to save memory?\n");
+
+       PSB_DEBUG_GENERAL("TOPAZ: setting up pc address\n");
+       topaz_write_core_reg(dev_priv, TOPAZ_MTX_PC, PC_START_ADDRESS);
+
+       PSB_DEBUG_GENERAL("TOPAZ: verify pc address\n");
+
+       topaz_read_core_reg(dev_priv, TOPAZ_MTX_PC, &verify_pc);
+
+       /* enable auto clock is essential for this driver */
+       TOPAZ_WRITE32(TOPAZ_CR_TOPAZ_AUTO_CLK_GATE,
+                     F_ENCODE(1, TOPAZ_CR_TOPAZ_VLC_AUTO_CLK_GATE) |
+                     F_ENCODE(1, TOPAZ_CR_TOPAZ_DB_AUTO_CLK_GATE));
+       MVEA_WRITE32(MVEA_CR_MVEA_AUTO_CLOCK_GATING,
+                    F_ENCODE(1, MVEA_CR_MVEA_IPE_AUTO_CLK_GATE) |
+                    F_ENCODE(1, MVEA_CR_MVEA_SPE_AUTO_CLK_GATE) |
+                    F_ENCODE(1, MVEA_CR_MVEA_CMPRS_AUTO_CLK_GATE) |
+                    F_ENCODE(1, MVEA_CR_MVEA_JMCOMP_AUTO_CLK_GATE));
+
+       PSB_DEBUG_GENERAL("TOPAZ: current pc(%08X) vs %08X\n",
+                         verify_pc, PC_START_ADDRESS);
+
+       /* # turn on MTX */
+       TOPAZ_WRITE32(TOPAZ_CR_IMG_TOPAZ_INTCLEAR,
+                     F_ENCODE(1, TOPAZ_CR_IMG_TOPAZ_INTCLR_MTX));
+
+       MTX_WRITE32(MTX_CORE_CR_MTX_ENABLE_OFFSET,
+                   MTX_CORE_CR_MTX_ENABLE_MTX_ENABLE_MASK);
+
+       /* # poll on the interrupt which the firmware will generate */
+       topaz_wait_for_register(dev_priv,
+                               TOPAZ_START + TOPAZ_CR_IMG_TOPAZ_INTSTAT,
+                               F_ENCODE(1, TOPAZ_CR_IMG_TOPAZ_INTS_MTX),
+                               F_MASK(TOPAZ_CR_IMG_TOPAZ_INTS_MTX));
+
+       TOPAZ_WRITE32(TOPAZ_CR_IMG_TOPAZ_INTCLEAR,
+                     F_ENCODE(1, TOPAZ_CR_IMG_TOPAZ_INTCLR_MTX));
+
+       PSB_DEBUG_GENERAL("TOPAZ: after topaz mtx setup ....\n");
+
+       /* # get ccb buffer addr -- file hostutils.c */
+       topaz_priv->topaz_ccb_buffer_addr =
+               topaz_read_mtx_mem(dev_priv,
+                                  MTX_DATA_MEM_BASE + mem_size - 4);
+       topaz_priv->topaz_ccb_ctrl_addr =
+               topaz_read_mtx_mem(dev_priv,
+                                  MTX_DATA_MEM_BASE + mem_size - 8);
+       topaz_priv->topaz_ccb_size =
+               topaz_read_mtx_mem(dev_priv,
+                                  topaz_priv->topaz_ccb_ctrl_addr +
+                                  MTX_CCBCTRL_CCBSIZE);
+
+       topaz_priv->topaz_cmd_windex = 0;
+
+       PSB_DEBUG_GENERAL("TOPAZ:ccb_buffer_addr(%x),ctrl_addr(%x) size(%d)\n",
+                         topaz_priv->topaz_ccb_buffer_addr,
+                         topaz_priv->topaz_ccb_ctrl_addr,
+                         topaz_priv->topaz_ccb_size);
+
+       /* # write back the initial QP Value */
+       topaz_write_mtx_mem(dev_priv,
+                           topaz_priv->topaz_ccb_ctrl_addr + MTX_CCBCTRL_INITQP,
+                           topaz_priv->stored_initial_qp);
+
+       PSB_DEBUG_GENERAL("TOPAZ: write WB mem address 0x%08x\n",
+                         topaz_priv->topaz_wb_offset);
+       topaz_write_mtx_mem(dev_priv, MTX_DATA_MEM_BASE + mem_size - 12,
+                           topaz_priv->topaz_wb_offset);
+
+       /* this kick is essential for mtx.... */
+       *((uint32_t *) topaz_priv->topaz_ccb_wb) = 0x01020304;
+       topaz_mtx_kick(dev_priv, 1);
+       DRM_UDELAY(1000);
+       PSB_DEBUG_GENERAL("TOPAZ: DDK expected 0x12345678 in WB memory,"
+                         " and here it is 0x%08x\n",
+                         *((uint32_t *) topaz_priv->topaz_ccb_wb));
+
+       *((uint32_t *) topaz_priv->topaz_ccb_wb) = 0x0;/* reset it to 0 */
+       PSB_DEBUG_GENERAL("TOPAZ: firmware uploaded.\n");
+
+       /* XXX: is there any need to record next cmd num??
+        * we use fence seqence number to record it
+        */
+       topaz_priv->topaz_busy = 0;
+       topaz_priv->topaz_cmd_seq = 0;
+
+#if !LNC_TOPAZ_NO_IRQ
+       psb_irq_preinstall_islands(dev, OSPM_VIDEO_ENC_ISLAND);
+       psb_irq_postinstall_islands(dev, OSPM_VIDEO_ENC_ISLAND);
+       lnc_topaz_enableirq(dev);
+#endif
+
+#if 0
+       topaz_mmu_flushcache(dev_priv);
+       topaz_test_null(dev, 0xe1e1);
+       topaz_test_null(dev, 0xe2e2);
+       topaz_test_sync(dev, 0xe2e2, 0x87654321);
+
+       topaz_mmu_test(dev, 0x12345678);
+       topaz_test_null(dev, 0xe3e3);
+       topaz_mmu_test(dev, 0x8764321);
+
+       topaz_test_null(dev, 0xe4e4);
+       topaz_test_null(dev, 0xf3f3);
+#endif
+
+       return 0;
+}
+
+#if UPLOAD_FW_BY_DMA
+int topaz_upload_fw(struct drm_device *dev, enum drm_lnc_topaz_codec codec)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       const struct topaz_codec_fw *cur_codec_fw;
+       uint32_t text_size, data_size;
+       uint32_t data_location;
+       uint32_t cur_mtx_data_size;
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+
+       /* # refer HLD document */
+
+       /* # MTX reset */
+       PSB_DEBUG_GENERAL("TOPAZ: mtx reset.\n");
+       MTX_WRITE32(MTX_CORE_CR_MTX_SOFT_RESET_OFFSET,
+                   MTX_CORE_CR_MTX_SOFT_RESET_MTX_RESET_MASK);
+
+       DRM_UDELAY(6000);
+
+       /* # upload the firmware by DMA */
+       cur_codec_fw = &topaz_priv->topaz_fw[codec];
+
+       PSB_DEBUG_GENERAL("Topaz:upload codec %s(%d) text sz=%d data sz=%d"
+                         " data location(0x%08x)\n",   codec_to_string(codec), codec,
+                         cur_codec_fw->text_size, cur_codec_fw->data_size,
+                         cur_codec_fw->data_location);
+
+       /* # upload text */
+       text_size = cur_codec_fw->text_size / 4;
+
+       /* setup the MTX to start recieving data:
+          use a register for the transfer which will point to the source
+          (MTX_CR_MTX_SYSC_CDMAT) */
+       /* #.# fill the dst addr */
+       MTX_WRITE32(MTX_CR_MTX_SYSC_CDMAA, 0x80900000);
+       MTX_WRITE32(MTX_CR_MTX_SYSC_CDMAC,
+                   F_ENCODE(2, MTX_BURSTSIZE) |
+                   F_ENCODE(0, MTX_RNW) |
+                   F_ENCODE(1, MTX_ENABLE) |
+                   F_ENCODE(text_size, MTX_LENGTH));
+
+       /* #.# set DMAC access to host memory via BIF */
+       TOPAZ_WRITE32(TOPAZ_CR_IMG_TOPAZ_DMAC_MODE, 1);
+
+       /* #.# transfer the codec */
+       topaz_dma_transfer(dev_priv, 0, cur_codec_fw->text->offset, 0,
+                          MTX_CR_MTX_SYSC_CDMAT, text_size, 0, 0);
+
+       /* #.# wait dma finish */
+       topaz_wait_for_register(dev_priv,
+                               DMAC_START + IMG_SOC_DMAC_IRQ_STAT(0),
+                               F_ENCODE(1, IMG_SOC_TRANSFER_FIN),
+                               F_ENCODE(1, IMG_SOC_TRANSFER_FIN));
+
+       /* #.# clear interrupt */
+       DMAC_WRITE32(IMG_SOC_DMAC_IRQ_STAT(0), 0);
+
+       /* # return access to topaz core */
+       TOPAZ_WRITE32(TOPAZ_CR_IMG_TOPAZ_DMAC_MODE, 0);
+
+       /* # upload data */
+       data_size = cur_codec_fw->data_size / 4;
+       data_location = cur_codec_fw->data_location;
+
+       /* #.# fill the dst addr */
+       MTX_WRITE32(MTX_CR_MTX_SYSC_CDMAA,
+                   0x80900000 + (data_location - 0x82880000));
+       MTX_WRITE32(MTX_CR_MTX_SYSC_CDMAC,
+                   F_ENCODE(2, MTX_BURSTSIZE) |
+                   F_ENCODE(0, MTX_RNW) |
+                   F_ENCODE(1, MTX_ENABLE) |
+                   F_ENCODE(data_size, MTX_LENGTH));
+
+       /* #.# set DMAC access to host memory via BIF */
+       TOPAZ_WRITE32(TOPAZ_CR_IMG_TOPAZ_DMAC_MODE, 1);
+
+       /* #.# transfer the codec */
+       topaz_dma_transfer(dev_priv, 0, cur_codec_fw->data->offset, 0,
+                          MTX_CR_MTX_SYSC_CDMAT, data_size, 0, 0);
+
+       /* #.# wait dma finish */
+       topaz_wait_for_register(dev_priv,
+                               DMAC_START + IMG_SOC_DMAC_IRQ_STAT(0),
+                               F_ENCODE(1, IMG_SOC_TRANSFER_FIN),
+                               F_ENCODE(1, IMG_SOC_TRANSFER_FIN));
+
+       /* #.# clear interrupt */
+       DMAC_WRITE32(IMG_SOC_DMAC_IRQ_STAT(0), 0);
+
+       /* # return access to topaz core */
+       TOPAZ_WRITE32(TOPAZ_CR_IMG_TOPAZ_DMAC_MODE, 0);
+
+       /* record this codec's mtx data size for
+        * context save & restore */
+       /* FIXME: since non-root sighting fixed by pre allocated,
+        * only need to correct the buffer size
+        */
+       cur_mtx_data_size = data_size;
+       if (topaz_priv->cur_mtx_data_size != cur_mtx_data_size)
+               topaz_priv->cur_mtx_data_size = cur_mtx_data_size;
+
+       return 0;
+}
+
+#else
+
+void topaz_mtx_upload_by_register(struct drm_device *dev, uint32_t mtx_mem,
+                                 uint32_t addr, uint32_t size,
+                                 struct ttm_buffer_object *buf)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       uint32_t *buf_p;
+       uint32_t debug_reg, bank_size, bank_ram_size, bank_count;
+       uint32_t cur_ram_id, ram_addr , ram_id;
+       int map_ret, lp;
+       struct ttm_bo_kmap_obj bo_kmap;
+       bool is_iomem;
+       uint32_t cur_addr;
+
+       get_mtx_control_from_dash(dev_priv);
+
+       map_ret = ttm_bo_kmap(buf, 0, buf->num_pages, &bo_kmap);
+       if (map_ret) {
+               DRM_ERROR("TOPAZ: drm_bo_kmap failed: %d\n", map_ret);
+               return;
+       }
+       buf_p = (uint32_t *) ttm_kmap_obj_virtual(&bo_kmap, &is_iomem);
+
+
+       TOPAZ_READ32(TOPAZ_CORE_CR_MTX_DEBUG_OFFSET, &debug_reg);
+       debug_reg = 0x0a0a0606;
+       bank_size = (debug_reg & 0xf0000) >> 16;
+       bank_ram_size = 1 << (bank_size + 2);
+
+       bank_count = (debug_reg & 0xf00) >> 8;
+
+       topaz_wait_for_register(dev_priv,
+                               MTX_START + MTX_CORE_CR_MTX_RAM_ACCESS_STATUS_OFFSET,
+                               MTX_CORE_CR_MTX_RAM_ACCESS_STATUS_MTX_MTX_MCM_STAT_MASK,
+                               MTX_CORE_CR_MTX_RAM_ACCESS_STATUS_MTX_MTX_MCM_STAT_MASK);
+
+       cur_ram_id = -1;
+       cur_addr = addr;
+       for (lp = 0; lp < size / 4; ++lp) {
+               ram_id = mtx_mem + (cur_addr / bank_ram_size);
+
+               if (cur_ram_id != ram_id) {
+                       ram_addr = cur_addr >> 2;
+
+                       MTX_WRITE32(MTX_CORE_CR_MTX_RAM_ACCESS_CONTROL_OFFSET,
+                                   F_ENCODE(ram_id, MTX_MTX_MCMID) |
+                                   F_ENCODE(ram_addr, MTX_MTX_MCM_ADDR) |
+                                   F_ENCODE(1, MTX_MTX_MCMAI));
+
+                       cur_ram_id = ram_id;
+               }
+               cur_addr += 4;
+
+               MTX_WRITE32(MTX_CORE_CR_MTX_RAM_ACCESS_DATA_TRANSFER_OFFSET,
+                           *(buf_p + lp));
+
+               topaz_wait_for_register(dev_priv,
+                                       MTX_CORE_CR_MTX_RAM_ACCESS_STATUS_OFFSET + MTX_START,
+                                       MTX_CORE_CR_MTX_RAM_ACCESS_STATUS_MTX_MTX_MCM_STAT_MASK,
+                                       MTX_CORE_CR_MTX_RAM_ACCESS_STATUS_MTX_MTX_MCM_STAT_MASK);
+       }
+
+       ttm_bo_kunmap(&bo_kmap);
+
+       PSB_DEBUG_GENERAL("TOPAZ: register data upload done\n");
+       return;
+}
+
+int topaz_upload_fw(struct drm_device *dev, enum drm_lnc_topaz_codec codec)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       const struct topaz_codec_fw *cur_codec_fw;
+       uint32_t text_size, data_size;
+       uint32_t data_location;
+
+       /* # refer HLD document */
+       /* # MTX reset */
+       PSB_DEBUG_GENERAL("TOPAZ: mtx reset.\n");
+       MTX_WRITE32(MTX_CORE_CR_MTX_SOFT_RESET_OFFSET,
+                   MTX_CORE_CR_MTX_SOFT_RESET_MTX_RESET_MASK);
+
+       DRM_UDELAY(6000);
+
+       /* # upload the firmware by DMA */
+       cur_codec_fw = &topaz_priv->topaz_fw[codec];
+
+       PSB_DEBUG_GENERAL("Topaz: upload codec %s text size(%d) data size(%d)"
+                         " data location(0x%08x)\n", codec_to_string(codec),
+                         cur_codec_fw->text_size, cur_codec_fw->data_size,
+                         cur_codec_fw->data_location);
+
+       /* # upload text */
+       text_size = cur_codec_fw->text_size;
+
+       topaz_mtx_upload_by_register(dev, LNC_MTX_CORE_CODE_MEM,
+                                    PC_START_ADDRESS - MTX_MEMORY_BASE,
+                                    text_size, cur_codec_fw->text);
+
+       /* # upload data */
+       data_size = cur_codec_fw->data_size;
+       data_location = cur_codec_fw->data_location;
+
+       topaz_mtx_upload_by_register(dev, LNC_MTX_CORE_DATA_MEM,
+                                    data_location - 0x82880000, data_size,
+                                    cur_codec_fw->data);
+
+       return 0;
+}
+
+#endif /* UPLOAD_FW_BY_DMA */
+
+void
+topaz_dma_transfer(struct drm_psb_private *dev_priv, uint32_t channel,
+                  uint32_t src_phy_addr, uint32_t offset,
+                  uint32_t soc_addr, uint32_t byte_num,
+                  uint32_t is_increment, uint32_t is_write)
+{
+       uint32_t dmac_count;
+       uint32_t irq_stat;
+       uint32_t count;
+
+       PSB_DEBUG_GENERAL("TOPAZ: using dma to transfer firmware\n");
+       /* # check that no transfer is currently in progress and no
+          interrupts are outstanding ?? (why care interrupt) */
+       DMAC_READ32(IMG_SOC_DMAC_COUNT(channel), &dmac_count);
+       if (0 != (dmac_count & (MASK_IMG_SOC_EN | MASK_IMG_SOC_LIST_EN)))
+               DRM_ERROR("TOPAZ: there is tranfer in progress\n");
+
+       /* assert(0==(dmac_count & (MASK_IMG_SOC_EN | MASK_IMG_SOC_LIST_EN)));*/
+
+       /* no hold off period */
+       DMAC_WRITE32(IMG_SOC_DMAC_PER_HOLD(channel), 0);
+       /* clear previous interrupts */
+       DMAC_WRITE32(IMG_SOC_DMAC_IRQ_STAT(channel), 0);
+       /* check irq status */
+       DMAC_READ32(IMG_SOC_DMAC_IRQ_STAT(channel), &irq_stat);
+       /* assert(0 == irq_stat); */
+       if (0 != irq_stat)
+               DRM_ERROR("TOPAZ: there is hold up\n");
+
+       DMAC_WRITE32(IMG_SOC_DMAC_SETUP(channel),
+                    (src_phy_addr + offset));
+       count = DMAC_VALUE_COUNT(DMAC_BSWAP_NO_SWAP, DMAC_PWIDTH_32_BIT,
+                                is_write, DMAC_PWIDTH_32_BIT, byte_num);
+       /* generate an interrupt at the end of transfer */
+       count |= MASK_IMG_SOC_TRANSFER_IEN;
+       count |= F_ENCODE(is_write, IMG_SOC_DIR);
+       DMAC_WRITE32(IMG_SOC_DMAC_COUNT(channel), count);
+
+       DMAC_WRITE32(IMG_SOC_DMAC_PERIPH(channel),
+                    DMAC_VALUE_PERIPH_PARAM(DMAC_ACC_DEL_0,
+                                            is_increment, DMAC_BURST_2));
+
+       DMAC_WRITE32(IMG_SOC_DMAC_PERIPHERAL_ADDR(channel), soc_addr);
+
+       /* Finally, rewrite the count register with
+        * the enable bit set to kick off the transfer
+        */
+       DMAC_WRITE32(IMG_SOC_DMAC_COUNT(channel), count | MASK_IMG_SOC_EN);
+
+       PSB_DEBUG_GENERAL("TOPAZ: dma transfer started.\n");
+
+       return;
+}
+
+void topaz_set_default_regs(struct drm_psb_private *dev_priv)
+{
+       int n;
+       int count = sizeof(topaz_default_regs) / (sizeof(unsigned long) * 3);
+
+       for (n = 0; n < count; n++)
+               MM_WRITE32(topaz_default_regs[n][0],
+                          topaz_default_regs[n][1],
+                          topaz_default_regs[n][2]);
+
+}
+
+void topaz_write_core_reg(struct drm_psb_private *dev_priv, uint32_t reg,
+                         const uint32_t val)
+{
+       uint32_t tmp;
+       get_mtx_control_from_dash(dev_priv);
+
+       /* put data into MTX_RW_DATA */
+       MTX_WRITE32(MTX_CORE_CR_MTX_REGISTER_READ_WRITE_DATA_OFFSET, val);
+
+       /* request a write */
+       tmp = reg &
+             ~MTX_CORE_CR_MTX_REGISTER_READ_WRITE_REQUEST_MTX_DREADY_MASK;
+       MTX_WRITE32(MTX_CORE_CR_MTX_REGISTER_READ_WRITE_REQUEST_OFFSET, tmp);
+
+       /* wait for operation finished */
+       topaz_wait_for_register(dev_priv,
+                               MTX_START +
+                               MTX_CORE_CR_MTX_REGISTER_READ_WRITE_REQUEST_OFFSET,
+                               MTX_CORE_CR_MTX_REGISTER_READ_WRITE_REQUEST_MTX_DREADY_MASK,
+                               MTX_CORE_CR_MTX_REGISTER_READ_WRITE_REQUEST_MTX_DREADY_MASK);
+
+       release_mtx_control_from_dash(dev_priv);
+}
+
+void topaz_read_core_reg(struct drm_psb_private *dev_priv, uint32_t reg,
+                        uint32_t *ret_val)
+{
+       uint32_t tmp;
+
+       get_mtx_control_from_dash(dev_priv);
+
+       /* request a write */
+       tmp = (reg &
+              ~MTX_CORE_CR_MTX_REGISTER_READ_WRITE_REQUEST_MTX_DREADY_MASK);
+       MTX_WRITE32(MTX_CORE_CR_MTX_REGISTER_READ_WRITE_REQUEST_OFFSET,
+                   MTX_CORE_CR_MTX_REGISTER_READ_WRITE_REQUEST_MTX_RNW_MASK | tmp);
+
+       /* wait for operation finished */
+       topaz_wait_for_register(dev_priv,
+                               MTX_START +
+                               MTX_CORE_CR_MTX_REGISTER_READ_WRITE_REQUEST_OFFSET,
+                               MTX_CORE_CR_MTX_REGISTER_READ_WRITE_REQUEST_MTX_DREADY_MASK,
+                               MTX_CORE_CR_MTX_REGISTER_READ_WRITE_REQUEST_MTX_DREADY_MASK);
+
+       /* read  */
+       MTX_READ32(MTX_CORE_CR_MTX_REGISTER_READ_WRITE_DATA_OFFSET,
+                  ret_val);
+
+       release_mtx_control_from_dash(dev_priv);
+}
+
+void get_mtx_control_from_dash(struct drm_psb_private *dev_priv)
+{
+       int debug_reg_slave_val;
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+
+       /* GetMTXControlFromDash */
+       TOPAZ_WRITE32(TOPAZ_CORE_CR_MTX_DEBUG_OFFSET,
+                     F_ENCODE(1, TOPAZ_CR_MTX_DBG_IS_SLAVE) |
+                     F_ENCODE(2, TOPAZ_CR_MTX_DBG_GPIO_OUT));
+       do {
+               TOPAZ_READ32(TOPAZ_CORE_CR_MTX_DEBUG_OFFSET,
+                            &debug_reg_slave_val);
+       } while ((debug_reg_slave_val & 0x18) != 0);
+
+       /* save access control */
+       TOPAZ_READ32(MTX_CORE_CR_MTX_RAM_ACCESS_CONTROL_OFFSET,
+                    &topaz_priv->topaz_dash_access_ctrl);
+}
+
+void release_mtx_control_from_dash(struct drm_psb_private *dev_priv)
+{
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+
+       /* restore access control */
+       TOPAZ_WRITE32(MTX_CORE_CR_MTX_RAM_ACCESS_CONTROL_OFFSET,
+                     topaz_priv->topaz_dash_access_ctrl);
+
+       /* release bus */
+       TOPAZ_WRITE32(TOPAZ_CORE_CR_MTX_DEBUG_OFFSET,
+                     F_ENCODE(1, TOPAZ_CR_MTX_DBG_IS_SLAVE));
+}
+
+void topaz_mmu_hwsetup(struct drm_psb_private *dev_priv)
+{
+       uint32_t pd_addr = psb_get_default_pd_addr(dev_priv->mmu);
+
+       /* bypass all request while MMU is being configured */
+       TOPAZ_WRITE32(TOPAZ_CR_MMU_CONTROL0,
+                     F_ENCODE(1, TOPAZ_CR_MMU_BYPASS));
+
+       /* set MMU hardware at the page table directory */
+       PSB_DEBUG_GENERAL("TOPAZ: write PD phyaddr=0x%08x "
+                         "into MMU_DIR_LIST0/1\n", pd_addr);
+       TOPAZ_WRITE32(TOPAZ_CR_MMU_DIR_LIST_BASE(0), pd_addr);
+       TOPAZ_WRITE32(TOPAZ_CR_MMU_DIR_LIST_BASE(1), 0);
+
+       /* setup index register, all pointing to directory bank 0 */
+       TOPAZ_WRITE32(TOPAZ_CR_MMU_BANK_INDEX, 0);
+
+       /* now enable MMU access for all requestors */
+       TOPAZ_WRITE32(TOPAZ_CR_MMU_CONTROL0, 0);
+}
+
+void topaz_mmu_flushcache(struct drm_psb_private *dev_priv)
+{
+       uint32_t mmu_control;
+
+       if (dev_priv->topaz_disabled)
+               return;
+
+#if 0
+       PSB_DEBUG_GENERAL("XXX: Only one PTD/PTE cache"
+                         " so flush using the master core\n");
+#endif
+       /* XXX: disable interrupt */
+
+       TOPAZ_READ32(TOPAZ_CR_MMU_CONTROL0, &mmu_control);
+       mmu_control |= F_ENCODE(1, TOPAZ_CR_MMU_INVALDC);
+       mmu_control |= F_ENCODE(1, TOPAZ_CR_MMU_FLUSH);
+
+#if 0
+       PSB_DEBUG_GENERAL("Set Invalid flag (this causes a flush with MMU\n"
+                         "still operating afterwards even if not cleared,\n"
+                         "but may want to replace with MMU_FLUSH?\n");
+#endif
+       TOPAZ_WRITE32(TOPAZ_CR_MMU_CONTROL0, mmu_control);
+
+       /* clear it */
+       mmu_control &= (~F_ENCODE(1, TOPAZ_CR_MMU_INVALDC));
+       mmu_control &= (~F_ENCODE(1, TOPAZ_CR_MMU_FLUSH));
+       TOPAZ_WRITE32(TOPAZ_CR_MMU_CONTROL0, mmu_control);
+}
+
+#if DEBUG_FUNCTION
+
+static int topaz_test_sync(struct drm_device *dev, uint32_t seq,
+                          uint32_t sync_seq)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+       uint32_t sync_cmd[3];
+       struct topaz_cmd_header *cmd_hdr;
+       uint32_t *sync_p = (uint32_t *)topaz_priv->topaz_sync_addr;
+       int count = 1000;
+       uint32_t clr_flag;
+
+       cmd_hdr = (struct topaz_cmd_header *)&sync_cmd[0];
+
+       /* reset sync area */
+       *sync_p = 0;
+
+       /* insert a SYNC command here */
+       cmd_hdr->id = MTX_CMDID_SYNC;
+       cmd_hdr->size = 3;
+       cmd_hdr->seq = seq;
+
+       sync_cmd[1] = topaz_priv->topaz_sync_offset;
+       sync_cmd[2] = sync_seq;
+
+       TOPAZ_BEGIN_CCB(dev_priv);
+       TOPAZ_OUT_CCB(dev_priv, sync_cmd[0]);
+       TOPAZ_OUT_CCB(dev_priv, sync_cmd[1]);
+       TOPAZ_OUT_CCB(dev_priv, sync_cmd[2]);
+       TOPAZ_END_CCB(dev_priv, 1);
+
+       PSB_DEBUG_GENERAL("Topaz: Sent SYNC with cmd seq=0x%08x,"
+                         "sync_seq=0x%08x\n", seq, sync_seq);
+
+       while (count && *sync_p != sync_seq) {
+               DRM_UDELAY(100);
+               --count;
+       }
+       if ((count == 0) && (*sync_p != sync_seq)) {
+               DRM_ERROR("TOPAZ: wait sycn timeout, expect sync seq 0x%08x,"
+                         "actual 0x%08x\n", sync_seq, *sync_p);
+       }
+       PSB_DEBUG_GENERAL("TOPAZ: SYNC succeed, sync seq=0x%08x\n", *sync_p);
+       PSB_DEBUG_GENERAL("Topaz: after SYNC test, query IRQ and clear it\n");
+
+       clr_flag = lnc_topaz_queryirq(dev);
+       lnc_topaz_clearirq(dev, clr_flag);
+
+       return 0;
+}
+static int topaz_test_sync_tt_test(struct drm_device *dev,
+                                  uint32_t seq,
+                                  uint32_t sync_seq)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       struct ttm_bo_device *bdev = &dev_priv->bdev;
+       int ret;
+       bool is_iomem;
+       struct ttm_buffer_object *test_obj;
+       struct ttm_bo_kmap_obj test_kmap;
+       unsigned int *test_adr;
+       uint32_t sync_cmd[3];
+       int count = 1000;
+       unsigned long pfn;
+
+       ret = ttm_buffer_object_create(bdev, 4096,
+                                      ttm_bo_type_kernel,
+                                      TTM_PL_FLAG_TT | TTM_PL_FLAG_NO_EVICT,
+                                      0, 0, 0, NULL, &test_obj);
+       if (ret) {
+               DRM_ERROR("failed create test object buffer\n");
+               return -1;
+       }
+
+       ret = psb_mmu_virtual_to_pfn(psb_mmu_get_default_pd(dev_priv->mmu),
+                                    test_obj->offset, &pfn);
+       if (ret) {
+               DRM_ERROR("failed to get pfn from virtual\n");
+               return -1;
+       }
+
+       PSB_DEBUG_GENERAL("Topaz:offset %lx, pfn %lx\n", test_obj->offset, pfn);
+
+       ret = ttm_bo_kmap(test_obj, 0, test_obj->num_pages,
+                         &test_kmap);
+       if (ret) {
+               DRM_ERROR("failed map buffer\n");
+               return -1;
+       }
+       test_adr = ttm_kmap_obj_virtual(&test_kmap, &is_iomem);
+       *test_adr = 0xff55;
+       ttm_bo_kunmap(&test_kmap);
+
+       /* insert a SYNC command here */
+       sync_cmd[0] = (MTX_CMDID_SYNC << 1) | (3 << 8) |
+                     (seq << 16);
+       sync_cmd[1] = test_obj->offset;
+       sync_cmd[2] = sync_seq;
+
+       TOPAZ_BEGIN_CCB(dev_priv);
+       TOPAZ_OUT_CCB(dev_priv, sync_cmd[0]);
+       TOPAZ_OUT_CCB(dev_priv, sync_cmd[1]);
+       TOPAZ_OUT_CCB(dev_priv, sync_cmd[2]);
+       TOPAZ_END_CCB(dev_priv, 1);
+
+       ret = ttm_bo_kmap(test_obj, 0, test_obj->num_pages,
+                         &test_kmap);
+       if (ret) {
+               DRM_ERROR("failed map buffer\n");
+               return -1;
+       }
+       test_adr = ttm_kmap_obj_virtual(&test_kmap, &is_iomem);
+
+       while (count && *test_adr != sync_seq) {
+               DRM_UDELAY(100);
+               --count;
+       }
+       if ((count == 0) && (*test_adr != sync_seq)) {
+               DRM_ERROR("TOPAZ: wait sycn timeout (0x%08x),"
+                         "actual 0x%08x\n",
+                         sync_seq, *test_adr);
+       }
+       PSB_DEBUG_GENERAL("TOPAZ: SYNC done, seq=0x%08x\n", *test_adr);
+       ttm_bo_kunmap(&test_kmap);
+       ttm_bo_unref(&test_obj);
+
+       return 0;
+}
+
+static int topaz_test_sync_manual_alloc_page(struct drm_device *dev,
+               uint32_t seq,
+               uint32_t sync_seq,
+               uint32_t offset)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       int ret;
+       uint32_t sync_cmd[3];
+       int count = 1000;
+       unsigned long pfn;
+
+       struct page *p;
+       uint32_t *v;
+       /*      uint32_t offset = 0xd0000000; */
+
+       p = alloc_page(GFP_DMA32);
+       if (!p) {
+               DRM_ERROR("Topaz:Failed allocating page\n");
+               return -1;
+       }
+
+       v = kmap(p);
+       memset(v, 0x67, PAGE_SIZE);
+       pfn = (offset >> PAGE_SHIFT);
+       kunmap(p);
+
+       ret = psb_mmu_insert_pages(psb_mmu_get_default_pd(dev_priv->mmu),
+                                  &p, pfn << PAGE_SHIFT, 1, 0, 0, 0);
+       if (ret) {
+               DRM_ERROR("Topaz:Failed inserting mmu page\n");
+               return -1;
+       }
+
+       /* insert a SYNC command here */
+       sync_cmd[0] = (MTX_CMDID_SYNC << 1) | (3 << 8) |
+                     (0x5b << 16);
+       sync_cmd[1] = pfn << PAGE_SHIFT;
+       sync_cmd[2] = seq;
+
+       TOPAZ_BEGIN_CCB(dev_priv);
+       TOPAZ_OUT_CCB(dev_priv, sync_cmd[0]);
+       TOPAZ_OUT_CCB(dev_priv, sync_cmd[1]);
+       TOPAZ_OUT_CCB(dev_priv, sync_cmd[2]);
+       TOPAZ_END_CCB(dev_priv, 1);
+
+       v = kmap(p);
+       while (count && *v != sync_seq) {
+               DRM_UDELAY(100);
+               --count;
+       }
+       if ((count == 0) && (*v != sync_seq)) {
+               DRM_ERROR("TOPAZ: wait sycn timeout (0x%08x),"
+                         "actual 0x%08x\n",
+                         sync_seq, *v);
+       }
+       PSB_DEBUG_GENERAL("TOPAZ: SYNC done, seq=0x%08x\n", *v);
+       kunmap(p);
+
+       return 0;
+}
+
+static int topaz_test_null(struct drm_device *dev, uint32_t seq)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       struct topaz_cmd_header null_cmd;
+       uint32_t clr_flag;
+
+       /* XXX: here we finished firmware setup....
+        * using a NULL command to verify the
+        * correctness of firmware
+        */
+
+       null_cmd.id = MTX_CMDID_NULL;
+       null_cmd.size = 1;
+       null_cmd.seq = seq;
+
+       TOPAZ_BEGIN_CCB(dev_priv);
+       TOPAZ_OUT_CCB(dev_priv, *((uint32_t *)&null_cmd));
+       TOPAZ_END_CCB(dev_priv, 1);
+
+       DRM_UDELAY(1000); /* wait to finish */
+
+       PSB_DEBUG_GENERAL("Topaz: Sent NULL with sequence=0x%08x,"
+                         " got sequence=0x%08x (WB_seq=0x%08x,WB_roff=%d)\n",
+                         seq, CCB_CTRL_SEQ(dev_priv), WB_CCB_CTRL_SEQ(dev_priv),
+                         WB_CCB_CTRL_RINDEX(dev_priv));
+
+       PSB_DEBUG_GENERAL("Topaz: after NULL test, query IRQ and clear it\n");
+
+       clr_flag = lnc_topaz_queryirq(dev);
+       lnc_topaz_clearirq(dev, clr_flag);
+
+       return 0;
+}
+
+
+/*
+ * this function will test whether the mmu is correct:
+ * it get a drm_buffer_object and use CMD_SYNC to write
+ * certain value into this buffer.
+ */
+static void topaz_mmu_test(struct drm_device *dev, uint32_t sync_value)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+       unsigned long real_pfn;
+       int ret;
+
+       /* topaz_mmu_flush(dev); */
+       topaz_test_sync(dev, 0x55, sync_value);
+
+       ret = psb_mmu_virtual_to_pfn(psb_mmu_get_default_pd(dev_priv->mmu),
+                                    topaz_priv->topaz_sync_offset, &real_pfn);
+       if (ret != 0) {
+               PSB_DEBUG_GENERAL("psb_mmu_virtual_to_pfn failed,exit\n");
+               return;
+       }
+       PSB_DEBUG_GENERAL("TOPAZ: issued SYNC command, "
+                         "BO offset=0x%08x (pfn=%lu), synch value=0x%08x\n",
+                         topaz_priv->topaz_sync_offset, real_pfn, sync_value);
+}
+
+void topaz_save_default_regs(struct drm_psb_private *dev_priv, uint32_t *data)
+{
+       int n;
+       int count;
+
+       count = sizeof(topaz_default_regs) / (sizeof(unsigned long) * 3);
+       for (n = 0; n < count; n++, ++data)
+               MM_READ32(topaz_default_regs[n][0],
+                         topaz_default_regs[n][1],
+                         data);
+
+}
+
+void topaz_restore_default_regs(struct drm_psb_private *dev_priv,
+                               uint32_t *data)
+{
+       int n;
+       int count;
+
+       count = sizeof(topaz_default_regs) / (sizeof(unsigned long) * 3);
+       for (n = 0; n < count; n++, ++data)
+               MM_WRITE32(topaz_default_regs[n][0],
+                          topaz_default_regs[n][1],
+                          *data);
+
+}
+
+#endif
+
+int lnc_topaz_restore_mtx_state(struct drm_device *dev)
+{
+       struct drm_psb_private *dev_priv =
+               (struct drm_psb_private *)dev->dev_private;
+       uint32_t reg_val;
+       uint32_t *mtx_reg_state;
+       int i;
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+
+       if (!topaz_priv->topaz_mtx_saved)
+               return -1;
+
+       if (topaz_priv->topaz_mtx_data_mem == NULL) {
+               PSB_DEBUG_GENERAL("TOPAZ: try to restore context without "
+                                 "space allocated, return directly without restore\n");
+               return -1;
+       }
+
+       /* turn on mtx clocks */
+       MTX_READ32(TOPAZ_CR_TOPAZ_MAN_CLK_GATE, &reg_val);
+       MTX_WRITE32(TOPAZ_CR_TOPAZ_MAN_CLK_GATE,
+                   reg_val & (~MASK_TOPAZ_CR_TOPAZ_MTX_MAN_CLK_GATE));
+
+       /* reset mtx */
+       /* FIXME: should use core_write??? */
+       MTX_WRITE32(MTX_CORE_CR_MTX_SOFT_RESET_OFFSET,
+                   MTX_CORE_CR_MTX_SOFT_RESET_MTX_RESET_MASK);
+       DRM_UDELAY(6000);
+
+       topaz_mmu_hwsetup(dev_priv);
+       /* upload code, restore mtx data */
+       mtx_dma_write(dev);
+
+       mtx_reg_state = topaz_priv->topaz_mtx_reg_state;
+       /* restore register */
+       /* FIXME: conside to put read/write into one function */
+       /* Saves 8 Registers of D0 Bank  */
+       /* DoRe0, D0Ar6, D0Ar4, D0Ar2, D0FrT, D0.5, D0.6 and D0.7 */
+       for (i = 0; i < 8; i++) {
+               topaz_write_core_reg(dev_priv, 0x1 | (i << 4),
+                                    *mtx_reg_state);
+               mtx_reg_state++;
+       }
+       /* Saves 8 Registers of D1 Bank  */
+       /* D1Re0, D1Ar5, D1Ar3, D1Ar1, D1RtP, D1.5, D1.6 and D1.7 */
+       for (i = 0; i < 8; i++) {
+               topaz_write_core_reg(dev_priv, 0x2 | (i << 4),
+                                    *mtx_reg_state);
+               mtx_reg_state++;
+       }
+       /* Saves 4 Registers of A0 Bank  */
+       /* A0StP, A0FrP, A0.2 and A0.3 */
+       for (i = 0; i < 4; i++) {
+               topaz_write_core_reg(dev_priv, 0x3 | (i << 4),
+                                    *mtx_reg_state);
+               mtx_reg_state++;
+       }
+       /* Saves 4 Registers of A1 Bank  */
+       /* A1GbP, A1LbP, A1.2 and A1.3 */
+       for (i = 0; i < 4; i++) {
+               topaz_write_core_reg(dev_priv, 0x4 | (i << 4),
+                                    *mtx_reg_state);
+               mtx_reg_state++;
+       }
+       /* Saves PC and PCX  */
+       for (i = 0; i < 2; i++) {
+               topaz_write_core_reg(dev_priv, 0x5 | (i << 4),
+                                    *mtx_reg_state);
+               mtx_reg_state++;
+       }
+       /* Saves 8 Control Registers */
+       /* TXSTAT, TXMASK, TXSTATI, TXMASKI, TXPOLL, TXGPIOI, TXPOLLI,
+        * TXGPIOO */
+       for (i = 0; i < 8; i++) {
+               topaz_write_core_reg(dev_priv, 0x7 | (i << 4),
+                                    *mtx_reg_state);
+               mtx_reg_state++;
+       }
+
+       /* turn on MTX */
+       MTX_WRITE32(MTX_CORE_CR_MTX_ENABLE_OFFSET,
+                   MTX_CORE_CR_MTX_ENABLE_MTX_ENABLE_MASK);
+
+       topaz_priv->topaz_mtx_saved = 0;
+
+       return 0;
+}
+
+int lnc_topaz_save_mtx_state(struct drm_device *dev)
+{
+       struct drm_psb_private *dev_priv =
+               (struct drm_psb_private *)dev->dev_private;
+       uint32_t *mtx_reg_state;
+       int i;
+       struct topaz_codec_fw *cur_codec_fw;
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+
+       /* FIXME: make sure the topaz_mtx_data_mem is allocated */
+       if (topaz_priv->topaz_mtx_data_mem == NULL) {
+               PSB_DEBUG_GENERAL("TOPAZ: try to save context without space "
+                                 "allocated, return directly without save\n");
+               return -1;
+       }
+       if (topaz_priv->topaz_fw_loaded == 0) {
+               PSB_DEBUG_GENERAL("TOPAZ: try to save context without firmware "
+                                 "uploaded\n");
+               return -1;
+       }
+
+       topaz_wait_for_register(dev_priv,
+                               MTX_START + MTX_CORE_CR_MTX_TXRPT_OFFSET,
+                               TXRPT_WAITONKICK_VALUE,
+                               0xffffffff);
+
+       /* stop mtx */
+       MTX_WRITE32(MTX_CORE_CR_MTX_ENABLE_OFFSET,
+                   MTX_CORE_CR_MTX_ENABLE_MTX_TOFF_MASK);
+
+       mtx_reg_state = topaz_priv->topaz_mtx_reg_state;
+
+       /* FIXME: conside to put read/write into one function */
+       /* Saves 8 Registers of D0 Bank  */
+       /* DoRe0, D0Ar6, D0Ar4, D0Ar2, D0FrT, D0.5, D0.6 and D0.7 */
+       for (i = 0; i < 8; i++) {
+               topaz_read_core_reg(dev_priv, 0x1 | (i << 4),
+                                   mtx_reg_state);
+               mtx_reg_state++;
+       }
+       /* Saves 8 Registers of D1 Bank  */
+       /* D1Re0, D1Ar5, D1Ar3, D1Ar1, D1RtP, D1.5, D1.6 and D1.7 */
+       for (i = 0; i < 8; i++) {
+               topaz_read_core_reg(dev_priv, 0x2 | (i << 4),
+                                   mtx_reg_state);
+               mtx_reg_state++;
+       }
+       /* Saves 4 Registers of A0 Bank  */
+       /* A0StP, A0FrP, A0.2 and A0.3 */
+       for (i = 0; i < 4; i++) {
+               topaz_read_core_reg(dev_priv, 0x3 | (i << 4),
+                                   mtx_reg_state);
+               mtx_reg_state++;
+       }
+       /* Saves 4 Registers of A1 Bank  */
+       /* A1GbP, A1LbP, A1.2 and A1.3 */
+       for (i = 0; i < 4; i++) {
+               topaz_read_core_reg(dev_priv, 0x4 | (i << 4),
+                                   mtx_reg_state);
+               mtx_reg_state++;
+       }
+       /* Saves PC and PCX  */
+       for (i = 0; i < 2; i++) {
+               topaz_read_core_reg(dev_priv, 0x5 | (i << 4),
+                                   mtx_reg_state);
+               mtx_reg_state++;
+       }
+       /* Saves 8 Control Registers */
+       /* TXSTAT, TXMASK, TXSTATI, TXMASKI, TXPOLL, TXGPIOI, TXPOLLI,
+        * TXGPIOO */
+       for (i = 0; i < 8; i++) {
+               topaz_read_core_reg(dev_priv, 0x7 | (i << 4),
+                                   mtx_reg_state);
+               mtx_reg_state++;
+       }
+
+       /* save mtx data memory */
+       cur_codec_fw = &topaz_priv->topaz_fw[topaz_priv->topaz_cur_codec];
+
+       mtx_dma_read(dev, cur_codec_fw->data_location + 0x80900000 - 0x82880000,
+                    topaz_priv->cur_mtx_data_size);
+
+       /* turn off mtx clocks */
+       MTX_WRITE32(TOPAZ_CR_TOPAZ_MAN_CLK_GATE,
+                   MASK_TOPAZ_CR_TOPAZ_MTX_MAN_CLK_GATE);
+
+       topaz_priv->topaz_mtx_saved = 1;
+
+       return 0;
+}
+
+void mtx_dma_read(struct drm_device *dev, uint32_t source_addr, uint32_t size)
+{
+       struct drm_psb_private *dev_priv =
+               (struct drm_psb_private *)dev->dev_private;
+       struct ttm_buffer_object *target;
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+
+       /* setup mtx DMAC registers to do transfer */
+       MTX_WRITE32(MTX_CR_MTX_SYSC_CDMAA, source_addr);
+       MTX_WRITE32(MTX_CR_MTX_SYSC_CDMAC,
+                   F_ENCODE(2, MTX_BURSTSIZE) |
+                   F_ENCODE(1, MTX_RNW) |
+                   F_ENCODE(1, MTX_ENABLE) |
+                   F_ENCODE(size, MTX_LENGTH));
+
+       /* give the DMAC access to the host memory via BIF */
+       TOPAZ_WRITE32(TOPAZ_CR_IMG_TOPAZ_DMAC_MODE, 1);
+
+       target = topaz_priv->topaz_mtx_data_mem;
+       /* transfert the data */
+       /* FIXME: size is meaured by bytes? */
+       topaz_dma_transfer(dev_priv, 0, target->offset, 0,
+                          MTX_CR_MTX_SYSC_CDMAT,
+                          size, 0, 1);
+
+       /* wait for it transfer */
+       topaz_wait_for_register(dev_priv, IMG_SOC_DMAC_IRQ_STAT(0) + DMAC_START,
+                               F_ENCODE(1, IMG_SOC_TRANSFER_FIN),
+                               F_ENCODE(1, IMG_SOC_TRANSFER_FIN));
+       /* clear interrupt */
+       DMAC_WRITE32(IMG_SOC_DMAC_IRQ_STAT(0), 0);
+       /* give access back to topaz core */
+       TOPAZ_WRITE32(TOPAZ_CR_IMG_TOPAZ_DMAC_MODE, 0);
+}
+
+void dmac_transfer(struct drm_device *dev, uint32_t channel, uint32_t dst_addr,
+                  uint32_t soc_addr, uint32_t bytes_num,
+                  int increment, int rnw)
+{
+       struct drm_psb_private *dev_priv =
+               (struct drm_psb_private *)dev->dev_private;
+       uint32_t count_reg;
+       uint32_t irq_state;
+
+       /* check no transfer is in progress */
+       DMAC_READ32(IMG_SOC_DMAC_COUNT(channel), &count_reg);
+       if (0 != (count_reg & (MASK_IMG_SOC_EN | MASK_IMG_SOC_LIST_EN))) {
+               DRM_ERROR("TOPAZ: there's transfer in progress when wanna "
+                         "save mtx data\n");
+               /* FIXME: how to handle this error */
+               return;
+       }
+
+       /* no hold off period */
+       DMAC_WRITE32(IMG_SOC_DMAC_PER_HOLD(channel), 0);
+       /* cleare irq state */
+       DMAC_WRITE32(IMG_SOC_DMAC_IRQ_STAT(channel), 0);
+       DMAC_READ32(IMG_SOC_DMAC_IRQ_STAT(channel), &irq_state);
+       if (0 != irq_state) {
+               DRM_ERROR("TOPAZ: there's irq cann't clear\n");
+               return;
+       }
+
+       DMAC_WRITE32(IMG_SOC_DMAC_SETUP(channel), dst_addr);
+       count_reg = DMAC_VALUE_COUNT(DMAC_BSWAP_NO_SWAP,
+                                    DMAC_PWIDTH_32_BIT, rnw,
+                                    DMAC_PWIDTH_32_BIT, bytes_num);
+       /* generate an interrupt at end of transfer */
+       count_reg |= MASK_IMG_SOC_TRANSFER_IEN;
+       count_reg |= F_ENCODE(rnw, IMG_SOC_DIR);
+       DMAC_WRITE32(IMG_SOC_DMAC_COUNT(channel), count_reg);
+
+       DMAC_WRITE32(IMG_SOC_DMAC_PERIPH(channel),
+                    DMAC_VALUE_PERIPH_PARAM(DMAC_ACC_DEL_0, increment,
+                                            DMAC_BURST_2));
+       DMAC_WRITE32(IMG_SOC_DMAC_PERIPHERAL_ADDR(channel), soc_addr);
+
+       /* Finally, rewrite the count register with the enable
+        * bit set to kick off the transfer */
+       DMAC_WRITE32(IMG_SOC_DMAC_COUNT(channel),
+                    count_reg | MASK_IMG_SOC_EN);
+}
+
+void mtx_dma_write(struct drm_device *dev)
+{
+       struct topaz_codec_fw *cur_codec_fw;
+       struct drm_psb_private *dev_priv =
+               (struct drm_psb_private *)dev->dev_private;
+       struct topaz_private *topaz_priv = dev_priv->topaz_private;
+
+       cur_codec_fw = &topaz_priv->topaz_fw[topaz_priv->topaz_cur_codec];
+
+       /* upload code */
+       /* setup mtx DMAC registers to recieve transfer */
+       MTX_WRITE32(MTX_CR_MTX_SYSC_CDMAA, 0x80900000);
+       MTX_WRITE32(MTX_CR_MTX_SYSC_CDMAC,
+                   F_ENCODE(2, MTX_BURSTSIZE) |
+                   F_ENCODE(0, MTX_RNW) |
+                   F_ENCODE(1, MTX_ENABLE) |
+                   F_ENCODE(cur_codec_fw->text_size / 4, MTX_LENGTH));
+
+       /* give DMAC access to host memory */
+       TOPAZ_WRITE32(TOPAZ_CR_IMG_TOPAZ_DMAC_MODE, 1);
+
+       /* transfer code */
+       topaz_dma_transfer(dev_priv, 0, cur_codec_fw->text->offset, 0,
+                          MTX_CR_MTX_SYSC_CDMAT, cur_codec_fw->text_size / 4,
+                          0, 0);
+       /* wait finished */
+       topaz_wait_for_register(dev_priv, IMG_SOC_DMAC_IRQ_STAT(0) + DMAC_START,
+                               F_ENCODE(1, IMG_SOC_TRANSFER_FIN),
+                               F_ENCODE(1, IMG_SOC_TRANSFER_FIN));
+       /* clear interrupt */
+       DMAC_WRITE32(IMG_SOC_DMAC_IRQ_STAT(0), 0);
+
+       /* setup mtx start recieving data */
+       MTX_WRITE32(MTX_CR_MTX_SYSC_CDMAA, 0x80900000 +
+                   (cur_codec_fw->data_location) - 0x82880000);
+
+       MTX_WRITE32(MTX_CR_MTX_SYSC_CDMAC,
+                   F_ENCODE(2, MTX_BURSTSIZE) |
+                   F_ENCODE(0, MTX_RNW) |
+                   F_ENCODE(1, MTX_ENABLE) |
+                   F_ENCODE(topaz_priv->cur_mtx_data_size, MTX_LENGTH));
+
+       /* give DMAC access to host memory */
+       TOPAZ_WRITE32(TOPAZ_CR_IMG_TOPAZ_DMAC_MODE, 1);
+
+       /* transfer data */
+       topaz_dma_transfer(dev_priv, 0, topaz_priv->topaz_mtx_data_mem->offset,
+                          0, MTX_CR_MTX_SYSC_CDMAT,
+                          topaz_priv->cur_mtx_data_size,
+                          0, 0);
+       /* wait finished */
+       topaz_wait_for_register(dev_priv, IMG_SOC_DMAC_IRQ_STAT(0) + DMAC_START,
+                               F_ENCODE(1, IMG_SOC_TRANSFER_FIN),
+                               F_ENCODE(1, IMG_SOC_TRANSFER_FIN));
+       /* clear interrupt */
+       DMAC_WRITE32(IMG_SOC_DMAC_IRQ_STAT(0), 0);
+
+       /* give access back to Topaz Core */
+       TOPAZ_WRITE32(TOPAZ_CR_IMG_TOPAZ_DMAC_MODE, 0);
+}
+
index 9d8db4f..76cbb63 100644 (file)
@@ -33,6 +33,7 @@
 #include "pnw_topaz.h"
 #include "psb_powermgmt.h"
 #include "pnw_topaz_hw_reg.h"
+#include "lnc_topaz.h"
 
 #include <linux/io.h>
 #include <linux/delay.h>
@@ -52,8 +53,8 @@ static int pnw_topaz_dequeue_send(struct drm_device *dev);
 static int pnw_topaz_save_command(struct drm_device *dev, void *cmd,
                                  unsigned long cmd_size, uint32_t sequence);
 
-static void pnw_topaz_mtx_kick(struct drm_psb_private *dev_priv,
-                       uint32_t core_id, uint32_t kick_count);
+static void topaz_mtx_kick(struct drm_psb_private *dev_priv, uint32_t core_id,
+                          uint32_t kick_count);
 
 IMG_BOOL pnw_topaz_interrupt(IMG_VOID *pvData)
 {
@@ -310,7 +311,7 @@ int pnw_wait_on_sync(struct drm_psb_private *dev_priv,
        }
 
        while (count && (sync_seq != *sync_p)) {
-               PSB_UDELAY(100);
+               PSB_UDELAY(100);/* experimental value */
                --count;
        }
        if ((count == 0) && (sync_seq != *sync_p)) {
@@ -322,7 +323,7 @@ int pnw_wait_on_sync(struct drm_psb_private *dev_priv,
        return 0;
 }
 
-static int pnw_topaz_deliver_command(struct drm_device *dev,
+int pnw_topaz_deliver_command(struct drm_device *dev,
                              struct ttm_buffer_object *cmd_buffer,
                              unsigned long cmd_offset, unsigned long cmd_size,
                              void **topaz_cmd, uint32_t sequence,
@@ -416,11 +417,12 @@ int pnw_topaz_kick_null_cmd(struct drm_psb_private *dev_priv,
        PSB_DEBUG_GENERAL("TOPAZ: Write back value for NULL CMD is %d\n",
                          sync_seq);
 
-       pnw_topaz_mtx_kick(dev_priv, 0, 1);
+       topaz_mtx_kick(dev_priv, 0, 1);
 
        return 0;
 }
 
+
 static void pnw_topaz_save_bias_table(struct pnw_topaz_private *topaz_priv,
        const void *cmd, int byte_size, int core)
 {
@@ -452,7 +454,8 @@ static void pnw_topaz_save_bias_table(struct pnw_topaz_private *topaz_priv,
        return;
 }
 
-static int
+
+int
 pnw_topaz_send(struct drm_device *dev, void *cmd,
               unsigned long cmd_size, uint32_t sync_seq)
 {
@@ -598,7 +601,7 @@ pnw_topaz_send(struct drm_device *dev, void *cmd,
 
                        cur_free_space -= 4;
                        topaz_priv->topaz_cmd_count %= MAX_TOPAZ_CMD_COUNT;
-                       pnw_topaz_mtx_kick(dev_priv, 0, 1);
+                       topaz_mtx_kick(dev_priv, 0, 1);
 #ifdef SYNC_FOR_EACH_COMMAND
                        pnw_wait_on_sync(dev_priv, cur_cmd_header->seq,
                                         topaz_priv->topaz_mtx_wb +
@@ -662,7 +665,7 @@ out:
        return ret;
 }
 
-static int pnw_topaz_dequeue_send(struct drm_device *dev)
+int pnw_topaz_dequeue_send(struct drm_device *dev)
 {
        struct drm_psb_private *dev_priv = dev->dev_private;
        struct pnw_topaz_cmd_queue *topaz_cmd = NULL;
@@ -695,7 +698,7 @@ static int pnw_topaz_dequeue_send(struct drm_device *dev)
        return ret;
 }
 
-static void pnw_topaz_mtx_kick(struct drm_psb_private *dev_priv, uint32_t core_id, uint32_t kick_count)
+void topaz_mtx_kick(struct drm_psb_private *dev_priv, uint32_t core_id, uint32_t kick_count)
 {
        PSB_DEBUG_GENERAL("TOPAZ: kick core(%d) mtx count(%d).\n",
                          core_id, kick_count);
@@ -800,8 +803,13 @@ void pnw_topaz_handle_timeout(struct ttm_fence_device *fdev)
 {
        struct drm_psb_private *dev_priv =
                container_of(fdev, struct drm_psb_private, fdev);
+       struct drm_device *dev =
+               container_of((void *)dev_priv, struct drm_device, dev_private);
        struct pnw_topaz_private *topaz_priv = dev_priv->topaz_private;
 
+       if (IS_MRST(dev))
+               return  lnc_topaz_handle_timeout(fdev);
+
        DRM_ERROR("TOPAZ: current codec is %s\n",
                        codec_to_string(topaz_priv->topaz_cur_codec));
        pnw_topaz_flush_cmd_queue(topaz_priv);
@@ -819,7 +827,7 @@ void pnw_map_topaz_reg(struct drm_device *dev)
 
        resource_start = pci_resource_start(dev->pdev, PSB_MMIO_RESOURCE);
 
-       if (!dev_priv->topaz_disabled) {
+       if (IS_MDFLD(dev) && !dev_priv->topaz_disabled) {
                dev_priv->topaz_reg = ioremap(
                                              resource_start + PNW_TOPAZ_OFFSET,
                                              PNW_TOPAZ_SIZE);
@@ -835,9 +843,11 @@ void pnw_unmap_topaz_reg(struct drm_device *dev)
        struct drm_psb_private *dev_priv =
                (struct drm_psb_private *)dev->dev_private;
 
-       if (dev_priv->topaz_reg) {
-               iounmap(dev_priv->topaz_reg);
-               dev_priv->topaz_reg = NULL;
+       if (IS_MDFLD(dev)) {
+               if (dev_priv->topaz_reg) {
+                       iounmap(dev_priv->topaz_reg);
+                       dev_priv->topaz_reg = NULL;
+               }
        }
 
        return;
index fdf0640..915c4a8 100644 (file)
 #define PNW_IS_JPEG_ENC(codec) \
        (codec == IMG_CODEC_JPEG)
 
+#define PNW_IS_MPEG4_ENC(codec) \
+       (codec == IMG_CODEC_MPEG4_VBR || \
+        codec == IMG_CODEC_MPEG4_CBR || \
+        codec == IMG_CODEC_MPEG4_NO_RC)
+
+#define PNW_IS_H263_ENC(codec) \
+       (codec == IMG_CODEC_H263_VBR || \
+        codec == IMG_CODEC_H263_CBR || \
+        codec == IMG_CODEC_H263_NO_RC)
+
 extern int drm_topaz_pmpolicy;
 
 /* XXX: it's a copy of msvdx cmd queue. should have some change? */
@@ -81,7 +91,8 @@ struct pnw_topaz_private {
        struct sysfs_dirent *sysfs_pmstate;
        int frame_skip;
 
-       void *topaz_mtx_reg_state[MAX_TOPAZ_CORES] ;
+       /*Save content of MTX register, whole RAM and BIAS table*/
+       void *topaz_mtx_reg_state[MAX_TOPAZ_CORES];
        struct ttm_buffer_object *topaz_mtx_data_mem[MAX_TOPAZ_CORES];
        uint32_t topaz_cur_codec;
        uint32_t cur_mtx_data_size[MAX_TOPAZ_CORES];
index f35c522..5453437 100644 (file)
 #ifndef _PNW_TOPAZ_HW_REG_H_
 #define _PNW_TOPAZ_HW_REG_H_
 
+#ifdef _LNC_TOPAZ_HW_REG_H_
+#error "lnc_topaz_hw_reg.h shouldn't be included"
+#endif
+
 #include "psb_drv.h"
 #include "img_types.h"
 #include "pnw_topaz.h"
index 802eba8..12ee92b 100644 (file)
@@ -86,6 +86,8 @@ static int  mtx_dma_read(struct drm_device *dev, uint32_t core,
                         uint32_t source_addr, uint32_t size);
 static int  mtx_dma_write(struct drm_device *dev,
                          uint32_t core);
+static void pnw_topaz_restore_bias_table(struct drm_psb_private *dev_priv,
+               int core);
 
 /* Reset the encode system buffer registers.*/
 static int pnw_topazsc_reset_ESB(struct drm_psb_private *dev_priv, int core_id)
@@ -129,7 +131,7 @@ static int pnw_topazsc_reset_ESB(struct drm_psb_private *dev_priv, int core_id)
        return 0;
 }
 
-static int pnw_error_dump_reg(struct drm_psb_private *dev_priv, int core_id)
+int pnw_error_dump_reg(struct drm_psb_private *dev_priv, int core_id)
 {
        uint32_t reg_val;
        int i;
@@ -257,8 +259,13 @@ int pnw_topaz_init(struct drm_device *dev)
        if (device_create_file(&dev->pdev->dev,
                               &dev_attr_topaz_pmstate))
                DRM_ERROR("TOPAZ: could not create sysfs file\n");
-       topaz_priv->sysfs_pmstate = sysfs_get_dirent(dev->pdev->dev.kobj.sd,
-                                               NULL, "topaz_pmstate");
+       topaz_priv->sysfs_pmstate = sysfs_get_dirent(
+                                           dev->pdev->dev.kobj.sd,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
+                                           NULL,
+#endif
+                                           "topaz_pmstate");
+
 
        topaz_priv = dev_priv->topaz_private;
 
@@ -906,7 +913,7 @@ int pnw_topaz_setup_fw(struct drm_device *dev, enum drm_pnw_topaz_codec codec)
 }
 
 #if UPLOAD_FW_BY_DMA
-static int topaz_upload_fw(struct drm_device *dev, enum drm_pnw_topaz_codec codec, uint32_t core_id)
+int topaz_upload_fw(struct drm_device *dev, enum drm_pnw_topaz_codec codec, uint32_t core_id)
 {
        struct drm_psb_private *dev_priv = dev->dev_private;
        const struct pnw_topaz_codec_fw *cur_codec_fw;
@@ -995,8 +1002,6 @@ static int topaz_upload_fw(struct drm_device *dev, enum drm_pnw_topaz_codec code
                     & ~(MTX_DMA_BURSTSIZE_BYTES - 1)) / 4;
 
        data_location = cur_codec_fw->data_location;
-       data_location = data_location & (~(MTX_DMA_BURSTSIZE_BYTES - 1));
-
        PSB_DEBUG_GENERAL("TOPAZ: data_size round up to %d\n"
                          "data_location round up to 0x%08x\n",
                          data_size, data_location);
@@ -1035,7 +1040,7 @@ static int topaz_upload_fw(struct drm_device *dev, enum drm_pnw_topaz_codec code
        /* # return access to topaz core(deserted) */
        /*TOPAZ_WRITE32(TOPAZ_CR_IMG_TOPAZ_DMAC_MODE, 0, core_id);*/
 
-       /* record this codec's mtx data size for
+       /* record this codec's mtx data size(+stack) for
         * context save & restore */
        /* FIXME: since non-root sighting fixed by pre allocated,
         * only need to correct the buffer size
@@ -1196,7 +1201,7 @@ int topaz_upload_fw(struct drm_device *dev, enum drm_pnw_topaz_codec codec,
 #endif /* UPLOAD_FW_BY_DMA */
 
 /* is_increment is always 0, so use it as core_id for workaround*/
-static int topaz_dma_transfer(struct drm_psb_private *dev_priv, uint32_t channel,
+int topaz_dma_transfer(struct drm_psb_private *dev_priv, uint32_t channel,
                       uint32_t src_phy_addr, uint32_t offset,
                       uint32_t soc_addr, uint32_t byte_num,
                       uint32_t is_increment, uint32_t is_write)
@@ -1325,7 +1330,7 @@ void topaz_read_core_reg(struct drm_psb_private *dev_priv,
        release_mtx_control_from_dash(dev_priv, core);
 }
 
-static void get_mtx_control_from_dash(struct drm_psb_private *dev_priv, uint32_t core)
+void get_mtx_control_from_dash(struct drm_psb_private *dev_priv, uint32_t core)
 {
        int debug_reg_slave_val;
        struct pnw_topaz_private *topaz_priv = dev_priv->topaz_private;
@@ -1350,7 +1355,7 @@ static void get_mtx_control_from_dash(struct drm_psb_private *dev_priv, uint32_t
                     &topaz_priv->topaz_dash_access_ctrl, core);
 }
 
-static void release_mtx_control_from_dash(struct drm_psb_private *dev_priv,
+void release_mtx_control_from_dash(struct drm_psb_private *dev_priv,
                                   uint32_t core)
 {
        struct pnw_topaz_private *topaz_priv = dev_priv->topaz_private;
@@ -1364,7 +1369,7 @@ static void release_mtx_control_from_dash(struct drm_psb_private *dev_priv,
                      F_ENCODE(1, TOPAZ_CR_MTX_DBG_IS_SLAVE), core);
 }
 
-static void pnw_topaz_mmu_hwsetup(struct drm_psb_private *dev_priv, uint32_t core_id)
+void pnw_topaz_mmu_hwsetup(struct drm_psb_private *dev_priv, uint32_t core_id)
 {
        uint32_t pd_addr = psb_get_default_pd_addr(dev_priv->mmu);
 
@@ -1858,7 +1863,7 @@ int pnw_topaz_save_mtx_state(struct drm_device *dev)
        return 0;
 }
 
-static int mtx_dma_read(struct drm_device *dev, uint32_t core,
+int mtx_dma_read(struct drm_device *dev, uint32_t core,
                 uint32_t source_addr, uint32_t size)
 {
        struct drm_psb_private *dev_priv =
@@ -1902,7 +1907,7 @@ static int mtx_dma_read(struct drm_device *dev, uint32_t core,
        return 0;
 }
 
-static int mtx_dma_write(struct drm_device *dev, uint32_t core_id)
+int mtx_dma_write(struct drm_device *dev, uint32_t core_id)
 {
        struct drm_psb_private *dev_priv =
                (struct drm_psb_private *)dev->dev_private;
index 02755f4..c66bed4 100644 (file)
@@ -30,6 +30,7 @@
 struct drm_psb_ttm_backend {
        struct ttm_backend base;
        struct page **pages;
+       dma_addr_t *dma_addrs;
        unsigned int desired_tile_stride;
        unsigned int hw_tile_stride;
        int mem_type;
@@ -77,6 +78,14 @@ static int psb_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
                man->available_caching = TTM_PL_FLAG_UNCACHED;
                man->default_caching = TTM_PL_FLAG_UNCACHED;
                break;
+       case TTM_PL_RAR:        /* Unmappable RAR memory */
+               man->func = &ttm_bo_manager_func;
+               man->flags = TTM_MEMTYPE_FLAG_MAPPABLE |
+                            TTM_MEMTYPE_FLAG_FIXED;
+               man->available_caching = TTM_PL_FLAG_UNCACHED;
+               man->default_caching = TTM_PL_FLAG_UNCACHED;
+               man->gpu_offset = PSB_MEM_RAR_START;
+               break;
        case TTM_PL_TT: /* Mappable GATT memory */
                man->func = &ttm_bo_manager_func;
 #ifdef PSB_WORKING_HOST_MMU_ACCESS
@@ -90,6 +99,15 @@ static int psb_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
                man->default_caching = TTM_PL_FLAG_WC;
                man->gpu_offset = pg->mmu_gatt_start + pg->ci_start + pg->ci_stolen_size;
                break;
+       case DRM_PSB_MEM_MMU_TILING:
+               man->func = &ttm_bo_manager_func;
+               man->flags = TTM_MEMTYPE_FLAG_MAPPABLE |
+                            TTM_MEMTYPE_FLAG_CMA;
+               man->gpu_offset = PSB_MEM_MMU_TILING_START;
+               man->available_caching = TTM_PL_FLAG_CACHED |
+                                        TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC;
+               man->default_caching = TTM_PL_FLAG_WC;
+               break;
        default:
                DRM_ERROR("Unsupported memory type %u\n", (unsigned) type);
                return -EINVAL;
@@ -211,17 +229,18 @@ static int psb_move(struct ttm_buffer_object *bo,
        return 0;
 }
 
-/* REVISIT: is there a need to use the dma_addrs or other parameters? */
 static int drm_psb_tbe_populate(struct ttm_backend *backend,
                                unsigned long num_pages,
                                struct page **pages,
                                struct page *dummy_read_page,
                                dma_addr_t *dma_addrs)
 {
+       int i;
        struct drm_psb_ttm_backend *psb_be =
                container_of(backend, struct drm_psb_ttm_backend, base);
 
        psb_be->pages = pages;
+       psb_be->dma_addrs = dma_addrs; /* Not concretely implemented by TTM yet*/
        return 0;
 }
 
@@ -267,12 +286,11 @@ static int drm_psb_tbe_bind(struct ttm_backend *backend,
        int ret = 0;
 
        psb_be->mem_type = bo_mem->mem_type;
-       WARN_ON_ONCE(psb_be->num_pages &&
-                    psb_be->num_pages != bo_mem->num_pages);
        psb_be->num_pages = bo_mem->num_pages;
        psb_be->desired_tile_stride = 0;
        psb_be->hw_tile_stride = 0;
-       psb_be->offset = (bo_mem->start << PAGE_SHIFT) + man->gpu_offset;
+       psb_be->offset = (bo_mem->start << PAGE_SHIFT) +
+                        man->gpu_offset;
 
        type =
                (bo_mem->
@@ -309,7 +327,7 @@ static void drm_psb_tbe_clear(struct ttm_backend *backend)
                container_of(backend, struct drm_psb_ttm_backend, base);
 
        psb_be->pages = NULL;
-
+       psb_be->dma_addrs = NULL;
        return;
 }
 
index 258b51a..9119f02 100644 (file)
 #include "psb_drv.h"
 #include "psb_msvdx.h"
 #include "pnw_topaz.h"
+#include "lnc_topaz.h"
+
 
 static void psb_fence_poll(struct ttm_fence_device *fdev,
                           uint32_t fence_class, uint32_t waiting_types)
 {
        struct drm_psb_private *dev_priv =
                container_of(fdev, struct drm_psb_private, fdev);
+       struct drm_device *dev = dev_priv->dev;
        uint32_t sequence = 0;
-       struct msvdx_private *msvdx_priv;
+       struct msvdx_private *msvdx_priv = dev_priv->msvdx_private;
 
 
        if (unlikely(!dev_priv))
                return;
 
-       msvdx_priv = dev_priv->msvdx_private;
-
        if (waiting_types == 0)
                return;
 
@@ -46,8 +47,12 @@ static void psb_fence_poll(struct ttm_fence_device *fdev,
                sequence = msvdx_priv->msvdx_current_sequence;
                break;
        case LNC_ENGINE_ENCODE:
-               sequence = *((uint32_t *)
-                       ((struct pnw_topaz_private *)dev_priv->topaz_private)->topaz_sync_addr + 1);
+               if (IS_MDFLD(dev))
+                       sequence = *((uint32_t *)
+                                    ((struct pnw_topaz_private *)dev_priv->topaz_private)->topaz_sync_addr + 1);
+               else
+                       sequence = *((uint32_t *)
+                                    ((struct topaz_private *)dev_priv->topaz_private)->topaz_sync_addr);
                break;
        default:
                break;
@@ -93,6 +98,8 @@ int psb_fence_emit_sequence(struct ttm_fence_device *fdev,
        case PSB_ENGINE_VIDEO:
                spin_lock(&dev_priv->sequence_lock);
                seq = dev_priv->sequence[fence_class]++;
+               /* cmds in one batch use different fence value */
+               seq <<= 4;
                spin_unlock(&dev_priv->sequence_lock);
                break;
        case LNC_ENGINE_ENCODE:
index 4cd8fa5..3711468 100644 (file)
@@ -167,7 +167,9 @@ static void psb_mmu_flush_pd_locked(struct psb_mmu_driver *driver,
        if (atomic_read(&driver->needs_tlbflush) || force) {
                if (driver->dev_priv) {
                        atomic_set(&driver->dev_priv->msvdx_mmu_invaldc, 1);
-                       atomic_set(&driver->dev_priv->topaz_mmu_invaldc, 1);
+                       if (IS_MSVDX(driver->dev_priv->dev))
+                               atomic_set(\
+                                          &driver->dev_priv->topaz_mmu_invaldc, 1);
                }
        }
        atomic_set(&driver->needs_tlbflush, 0);
@@ -186,7 +188,8 @@ void psb_mmu_flush(struct psb_mmu_driver *driver, int rc_prot)
                down_write(&driver->sem);
        if (driver->dev_priv) {
                atomic_set(&driver->dev_priv->msvdx_mmu_invaldc, 1);
-               atomic_set(&driver->dev_priv->topaz_mmu_invaldc, 1);
+               if (IS_MSVDX(driver->dev_priv->dev))
+                       atomic_set(&driver->dev_priv->topaz_mmu_invaldc, 1);
        }
        if (rc_prot)
                up_write(&driver->sem);
@@ -293,7 +296,7 @@ out_err1:
        return NULL;
 }
 
-static void psb_mmu_free_pt(struct psb_mmu_pt *pt)
+void psb_mmu_free_pt(struct psb_mmu_pt *pt)
 {
        __free_page(pt->p);
        kfree(pt);
@@ -374,7 +377,7 @@ static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd) {
        return pt;
 }
 
-static struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd,
+struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd,
                unsigned long addr) {
        uint32_t index = psb_mmu_pd_index(addr);
        struct psb_mmu_pt *pt;
index 53dfcd5..24817e3 100644 (file)
@@ -23,6 +23,7 @@
 #include "psb_drm.h"
 #include "psb_drv.h"
 #include "psb_msvdx.h"
+#include "psb_msvdx_ec.h"
 #include "pnw_topaz.h"
 #include "psb_powermgmt.h"
 #include <linux/io.h>
        list_entry((ptr)->next, type, member)
 #endif
 
+static int ied_enabled;
 
 static int psb_msvdx_send(struct drm_device *dev, void *cmd,
                          unsigned long cmd_size);
 
+static void psb_msvdx_set_tile(struct drm_device *dev,
+                               unsigned long msvdx_tile);
+
 static int psb_msvdx_dequeue_send(struct drm_device *dev)
 {
        struct drm_psb_private *dev_priv = dev->dev_private;
        struct psb_msvdx_cmd_queue *msvdx_cmd = NULL;
        int ret = 0;
        struct msvdx_private *msvdx_priv = dev_priv->msvdx_private;
+       unsigned long irq_flags;
 
+       spin_lock_irqsave(&msvdx_priv->msvdx_lock, irq_flags);
        if (list_empty(&msvdx_priv->msvdx_queue)) {
                PSB_DEBUG_GENERAL("MSVDXQUE: msvdx list empty.\n");
                msvdx_priv->msvdx_busy = 0;
+               spin_unlock_irqrestore(&msvdx_priv->msvdx_lock, irq_flags);
                return -EINVAL;
        }
+
        msvdx_cmd = list_first_entry(&msvdx_priv->msvdx_queue,
                                     struct psb_msvdx_cmd_queue, head);
+       list_del(&msvdx_cmd->head);
+       spin_unlock_irqrestore(&msvdx_priv->msvdx_lock, irq_flags);
+
        PSB_DEBUG_GENERAL("MSVDXQUE: Queue has id %08x\n", msvdx_cmd->sequence);
+       if (IS_MSVDX_MEM_TILE(dev) && drm_psb_msvdx_tiling)
+               psb_msvdx_set_tile(dev, msvdx_cmd->msvdx_tile);
+
+       if (msvdx_cmd->host_be_opp_enabled) {
+               psb_msvdx_update_frame_info(msvdx_priv,
+                       msvdx_cmd->cmd + msvdx_cmd->deblock_cmd_offset);
+       }
+       psb_msvdx_backup_cmd(msvdx_priv,
+                       msvdx_cmd->cmd,
+                       msvdx_cmd->cmd_size,
+                       msvdx_cmd->deblock_cmd_offset);
        ret = psb_msvdx_send(dev, msvdx_cmd->cmd, msvdx_cmd->cmd_size);
        if (ret) {
                DRM_ERROR("MSVDXQUE: psb_msvdx_send failed\n");
                ret = -EINVAL;
        }
-       list_del(&msvdx_cmd->head);
        kfree(msvdx_cmd->cmd);
        kfree(msvdx_cmd);
 
@@ -98,6 +120,9 @@ static int psb_msvdx_map_command(struct drm_device *dev,
        cmd = cmd_start;
        cmd_size_remaining = cmd_size;
 
+       msvdx_priv->host_be_opp_enabled = 0;
+       msvdx_priv->deblock_cmd_offset = PSB_MSVDX_INVALID_OFFSET;
+
        while (cmd_size_remaining > 0) {
                uint32_t cur_cmd_size = MEMIO_READ_FIELD(cmd, FWRK_GENMSG_SIZE);
                uint32_t cur_cmd_id = MEMIO_READ_FIELD(cmd, FWRK_GENMSG_ID);
@@ -105,9 +130,17 @@ static int psb_msvdx_map_command(struct drm_device *dev,
                struct psb_msvdx_deblock_queue *msvdx_deblock;
                unsigned long irq_flags;
 
+#if 0
                PSB_DEBUG_GENERAL("cmd start at %08x cur_cmd_size = %d"
                                  " cur_cmd_id = %02x fence = %08x\n",
                                  (uint32_t) cmd, cur_cmd_size, cur_cmd_id, sequence);
+#else
+               PSB_DEBUG_GENERAL("cmd start at %08x cur_cmd_size = %d,"
+                       " cmd_size_remaining = %d"
+                       " cur_cmd_id = %02x fence = %08x\n",
+                       (uint32_t) cmd, cur_cmd_size, cmd_size_remaining,
+                       cur_cmd_id, sequence);
+#endif
                if ((cur_cmd_size % sizeof(uint32_t))
                    || (cur_cmd_size > cmd_size_remaining)) {
                        ret = -EINVAL;
@@ -120,25 +153,36 @@ static int psb_msvdx_map_command(struct drm_device *dev,
                        PSB_DEBUG_MSVDX("MSVDX_DEBUG: send render message. \n");
 
                        /* Fence ID */
-                       MEMIO_WRITE_FIELD(cmd, FW_VA_DECODE_MSG_ID, sequence);
-
+                       if (IS_MDFLD(dev) && IS_FW_UPDATED)
+                               MEMIO_WRITE_FIELD(cmd, FW_VA_DECODE_MSG_ID, sequence);
+                       else
+                               MEMIO_WRITE_FIELD(cmd, FW_VA_RENDER_FENCE_VALUE, sequence);
                        mmu_ptd = psb_get_default_pd_addr(dev_priv->mmu);
                        msvdx_mmu_invalid = atomic_cmpxchg(&dev_priv->msvdx_mmu_invaldc,
                                                           1, 0);
                        if (msvdx_mmu_invalid == 1) {
-                               uint32_t flags;
-                               flags = MEMIO_READ_FIELD(cmd, FW_DEVA_DECODE_FLAGS);
-                               flags |= FW_DEVA_INVALIDATE_MMU;
-                               MEMIO_WRITE_FIELD(cmd, FW_DEVA_DECODE_FLAGS, flags);
-                               psb_gl3_global_invalidation(dev);
+                               if (!(IS_MDFLD(dev) && IS_FW_UPDATED))
+                                       mmu_ptd |= 1;
+                               else 
+                               {
+                                       uint32_t flags;
+                                       flags = MEMIO_READ_FIELD(cmd, FW_DEVA_DECODE_FLAGS);
+                                       flags |= FW_DEVA_INVALIDATE_MMU;
+                                       MEMIO_WRITE_FIELD(cmd, FW_DEVA_DECODE_FLAGS, flags);
+                                       psb_gl3_global_invalidation(dev);
+                               }
 
                                PSB_DEBUG_GENERAL("MSVDX:Set MMU invalidate\n");
                        }
 
                        /* PTD */
-                       mmu_ptd |= MEMIO_READ_FIELD(cmd,
-                                               FW_VA_DECODE_MMUPTD) & 0xff;
-                       MEMIO_WRITE_FIELD(cmd, FW_VA_DECODE_MMUPTD, mmu_ptd);
+                       if (IS_MDFLD(dev) && IS_FW_UPDATED) {
+                               uint32_t context_id;
+                               context_id = MEMIO_READ_FIELD(cmd, FW_VA_DECODE_MMUPTD);
+                               mmu_ptd = mmu_ptd | (context_id & 0xff);
+                               MEMIO_WRITE_FIELD(cmd, FW_VA_DECODE_MMUPTD, mmu_ptd);
+                       } else
+                               MEMIO_WRITE_FIELD(cmd, FW_VA_RENDER_MMUPTD, mmu_ptd);
                        break;
 
                case VA_MSGID_OOLD:
@@ -158,7 +202,10 @@ static int psb_msvdx_map_command(struct drm_device *dev,
                        PSB_DEBUG_GENERAL("MSVDX:Get oold cmd\n");
 
                        break;
-
+               case VA_MSGID_HOST_BE_OPP_MFLD:
+                       msvdx_priv->host_be_opp_enabled = 1;
+                       msvdx_priv->deblock_cmd_offset =
+                                       cmd_size - cmd_size_remaining;
                case VA_MSGID_OOLD_MFLD:
                case VA_MSGID_DEBLOCK_MFLD: {
                        FW_VA_DEBLOCK_MSG * deblock_msg;
@@ -179,11 +226,18 @@ static int psb_msvdx_map_command(struct drm_device *dev,
                                PSB_DEBUG_GENERAL("MSVDX:Set MMU invalidate\n");
                        }
 
+                       /* patch to right cmd type */
+                       deblock_msg->header.bits.msg_type =
+                                       cur_cmd_id -
+                                       VA_MSGID_DEBLOCK_MFLD +
+                                       VA_MSGID_DEBLOCK;
 
-                       deblock_msg->header.bits.msg_type = cur_cmd_id - VA_MSGID_DEBLOCK_MFLD + VA_MSGID_DEBLOCK; /* patch to right cmd type */
                        deblock_msg->header.bits.msg_fence = (uint16_t)(sequence & 0xffff);
                        deblock_msg->mmu_context.bits.mmu_ptd = (mmu_ptd >> 8);
 
+                       cmd += (sizeof(FW_VA_DEBLOCK_MSG) - cur_cmd_size);
+                       cmd_size_remaining -= (sizeof(FW_VA_DEBLOCK_MSG) -
+                                              cur_cmd_size);
                }
                break;
 
@@ -329,6 +383,12 @@ static int psb_msvdx_map_command(struct drm_device *dev,
 
                cmd += cur_cmd_size;
                cmd_size_remaining -= cur_cmd_size;
+
+               if (((sequence++) & 0xf) == 0xf) {
+                       ret = -EINVAL;
+                       PSB_DEBUG_GENERAL("MSVDX: too many cmds, abort\n");
+                       goto out;
+               }
        }
 
        if (copy_cmd) {
@@ -344,6 +404,19 @@ static int psb_msvdx_map_command(struct drm_device *dev,
                *msvdx_cmd = cmd_copy;
        } else {
                PSB_DEBUG_GENERAL("MSVDXQUE:did NOT copy command\n");
+               if (IS_MSVDX_MEM_TILE(dev) && drm_psb_msvdx_tiling) {
+                       unsigned long msvdx_tile =
+                               ((dev_priv->msvdx_ctx->ctx_type >> 16) & 0xff);
+                       psb_msvdx_set_tile(dev, msvdx_tile);
+               }
+               if (msvdx_priv->host_be_opp_enabled) {
+                       psb_msvdx_update_frame_info(msvdx_priv,
+                               cmd_start + msvdx_priv->deblock_cmd_offset);
+               }
+               psb_msvdx_backup_cmd(msvdx_priv,
+                               cmd_start,
+                               cmd_size,
+                               msvdx_priv->deblock_cmd_offset);
                ret = psb_msvdx_send(dev, cmd_start, cmd_size);
                if (ret) {
                        DRM_ERROR("MSVDXQUE: psb_msvdx_send failed\n");
@@ -357,13 +430,13 @@ out:
        return ret;
 }
 
-static int psb_submit_video_cmdbuf(struct drm_device *dev,
+int psb_submit_video_cmdbuf(struct drm_device *dev,
                            struct ttm_buffer_object *cmd_buffer,
                            unsigned long cmd_offset, unsigned long cmd_size,
                            struct ttm_fence_object *fence)
 {
        struct drm_psb_private *dev_priv = dev->dev_private;
-       uint32_t sequence =  dev_priv->sequence[PSB_ENGINE_VIDEO];
+       uint32_t sequence =  (dev_priv->sequence[PSB_ENGINE_VIDEO] << 4);
        unsigned long irq_flags;
        int ret = 0;
        struct msvdx_private *msvdx_priv = dev_priv->msvdx_private;
@@ -371,16 +444,38 @@ static int psb_submit_video_cmdbuf(struct drm_device *dev,
        /* psb_schedule_watchdog(dev_priv); */
 
        spin_lock_irqsave(&msvdx_priv->msvdx_lock, irq_flags);
-
-       /* expected msvdx_needs_reset is set after previous session exited
-        * but msvdx_hw_busy is always 1, and caused powerdown not excuted
-        * so reload the firmware for every new context
-        */
+       if (!IS_D0(dev)) {
+               /* expected msvdx_needs_reset is set after previous session exited
+                * but msvdx_hw_busy is always 1, and caused powerdown not excuted
+                * so reload the firmware for every new context
+                */
+               if (IS_MRST(dev) && (dev_priv->last_msvdx_ctx == NULL))
+                       msvdx_priv->msvdx_needs_reset = 1; /* re-load firmware */
+
+               if (IS_MRST(dev) && dev_priv->msvdx_ctx && dev_priv->last_msvdx_ctx) {
+                       uint32_t from_profile, to_profile;
+
+                       from_profile =
+                               (dev_priv->last_msvdx_ctx->ctx_type >> 8) &
+                               0xff;
+                       to_profile =
+                               (dev_priv->msvdx_ctx->ctx_type >> 8) & 0xff;
+
+                       /* not the same profile, and one of them is H264 constrained BP
+                        * which needs Error Concealment firmware
+                        */
+                       if ((from_profile != to_profile) &&
+                           ((from_profile == VAProfileH264ConstrainedBaseline) ||
+                            (to_profile == VAProfileH264ConstrainedBaseline))) {
+                               PSB_DEBUG_INIT("MSVDX: firmware switching needed\n");
+                               msvdx_priv->msvdx_needs_reset = 1; /* re-load firmware */
+                       }
+               }
+       }
        dev_priv->last_msvdx_ctx = dev_priv->msvdx_ctx;
 
        if (msvdx_priv->msvdx_needs_reset) {
                spin_unlock_irqrestore(&msvdx_priv->msvdx_lock, irq_flags);
-
                PSB_DEBUG_GENERAL("MSVDX: will reset msvdx\n");
                if (!IS_D0(dev)) {
                        if (psb_msvdx_reset(dev_priv)) {
@@ -459,14 +554,20 @@ static int psb_submit_video_cmdbuf(struct drm_device *dev,
                msvdx_cmd->cmd = cmd;
                msvdx_cmd->cmd_size = cmd_size;
                msvdx_cmd->sequence = sequence;
+               msvdx_cmd->msvdx_tile =
+                       ((dev_priv->msvdx_ctx->ctx_type >> 16) & 0xff);
+               msvdx_cmd->deblock_cmd_offset =
+                       msvdx_priv->deblock_cmd_offset;
+               msvdx_cmd->host_be_opp_enabled =
+                       msvdx_priv->host_be_opp_enabled;
                spin_lock_irqsave(&msvdx_priv->msvdx_lock, irq_flags);
                list_add_tail(&msvdx_cmd->head, &msvdx_priv->msvdx_queue);
+               spin_unlock_irqrestore(&msvdx_priv->msvdx_lock, irq_flags);
                if (!msvdx_priv->msvdx_busy) {
                        msvdx_priv->msvdx_busy = 1;
                        PSB_DEBUG_GENERAL("MSVDXQUE: Need immediate dequeue\n");
                        psb_msvdx_dequeue_send(dev);
                }
-               spin_unlock_irqrestore(&msvdx_priv->msvdx_lock, irq_flags);
        }
 
        return ret;
@@ -533,10 +634,23 @@ static int psb_msvdx_send(struct drm_device *dev, void *cmd,
                }
                cmd += cur_cmd_size;
                cmd_size -= cur_cmd_size;
-               if (cur_cmd_id == VA_MSGID_HOST_BE_OPP) {
+#if 0
+               if (cur_cmd_id == VA_MSGID_DEBLOCK && IS_MRST(dev)) {
+                       cmd += sizeof(struct DEBLOCKPARAMS);
+                       cmd_size -= sizeof(struct DEBLOCKPARAMS);
+               }
+               if (cur_cmd_id == VA_MSGID_HOST_BE_OPP && IS_MRST(dev)) {
                        cmd += sizeof(struct HOST_BE_OPP_PARAMS);
                        cmd_size -= sizeof(struct HOST_BE_OPP_PARAMS);
                }
+#endif
+
+               if (cur_cmd_id == VA_MSGID_HOST_BE_OPP ||
+                   cur_cmd_id == VA_MSGID_DEBLOCK ||
+                   cur_cmd_id == VA_MSGID_OOLD) {
+                       cmd += (sizeof(FW_VA_DEBLOCK_MSG) - cur_cmd_size);
+                       cmd_size -= (sizeof(FW_VA_DEBLOCK_MSG) - cur_cmd_size);
+               }
        }
 
 out:
@@ -558,16 +672,17 @@ int psb_mtx_send(struct drm_psb_private *dev_priv, const void *msg)
 
        msg_num = (MEMIO_READ_FIELD(msg, FWRK_GENMSG_SIZE) + 3) / 4;
 
-       /*
+#if 0
                {
                        int i;
-                       printk("MSVDX: psb_mtx_send is %dDW\n", msg_num);
+                       printk(KERN_DEBUG "MSVDX: psb_mtx_send is %dDW\n",
+                              msg_num);
 
                        for(i = 0; i < msg_num; i++)
-                               printk("0x%08x ", p_msg[i]);
-                       printk("\n");
+                               printk(KERN_DEBUG "0x%08x ", p_msg[i]);
+                       printk(KERN_DEBUG "\n");
                }
-       */
+#endif
        buf_size = PSB_RMSVDX32(MSVDX_COMMS_TO_MTX_BUF_SIZE) & ((1 << 16) - 1);
 
        if (msg_num > buf_size) {
@@ -760,6 +875,7 @@ static void psb_msvdx_mtx_interrupt(struct drm_device *dev)
                PSB_WMSVDX32(clk_enable_all, MSVDX_MAN_CLK_ENABLE);
        }
 
+
 loop: /* just for coding style check */
        ridx = PSB_RMSVDX32(MSVDX_COMMS_TO_HOST_RD_INDEX);
        widx = PSB_RMSVDX32(MSVDX_COMMS_TO_HOST_WRT_INDEX);
@@ -819,21 +935,32 @@ loop: /* just for coding style check */
                                                    FW_VA_HW_PANIC_FIRST_MB_NUM);
                        last_mb = MEMIO_READ_FIELD(buf,
                                                   FW_VA_HW_PANIC_FAULT_MB_NUM);
-                       printk("jiangfei debug: fence in panic message is %d.\n", fence);
-                       PSB_DEBUG_MSVDX("MSVDX_DEBUG: PANIC MESSAGE fence is %d.\n", MEMIO_READ_FIELD(buf, FW_VA_HW_PANIC_FENCE_VALUE));
-                       PSB_DEBUG_MSVDX("MSVDX_DEBUG: PANIC MESSAGE first mb num is %d.\n", MEMIO_READ_FIELD(buf, FW_VA_HW_PANIC_FIRST_MB_NUM));
-                       PSB_DEBUG_MSVDX("MSVDX_DEBUG: PANIC MESSAGE fault mb num is %d.\n", MEMIO_READ_FIELD(buf, FW_VA_HW_PANIC_FAULT_MB_NUM));
-                       PSB_DEBUG_MSVDX("MSVDX_DEBUG: PANIC MESSAGE fe status is 0x%x.\n", MEMIO_READ_FIELD(buf, FW_VA_HW_PANIC_FESTATUS));
-                       PSB_DEBUG_MSVDX("MSVDX_DEBUG: PANIC MESSAGE be status is 0x%x.\n", MEMIO_READ_FIELD(buf, FW_VA_HW_PANIC_BESTATUS));
+                       PSB_DEBUG_MSVDX("MSVDX: PANIC fence is 0x%x\n",
+                                       MEMIO_READ_FIELD(buf,
+                                               FW_VA_HW_PANIC_FENCE_VALUE));
+                       PSB_DEBUG_MSVDX("MSVDX: PANIC first mb num is %d\n",
+                                       MEMIO_READ_FIELD(buf,
+                                               FW_VA_HW_PANIC_FIRST_MB_NUM));
+                       PSB_DEBUG_MSVDX("MSVDX: PANIC fault mb num is %d\n",
+                                       MEMIO_READ_FIELD(buf,
+                                               FW_VA_HW_PANIC_FAULT_MB_NUM));
+                       PSB_DEBUG_MSVDX("MSVDX: PANIC fe status is 0x%x\n",
+                                       MEMIO_READ_FIELD(buf,
+                                               FW_VA_HW_PANIC_FESTATUS));
+                       PSB_DEBUG_MSVDX("MSVDX: PANIC be status is 0x%x\n",
+                                       MEMIO_READ_FIELD(buf,
+                                               FW_VA_HW_PANIC_BESTATUS));
                } else {
                        fence = MEMIO_READ_FIELD(buf,
                                                 FW_VA_CMD_FAILED_FENCE_VALUE);
                        PSB_DEBUG_MSVDX("MSVDX_DEBUG: FAILED MESSAGE fence is %d.\n", MEMIO_READ_FIELD(buf, FW_VA_HW_PANIC_FIRST_MB_NUM));
                        PSB_DEBUG_MSVDX("MSVDX_DEBUG: FAILED MESSAGE flag is %d.\n", MEMIO_READ_FIELD(buf, FW_VA_CMD_FAILED_FLAGS));
                }
-
-               fence = MEMIO_READ_FIELD(buf, FW_DEVA_CMD_FAILED_MSG_ID);
-               fault = MEMIO_READ_FIELD(buf, FW_DEVA_CMD_FAILED_FLAGS);
+               if (IS_MDFLD(dev) && IS_FW_UPDATED) 
+               {
+                       fence = MEMIO_READ_FIELD(buf, FW_DEVA_CMD_FAILED_MSG_ID);
+                       fault = MEMIO_READ_FIELD(buf, FW_DEVA_CMD_FAILED_FLAGS);
+               }
 
                if (msg_id == VA_MSGID_CMD_HW_PANIC)
                        PSB_DEBUG_GENERAL("MSVDX: VA_MSGID_CMD_HW_PANIC:"
@@ -901,8 +1028,10 @@ loop: /* just for coding style check */
                /* uint32_t last_mb = MEMIO_READ_FIELD(buf,
                   FW_VA_CMD_COMPLETED_LASTMB);
                */
-
-               fence = MEMIO_READ_FIELD(buf, FW_VA_CMD_COMPLETED_MSG_ID);
+               if (IS_MDFLD(dev) && IS_FW_UPDATED)
+                       fence = MEMIO_READ_FIELD(buf, FW_VA_CMD_COMPLETED_MSG_ID);
+               else
+                       fence = MEMIO_READ_FIELD(buf, FW_VA_CMD_COMPLETED_FENCE_VALUE);
 
                PSB_DEBUG_GENERAL("MSVDX:VA_MSGID_CMD_COMPLETED: "
                                  "FenceID: %08x, flags: 0x%x\n",
@@ -952,15 +1081,12 @@ loop: /* just for coding style check */
                                                  FW_VA_DEBLOCK_REQUIRED_FENCE_VALUE);
 
                PSB_DEBUG_GENERAL("MSVDX: VA_MSGID_DEBLOCK_REQUIRED"
-                                 " Context=%08x\n", ctxid);
+                                 " Fence=%08x\n", fence);
 
 
                /*deblock and on-be-opp use the same message, there is difficulty to distinguish them*/
-               /*now I just let user space use cpu copy error mb*/
-               if ((msvdx_priv->deblock_enabled == 1) && (msvdx_priv->host_be_opp_enabled == 1)) {
-                       DRM_ERROR("MSVDX: should not support both deblock and host_be_opp message. \n");
-                       goto done;
-               } else if (msvdx_priv->deblock_enabled == 1) {
+               if (IS_MRST(dev) && 
+               (msvdx_priv->deblock_enabled == 1)) {
                        PSB_DEBUG_MSVDX("MSVDX_DEBUG: get deblock required message for deblock operation.\n");
                        if (list_empty(&msvdx_priv->deblock_queue)) {
                                PSB_DEBUG_GENERAL(
@@ -1017,71 +1143,112 @@ loop: /* just for coding style check */
 
                        list_del(&msvdx_deblock->head);
                        kfree(msvdx_deblock);
-               } else if (msvdx_priv->host_be_opp_enabled == 1) {
-                       PSB_DEBUG_MSVDX("MSVDX_DEBUG: get deblock required message for error concealment.\n");
+               }
+               else {
+                       struct psb_msvdx_ec_ctx *msvdx_ec_ctx = NULL;
+                       int found = 0;
+                       PSB_DEBUG_MSVDX("Get deblock required msg for ec\n");
+                       for (i = 0; i < PSB_MAX_EC_INSTANCE; i++)
+                               if (msvdx_priv->msvdx_ec_ctx[i]->fence
+                                                       == (fence & (~0xf))) {
+                                       msvdx_ec_ctx =
+                                               msvdx_priv->msvdx_ec_ctx[i];
+                                       found++;
+                               }
+                       /* if found > 1, fence wrapping happens */
+                       if (!msvdx_ec_ctx ||
+                           !(msvdx_ec_ctx->tfile) || found > 1) {
+                               PSB_DEBUG_MSVDX(
+                       "no matched ctx: fence 0x%x, found %d, ctx 0x%08x\n",
+                                       fence, found, msvdx_ec_ctx);
+                               PSB_WMSVDX32(0, MSVDX_CMDS_END_SLICE_PICTURE);
+                               PSB_WMSVDX32(1, MSVDX_CMDS_END_SLICE_PICTURE);
+                               goto done;
+                       }
+
+                       msvdx_ec_ctx->cur_frame_info->fw_status = 1;
 
                        /* try to unblock rendec */
+                       /*
                        PSB_WMSVDX32(0, MSVDX_CMDS_END_SLICE_PICTURE);
                        PSB_WMSVDX32(1, MSVDX_CMDS_END_SLICE_PICTURE);
-
+                       */
                        /*do error concealment with hw*/
-                       msvdx_priv->ec_fence = fence;
+                       msvdx_priv->cur_msvdx_ec_ctx = msvdx_ec_ctx;
                        schedule_work(&msvdx_priv->ec_work);
                }
-
                break;
        }
 
        case VA_MSGID_CMD_CONTIGUITY_WARNING: {
                drm_psb_msvdx_frame_info_t *ec_frame = NULL;
                drm_psb_msvdx_decode_status_t *fault_region = NULL;
+               struct psb_msvdx_ec_ctx *msvdx_ec_ctx = NULL;
+               uint32_t reg_idx;
+               int found = 0;
 
                /*get erro info*/
                uint32_t fence = MEMIO_READ_FIELD(buf,
-                                                 FW_VA_CONTIGUITY_WARNING_FENCE_VALUE);
-               uint32_t ui32Start = MEMIO_READ_FIELD(buf,
-                                                     FW_VA_CONTIGUITY_WARNING_BEGIN_MB_NUM);
-               uint32_t ui32End = MEMIO_READ_FIELD(buf,
-                                                   FW_VA_CONTIGUITY_WARNING_END_MB_NUM);
-               PSB_DEBUG_GENERAL("MSVDX: VA_MSGID_CMD_CONTIGUITY_WARNING\n");
-               PSB_DEBUG_MSVDX("MSVDX_DEBUG: get contiguity warning message.\n");
-               PSB_DEBUG_MSVDX("MSVDX_DEBUG: CONTIGUITY_WARNING MESSAGE fence is %d.\n", MEMIO_READ_FIELD(buf, FW_VA_CONTIGUITY_WARNING_FENCE_VALUE));
-               PSB_DEBUG_MSVDX("MSVDX_DEBUG: CONTIGUITY_WARNING MESSAGE end mb num is %d.\n", MEMIO_READ_FIELD(buf, FW_VA_CONTIGUITY_WARNING_END_MB_NUM));
-               PSB_DEBUG_MSVDX("MSVDX_DEBUG: CONTIGUITY_WARNING MESSAGE begin mb num is %d.\n", MEMIO_READ_FIELD(buf, FW_VA_CONTIGUITY_WARNING_BEGIN_MB_NUM));
+                                       FW_VA_CONTIGUITY_WARNING_FENCE_VALUE);
+               uint32_t start = MEMIO_READ_FIELD(buf,
+                                       FW_VA_CONTIGUITY_WARNING_BEGIN_MB_NUM);
+               uint32_t end = MEMIO_READ_FIELD(buf,
+                                       FW_VA_CONTIGUITY_WARNING_END_MB_NUM);
+               PSB_DEBUG_MSVDX("MSVDX: get contiguity warning message\n");
+               PSB_DEBUG_MSVDX("MSVDX: CONTIGUITY_WARNING fence %x\n",
+                               MEMIO_READ_FIELD(buf,
+                                       FW_VA_CONTIGUITY_WARNING_FENCE_VALUE));
+               PSB_DEBUG_MSVDX("MSVDX: CONTIGUITY_WARNING end mb num %d\n",
+                               MEMIO_READ_FIELD(buf,
+                                       FW_VA_CONTIGUITY_WARNING_END_MB_NUM));
+               PSB_DEBUG_MSVDX("MSVDX: CONTIGUITY_WARNING begin mb num %d\n",
+                       MEMIO_READ_FIELD(buf,
+                               FW_VA_CONTIGUITY_WARNING_BEGIN_MB_NUM));
 
                /*get the frame_info struct for error concealment frame*/
-               for (i = 0; i < MAX_DECODE_BUFFERS; i++) {
-                       if (msvdx_priv->frame_info[i].fence == fence) {
-                               ec_frame = &msvdx_priv->frame_info[i];
-                               break;
+               for (i = 0; i < PSB_MAX_EC_INSTANCE; i++)
+                       if (msvdx_priv->msvdx_ec_ctx[i]->fence ==
+                                                       (fence & (~0xf))) {
+                               msvdx_ec_ctx = msvdx_priv->msvdx_ec_ctx[i];
+                               found++;
                        }
-               }
-               if (!ec_frame) {
-                       DRM_ERROR("MSVDX: didn't find frame_info which matched the fence %d when get contiguity warning.\n", fence);
+               /* psb_msvdx_mtx_message_dump(dev); */
+               if (!msvdx_ec_ctx || !(msvdx_ec_ctx->tfile) || found > 1) {
+                       PSB_DEBUG_MSVDX(
+                       "no matched ctx: fence 0x%x, found %d, ctx 0x%08x\n",
+                               fence, found, msvdx_ec_ctx);
                        goto done;
-               } else if (msvdx_priv->host_be_opp_enabled) {
-                       ec_frame->fw_status = 1;
-                       fault_region = &ec_frame->decode_status;
-                       if (ui32Start == 0xffff) {
-                               if (fault_region->num_error_slice == 0) {
-                                       fault_region->start_error_mb_list[fault_region->num_error_slice] = 0;
-                                       fault_region->end_error_mb_list[fault_region->num_error_slice] = ui32End;
-                                       fault_region->num_error_slice++;
-                               } else if (fault_region->end_error_mb_list[fault_region->num_error_slice - 1] == 0xffff) {
-                                       fault_region->end_error_mb_list[fault_region->num_error_slice - 1] = ui32End;
-                               }
-                       } else if (ui32Start <  ui32End) {
-                               fault_region->start_error_mb_list[fault_region->num_error_slice] = ui32Start;
-                               fault_region->end_error_mb_list[fault_region->num_error_slice] = ui32End;
-                               fault_region->num_error_slice++;
-                       } else {
-                               DRM_ERROR("msvdx error: start mb counter should not be larger than end mb counter.\n");
-                               goto done;
-                       }
                }
 
-               break;
+               /*
+               ec_frame->fw_status = 1;
+               fault_region = &ec_frame->decode_status;
+               */
 
+               fault_region = &msvdx_ec_ctx->decode_status;
+               if (start > end)
+                       start = end;
+               if (start < PSB_MSVDX_EC_ROLLBACK)
+                       start = 0;
+               else
+                       start -= PSB_MSVDX_EC_ROLLBACK;
+
+               if (fault_region->num_region) {
+                       reg_idx = fault_region->num_region - 1;
+                       if ((start <= fault_region->mb_regions[reg_idx].end) &&
+                           (end > fault_region->mb_regions[reg_idx].end))
+                               fault_region->mb_regions[reg_idx].end = end;
+                       else {
+                               reg_idx = fault_region->num_region++;
+                               fault_region->mb_regions[reg_idx].start = start;
+                               fault_region->mb_regions[reg_idx].end = end;
+                       }
+               } else {
+                       reg_idx = fault_region->num_region++;
+                       fault_region->mb_regions[reg_idx].start = start;
+                       fault_region->mb_regions[reg_idx].end = end;
+               }
+               break;
        }
        default:
                DRM_ERROR("ERROR: msvdx Unknown message from MTX, ID:0x%08x\n", MEMIO_READ_FIELD(buf, FWRK_GENMSG_ID));
@@ -1089,10 +1256,12 @@ loop: /* just for coding style check */
        }
 
 done:
+       PSB_DEBUG_GENERAL("MSVDX Interrupt: finish process a message\n");
        if (ridx != widx) {
                PSB_DEBUG_GENERAL("MSVDX Interrupt: there are more message to be read\n");
                goto loop;
        }
+
        /* we get a frame/slice done, try to save some power*/
        if (IS_D0(dev)) {
                if (drm_msvdx_pmpolicy == PSB_PMPOLICY_POWERDOWN)
@@ -1122,6 +1291,10 @@ IMG_BOOL psb_msvdx_interrupt(IMG_VOID *pvData)
        }
 
        dev = (struct drm_device *)pvData;
+       if (!ospm_power_is_hw_on(OSPM_VIDEO_DEC_ISLAND) && IS_MRST(dev)) {
+               DRM_ERROR("ERROR: interrupt arrived but HW is power off\n");
+               return IMG_FALSE;
+       }
 
        dev_priv = (struct drm_psb_private *) dev->dev_private;
        msvdx_priv = dev_priv->msvdx_private;
@@ -1133,7 +1306,7 @@ IMG_BOOL psb_msvdx_interrupt(IMG_VOID *pvData)
        /* driver only needs to handle mtx irq
         * For MMU fault irq, there's always a HW PANIC generated
         * if HW/FW is totally hang, the lockup function will handle
-        * the reseting when firmware is loaded w/o the driver
+        * the reseting
         */
        if (!IS_D0(dev) &&
            (msvdx_stat & MSVDX_INTERRUPT_STATUS_CR_MMU_FAULT_IRQ_MASK)) {
@@ -1243,28 +1416,32 @@ int psb_check_msvdx_idle(struct drm_device *dev)
 int psb_remove_videoctx(struct drm_psb_private *dev_priv, struct file *filp)
 {
        struct psb_video_ctx *pos, *n;
+       /* iterate to query all ctx to if there is DRM running*/
+       ied_enabled = 0;
 
        list_for_each_entry_safe(pos, n, &dev_priv->video_ctx, head) {
                if (pos->filp == filp) {
                        PSB_DEBUG_GENERAL("Video:remove context profile %d,"
-                                         " entrypoint %d",
-                                         (pos->ctx_type >> 8),
+                                         " entrypoint %d\n",
+                                         (pos->ctx_type >> 8) & 0xff,
                                          (pos->ctx_type & 0xff));
 
                        /* if current ctx points to it, set to NULL */
                        if (dev_priv->topaz_ctx == pos) {
                                /*Reset fw load status here.*/
-                               if (VAEntrypointEncSlice ==
-                                       (pos->ctx_type & 0xff)
+                               if (IS_MDFLD(dev_priv->dev) &&
+                                       (VAEntrypointEncSlice ==
+                                               (pos->ctx_type & 0xff)
                                        || VAEntrypointEncPicture ==
-                                               (pos->ctx_type & 0xff))
+                                               (pos->ctx_type & 0xff)))
                                        pnw_reset_fw_status(dev_priv->dev);
 
                                dev_priv->topaz_ctx = NULL;
-                       } else if (VAEntrypointEncSlice ==
+                       } else if (IS_MDFLD(dev_priv->dev) &&
+                                       (VAEntrypointEncSlice ==
                                                (pos->ctx_type & 0xff)
                                        || VAEntrypointEncPicture ==
-                                               (pos->ctx_type & 0xff))
+                                               (pos->ctx_type & 0xff)))
                                PSB_DEBUG_GENERAL("Remove a inactive "\
                                                "encoding context.\n");
 
@@ -1278,10 +1455,24 @@ int psb_remove_videoctx(struct drm_psb_private *dev_priv, struct file *filp)
 
                        list_del(&pos->head);
                        kfree(pos);
+               }  else {
+                       if (pos->ctx_type & VA_RT_FORMAT_PROTECTED)
+                               ied_enabled = 1;
                }
        }
        return 0;
 }
+struct psb_video_ctx *psb_find_videoctx(struct drm_psb_private *dev_priv,
+                                       struct file *filp)
+{
+       struct psb_video_ctx *pos, *n;
+
+       list_for_each_entry_safe(pos, n, &dev_priv->video_ctx, head) {
+               if (pos->filp == filp)
+                       return pos;
+       }
+       return NULL;
+}
 
 static int psb_entrypoint_number(struct drm_psb_private *dev_priv,
                uint32_t entry_type)
@@ -1298,7 +1489,8 @@ static int psb_entrypoint_number(struct drm_psb_private *dev_priv,
        }
 
        list_for_each_entry_safe(pos, n, &dev_priv->video_ctx, head) {
-               if (entry_type == (pos->ctx_type & 0xff))
+               if (IS_MDFLD(dev_priv->dev) &&
+                               (entry_type == (pos->ctx_type & 0xff)))
                        count++;
 
        }
@@ -1317,8 +1509,9 @@ int lnc_video_getparam(struct drm_device *dev, void *data,
        struct drm_psb_private *dev_priv =
                (struct drm_psb_private *)file_priv->minor->dev->dev_private;
        drm_psb_msvdx_frame_info_t *current_frame = NULL;
+       struct ttm_object_file *tfile = psb_fpriv(file_priv)->tfile;
        uint32_t handle, i;
-
+       uint32_t offset = 0;
        uint32_t device_info = 0;
        uint32_t ctx_type = 0;
        struct psb_video_ctx *video_ctx = NULL;
@@ -1341,7 +1534,10 @@ int lnc_video_getparam(struct drm_device *dev, void *data,
                                   sizeof(rar_ci_info));
                break;
        case LNC_VIDEO_FRAME_SKIP:
-               ret = -EFAULT;
+               if (IS_MRST(dev))
+                       ret = lnc_video_frameskip(dev, arg->value);
+               else if (IS_MDFLD(dev)) /* Medfield should not call it */
+                       ret = -EFAULT;
                break;
        case LNC_VIDEO_DEVICE_INFO:
                device_info = 0xffff & dev_priv->video_device_fuse;
@@ -1364,16 +1560,43 @@ int lnc_video_getparam(struct drm_device *dev, void *data,
                video_ctx->filp = file_priv->filp;
                list_add(&video_ctx->head, &dev_priv->video_ctx);
 
-               if (VAEntrypointEncSlice == (ctx_type & 0xff))
+               if (IS_MDFLD(dev_priv->dev) &&
+                               (VAEntrypointEncSlice ==
+                                (ctx_type & 0xff)))
                        pnw_reset_fw_status(dev_priv->dev);
 
-               PSB_DEBUG_GENERAL("Video:add context profile %d, entrypoint %d",
-                                 (ctx_type >> 8), (ctx_type & 0xff));
+               PSB_DEBUG_GENERAL("Video:add ctx profile %d, entry %d.\n",
+                                       ((ctx_type >> 8) & 0xff),
+                                       (ctx_type & 0xff));
+               PSB_DEBUG_GENERAL("Video:add context protected 0x%x.\n",
+                                       (ctx_type & VA_RT_FORMAT_PROTECTED));
+               if (ctx_type & VA_RT_FORMAT_PROTECTED)
+                       ied_enabled = 1;
                break;
 
        case IMG_VIDEO_RM_CONTEXT:
                psb_remove_videoctx(dev_priv, file_priv->filp);
                break;
+#if 0 //TODO: add this with usr space update
+       case IMG_VIDEO_UPDATE_CONTEXT:
+               ret = copy_from_user(&ctx_type,
+                               (void __user *)((unsigned long)arg->value),
+                               sizeof(ctx_type));
+               video_ctx = psb_find_videoctx(dev_priv, file_priv->filp);
+               if (video_ctx) {
+                       PSB_DEBUG_GENERAL(
+                               "Video: update video ctx old value 0x%08x\n",
+                               video_ctx->ctx_type);
+                       video_ctx->ctx_type = ctx_type;
+                       PSB_DEBUG_GENERAL(
+                               "Video: update video ctx new value 0x%08x\n",
+                               video_ctx->ctx_type);
+               } else
+                       PSB_DEBUG_GENERAL(
+                               "Video:fail to find context profile %d, entrypoint %d",
+                               (ctx_type >> 8), (ctx_type & 0xff));
+#endif
+               break;
        case IMG_VIDEO_DECODE_STATUS:
                if (msvdx_priv->host_be_opp_enabled) {
                        /*get the right frame_info struct for current surface*/
@@ -1443,6 +1666,9 @@ int lnc_video_getparam(struct drm_device *dev, void *data,
                        return -EFAULT;
                }
                break;
+       case IMG_DISPLAY_SET_WIDI_EXT_STATE:
+               DRM_ERROR("variable drm_psb_widi has been removed\n");
+               break;
        case IMG_VIDEO_GET_HDMI_STATE:
 #ifdef IMG_VIDEO_SUPPORT_HDMI_STATE_SETTING
                ret = copy_to_user((void __user *)((unsigned long)arg->value),
@@ -1486,6 +1712,33 @@ int lnc_video_getparam(struct drm_device *dev, void *data,
                                        ((unsigned long)arg->value),
                                        &i, sizeof(i));
                break;
+               case IMG_VIDEO_IED_STATE:
+               if (IS_MDFLD(dev)) {
+                       /* query IED status by register is not safe */
+                       /* need first power-on msvdx, while now only  */
+                       /* schedule vxd suspend wq in interrupt handler */
+#if 0
+                       int ied_enable;
+                       /* VXD must be power on during query IED register */
+                       if (!ospm_power_using_hw_begin(OSPM_VIDEO_DEC_ISLAND,
+                                       OSPM_UHB_FORCE_POWER_ON))
+                               return -EBUSY;
+                       /* wrong spec, IED should be located in pci device 2 */
+                       if (REG_READ(PSB_IED_DRM_CNTL_STATUS) & IED_DRM_VLD)
+                               ied_enable = 1;
+                       else
+                               ied_enable = 0;
+                       PSB_DEBUG_GENERAL("ied_enable is %d.\n", ied_enable);
+                       ospm_power_using_hw_end(OSPM_VIDEO_DEC_ISLAND);
+#endif
+                       ret = copy_to_user((void __user *)
+                                       ((unsigned long)arg->value),
+                                       &ied_enabled, sizeof(ied_enabled));
+               } else { /* Moorestown should not call it */
+                       DRM_ERROR("IMG_VIDEO_IED_EANBLE error.\n");
+                       return -EFAULT;
+               }
+               break;
        default:
                ret = -EFAULT;
                break;
@@ -1542,15 +1795,74 @@ int psb_msvdx_check_reset_fw(struct drm_device *dev)
        unsigned long irq_flags;
 
        spin_lock_irqsave(&msvdx_priv->msvdx_lock, irq_flags);
+       /* reserve these code, once we use a unified firmware upload, we may
+        * have to support MRST with additional code change
+        */
+       /* expected msvdx_needs_reset is set after previous session exited
+        * but msvdx_hw_busy is always 1, and caused powerdown not excuted
+        * so reload the firmware for every new context
+        */
+       if (IS_MRST(dev) && (dev_priv->last_msvdx_ctx == NULL))
+               msvdx_priv->msvdx_needs_reset |= MSVDX_RESET_NEEDS_REUPLOAD_FW |
+                       MSVDX_RESET_NEEDS_INIT_FW; /* re-load firmware */
 
+       if (IS_MRST(dev) && dev_priv->msvdx_ctx && dev_priv->last_msvdx_ctx) {
+               uint32_t from_profile, to_profile;
+
+               from_profile = (dev_priv->last_msvdx_ctx->ctx_type >> 8) & 0xff;
+               to_profile = (dev_priv->msvdx_ctx->ctx_type >> 8) & 0xff;
+
+               /* not the same profile, and one of them is H264 constrained BP
+                * which needs Error Concealment firmware
+                */
+               if ((from_profile != to_profile) &&
+                   ((from_profile == VAProfileH264ConstrainedBaseline) ||
+                    (to_profile == VAProfileH264ConstrainedBaseline))) {
+                       PSB_DEBUG_INIT("MSVDX: firmware switching needed\n");
+                       msvdx_priv->msvdx_needs_reset |= MSVDX_RESET_NEEDS_REUPLOAD_FW |
+                               MSVDX_RESET_NEEDS_INIT_FW; /* re-load firmware */
+               }
+       }
        /* handling fw upload here if required */
        /* power off first, then hw_begin will power up/upload FW correctly */
        if (msvdx_priv->msvdx_needs_reset & MSVDX_RESET_NEEDS_REUPLOAD_FW) {
                msvdx_priv->msvdx_needs_reset &= ~MSVDX_RESET_NEEDS_REUPLOAD_FW;
                ospm_power_island_down(OSPM_VIDEO_DEC_ISLAND);
        }
-
        spin_unlock_irqrestore(&msvdx_priv->msvdx_lock, irq_flags);
-
        return 0;
 }
+static void psb_msvdx_set_tile(struct drm_device *dev, unsigned long msvdx_tile)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       struct msvdx_private *msvdx_priv = dev_priv->msvdx_private;
+       uint32_t cmd, msvdx_stride;
+       uint32_t start = msvdx_priv->tile_region_start0;
+       uint32_t end = msvdx_priv->tile_region_end0;
+
+       msvdx_stride = (msvdx_tile & 0xf);
+       /* Enable memory tiling */
+       cmd = ((start >> 20) + (((end >> 20) - 1) << 12) +
+                               ((0x8 | (msvdx_stride - 1)) << 24));
+       if (msvdx_stride) {
+               PSB_DEBUG_GENERAL("MSVDX: MMU Tiling register0 %08x\n", cmd);
+               PSB_DEBUG_GENERAL("       Region 0x%08x-0x%08x\n",
+                                       start, end);
+               PSB_WMSVDX32(cmd, MSVDX_MMU_TILE_BASE0);
+       }
+
+       start = msvdx_priv->tile_region_start1;
+       end = msvdx_priv->tile_region_end1;
+
+       msvdx_stride = (msvdx_tile >> 4);
+       /* Enable memory tiling */
+       PSB_WMSVDX32(0, MSVDX_MMU_TILE_BASE1);
+       cmd = ((start >> 20) + (((end >> 20) - 1) << 12) +
+                               ((0x8 | (msvdx_stride - 1)) << 24));
+       if (msvdx_stride) {
+               PSB_DEBUG_GENERAL("MSVDX: MMU Tiling register1 %08x\n", cmd);
+               PSB_DEBUG_GENERAL("       Region 0x%08x-0x%08x\n",
+                                       start, end);
+               PSB_WMSVDX32(cmd, MSVDX_MMU_TILE_BASE1);
+       }
+}
index 65099f3..403c72f 100644 (file)
@@ -26,6 +26,8 @@
 
 extern int drm_msvdx_pmpolicy;
 extern int drm_msvdx_delay;
+extern int hdmi_state;
+extern int drm_psb_msvdx_tiling;
 
 typedef enum {
        PSB_DMAC_BSWAP_NO_SWAP = 0x0,   //!< No byte swapping will be performed.
@@ -96,7 +98,6 @@ int psb_cmdbuf_video(struct drm_file *priv,
 int psb_msvdx_save_context(struct drm_device *dev);
 int psb_msvdx_restore_context(struct drm_device *dev);
 int psb_msvdx_check_reset_fw(struct drm_device *dev);
-
 bool
 psb_host_second_pass(struct drm_device *dev,
                     uint32_t ui32OperatingModeCmd,
@@ -263,6 +264,8 @@ MSVDX_CORE_CR_MSVDX_MAN_CLK_ENABLE_CR_MTX_MAN_CLK_ENABLE_MASK)
 #define MSVDX_MMU_CONTROL0             (0x0680)
 #define MSVDX_MMU_STATUS               (0x068C)
 #define MSVDX_MMU_MEM_REQ              (0x06D0)
+#define MSVDX_MMU_TILE_BASE0           (0x06D4)
+#define MSVDX_MMU_TILE_BASE1           (0x06D8)
 #define MSVDX_MTX_RAM_BANK             (0x06F0)
 #define MSVDX_MTX_DEBUG                        MSVDX_MTX_RAM_BANK
 #define MSVDX_MAN_CLK_ENABLE           (0x0620)
@@ -616,57 +619,55 @@ MSVDX_CORE_CR_MSVDX_MAN_CLK_ENABLE_CR_MTX_MAN_CLK_ENABLE_MASK)
 #define VEC_LOCAL_MEM_OFFSET 0x2000
 
 /* 1311 RENDEC init msg */
-#define FW_DEVA_INIT_SIZE              16
-#define FW_DEVA_INIT_ID                        0x80
+#define FW_DEVA_INIT_SIZE (16)
+#define FW_DEVA_INIT_ID (0x80)
 
 /* FW_DEVA_INIT     RENDEC_ADDR0 */
-#define FW_DEVA_INIT_RENDEC_ADDR0_START_BIT    0
-#define FW_DEVA_INIT_RENDEC_ADDR0_END_BIT      31
-#define FW_DEVA_INIT_RENDEC_ADDR0_ALIGNMENT    4
-#define FW_DEVA_INIT_RENDEC_ADDR0_TYPE         IMG_UINT32
-#define FW_DEVA_INIT_RENDEC_ADDR0_MASK         0xFFFFFFFF
-#define FW_DEVA_INIT_RENDEC_ADDR0_LSBMASK       0xFFFFFFFF
-#define FW_DEVA_INIT_RENDEC_ADDR0_OFFSET        0x0004
-#define FW_DEVA_INIT_RENDEC_ADDR0_SHIFT                0
+#define FW_DEVA_INIT_RENDEC_ADDR0_START_BIT     0
+#define FW_DEVA_INIT_RENDEC_ADDR0_END_BIT       31
+#define FW_DEVA_INIT_RENDEC_ADDR0_ALIGNMENT     (4)
+#define FW_DEVA_INIT_RENDEC_ADDR0_TYPE      IMG_UINT32
+#define FW_DEVA_INIT_RENDEC_ADDR0_MASK      (0xFFFFFFFF)
+#define FW_DEVA_INIT_RENDEC_ADDR0_LSBMASK       (0xFFFFFFFF)
+#define FW_DEVA_INIT_RENDEC_ADDR0_OFFSET        (0x0004)
+#define FW_DEVA_INIT_RENDEC_ADDR0_SHIFT     (0)
 #define FW_DEVA_INIT_RENDEC_ADDR0_SIGNED_FIELD  IMG_FALSE
 
 /* FW_DEVA_INIT     RENDEC_ADDR1 */
-#define FW_DEVA_INIT_RENDEC_ADDR1_START_BIT    0
-#define FW_DEVA_INIT_RENDEC_ADDR1_END_BIT      31
-#define FW_DEVA_INIT_RENDEC_ADDR1_ALIGNMENT    4
-#define FW_DEVA_INIT_RENDEC_ADDR1_TYPE         IMG_UINT32
-#define FW_DEVA_INIT_RENDEC_ADDR1_MASK         0xFFFFFFFF
-#define FW_DEVA_INIT_RENDEC_ADDR1_LSBMASK      0xFFFFFFFF
-#define FW_DEVA_INIT_RENDEC_ADDR1_OFFSET        0x0008
-#define FW_DEVA_INIT_RENDEC_ADDR1_SHIFT                0
+#define FW_DEVA_INIT_RENDEC_ADDR1_START_BIT     0
+#define FW_DEVA_INIT_RENDEC_ADDR1_END_BIT       31
+#define FW_DEVA_INIT_RENDEC_ADDR1_ALIGNMENT     (4)
+#define FW_DEVA_INIT_RENDEC_ADDR1_TYPE      IMG_UINT32
+#define FW_DEVA_INIT_RENDEC_ADDR1_MASK      (0xFFFFFFFF)
+#define FW_DEVA_INIT_RENDEC_ADDR1_LSBMASK       (0xFFFFFFFF)
+#define FW_DEVA_INIT_RENDEC_ADDR1_OFFSET        (0x0008)
+#define FW_DEVA_INIT_RENDEC_ADDR1_SHIFT     (0)
 #define FW_DEVA_INIT_RENDEC_ADDR1_SIGNED_FIELD  IMG_FALSE
 
 /* FW_DEVA_INIT     RENDEC_SIZE1 */
-#define FW_DEVA_INIT_RENDEC_SIZE1_START_BIT    16
-#define FW_DEVA_INIT_RENDEC_SIZE1_END_BIT      31
-#define FW_DEVA_INIT_RENDEC_SIZE1_ALIGNMENT    2
-#define FW_DEVA_INIT_RENDEC_SIZE1_TYPE         IMG_UINT16
-#define FW_DEVA_INIT_RENDEC_SIZE1_MASK         0xFFFF
-#define FW_DEVA_INIT_RENDEC_SIZE1_LSBMASK      0xFFFF
-#define FW_DEVA_INIT_RENDEC_SIZE1_OFFSET       0x000E
-#define FW_DEVA_INIT_RENDEC_SIZE1_SHIFT                0
-#define FW_DEVA_INIT_RENDEC_SIZE1_SIGNED_FIELD IMG_FALSE
+#define FW_DEVA_INIT_RENDEC_SIZE1_START_BIT     16
+#define FW_DEVA_INIT_RENDEC_SIZE1_END_BIT       31
+#define FW_DEVA_INIT_RENDEC_SIZE1_ALIGNMENT     (2)
+#define FW_DEVA_INIT_RENDEC_SIZE1_TYPE      IMG_UINT16
+#define FW_DEVA_INIT_RENDEC_SIZE1_MASK      (0xFFFF)
+#define FW_DEVA_INIT_RENDEC_SIZE1_LSBMASK       (0xFFFF)
+#define FW_DEVA_INIT_RENDEC_SIZE1_OFFSET        (0x000E)
+#define FW_DEVA_INIT_RENDEC_SIZE1_SHIFT     (0)
+#define FW_DEVA_INIT_RENDEC_SIZE1_SIGNED_FIELD  IMG_FALSE
 
 /* FW_DEVA_INIT     RENDEC_SIZE0 */
-#define FW_DEVA_INIT_RENDEC_SIZE0_START_BIT    0
-#define FW_DEVA_INIT_RENDEC_SIZE0_END_BIT      15
-#define FW_DEVA_INIT_RENDEC_SIZE0_ALIGNMENT    2
-#define FW_DEVA_INIT_RENDEC_SIZE0_TYPE         IMG_UINT16
-#define FW_DEVA_INIT_RENDEC_SIZE0_MASK         0xFFFF
-#define FW_DEVA_INIT_RENDEC_SIZE0_LSBMASK      0xFFFF
-#define FW_DEVA_INIT_RENDEC_SIZE0_OFFSET       0x000C
-#define FW_DEVA_INIT_RENDEC_SIZE0_SHIFT                0
-#define FW_DEVA_INIT_RENDEC_SIZE0_SIGNED_FIELD IMG_FALSE
-
-#define MSVDX_RESET_NEEDS_REUPLOAD_FW          0x2
-#define MSVDX_RESET_NEEDS_INIT_FW              0x1
-
-
+#define FW_DEVA_INIT_RENDEC_SIZE0_START_BIT     0
+#define FW_DEVA_INIT_RENDEC_SIZE0_END_BIT       15
+#define FW_DEVA_INIT_RENDEC_SIZE0_ALIGNMENT     (2)
+#define FW_DEVA_INIT_RENDEC_SIZE0_TYPE      IMG_UINT16
+#define FW_DEVA_INIT_RENDEC_SIZE0_MASK      (0xFFFF)
+#define FW_DEVA_INIT_RENDEC_SIZE0_LSBMASK       (0xFFFF)
+#define FW_DEVA_INIT_RENDEC_SIZE0_OFFSET        (0x000C)
+#define FW_DEVA_INIT_RENDEC_SIZE0_SHIFT     (0)
+#define FW_DEVA_INIT_RENDEC_SIZE0_SIGNED_FIELD  IMG_FALSE
+
+#define MSVDX_RESET_NEEDS_REUPLOAD_FW          (0x2)
+#define MSVDX_RESET_NEEDS_INIT_FW              (0x1)
 
 /* This type defines the framework specified message ids */
 enum {
@@ -687,6 +688,8 @@ enum {
 
        VA_MSGID_DEBLOCK_MFLD = FWRK_MSGID_HOST_EMULATED,
        VA_MSGID_OOLD_MFLD,
+       VA_MSGID_TEST1_MFLD,
+       VA_MSGID_HOST_BE_OPP_MFLD,
        /*! Sent by the DXVA firmware on the MTX to the host.
         */
        VA_MSGID_CMD_COMPLETED = FWRK_MSGID_START_PSR_MTXHOST_MSG,
@@ -753,9 +756,15 @@ typedef struct {
        uint32_t address_a0;
        uint32_t address_a1;
        uint32_t mb_param_address;
+       uint32_t ext_stride_a;
+
        uint32_t address_b0;
        uint32_t address_b1;
        uint32_t rotation_flags;
+
+       /* additional msg outside of IMG msg */
+       uint32_t address_c0;
+       uint32_t address_c1;
 } FW_VA_DEBLOCK_MSG;
 
 typedef struct drm_psb_msvdx_frame_info {
@@ -770,7 +779,29 @@ typedef struct drm_psb_msvdx_frame_info {
        drm_psb_msvdx_decode_status_t decode_status;
 } drm_psb_msvdx_frame_info_t;
 
-#define MAX_DECODE_BUFFERS 24
+#define MAX_DECODE_BUFFERS (24)
+#define PSB_MAX_EC_INSTANCE (4)
+#define PSB_MSVDX_INVALID_FENCE (0xffffffff)
+#define PSB_MSVDX_INVALID_OFFSET (0xffffffff)
+#define PSB_MSVDX_EC_ROLLBACK (9)
+
+struct psb_msvdx_ec_ctx {
+       struct ttm_object_file *tfile; /* protected by cmdbuf_mutex */
+       uint32_t context_id;
+       drm_psb_msvdx_frame_info_t frame_info[MAX_DECODE_BUFFERS];
+       drm_psb_msvdx_frame_info_t *cur_frame_info;
+       int frame_idx;
+
+       /* 12 render msg + 1 deblock msg
+        * 12 * 20 + 1 * 48 = 288;
+       */
+       unsigned char unfenced_cmd[300];
+       uint32_t cmd_size;
+       uint32_t deblock_cmd_offset;
+       uint32_t fence;
+       drm_psb_msvdx_decode_status_t decode_status;
+};
+
 /* MSVDX private structure */
 struct msvdx_private {
        int msvdx_needs_reset;
@@ -782,6 +813,7 @@ struct msvdx_private {
        uint32_t msvdx_current_sequence;
        uint32_t msvdx_last_sequence;
 
+       struct drm_psb_private *dev_priv;
        /*
         *MSVDX Rendec Memory
         */
@@ -795,6 +827,14 @@ struct msvdx_private {
        uint32_t mtx_mem_size;
 
        /*
+        *MSVDX tile regions
+       */
+       uint32_t tile_region_start0;
+       uint32_t tile_region_end0;
+       uint32_t tile_region_start1;
+       uint32_t tile_region_end1;
+
+       /*
         *msvdx command queue
         */
        spinlock_t msvdx_lock;
@@ -824,7 +864,11 @@ struct msvdx_private {
        uint32_t ref_pic_fence;
        /*work for error concealment*/
        struct work_struct ec_work;
-       struct ttm_object_file *tfile;
+       struct ttm_object_file *tfile; /* protected by cmdbuf_mutex */
+       struct psb_msvdx_ec_ctx *msvdx_ec_ctx[PSB_MAX_EC_INSTANCE];
+       struct psb_msvdx_ec_ctx *cur_msvdx_ec_ctx;
+       uint32_t deblock_cmd_offset;
+
        struct drm_video_displaying_frameinfo displaying_frame;
 };
 
@@ -1395,6 +1439,10 @@ struct msvdx_private {
 
 #define FW_VA_LAST_SLICE_OF_EXT_DMA                                         0x00001000
 
+struct psb_msvdx_ec_ctx *psb_msvdx_find_ec_ctx(
+                       struct msvdx_private *msvdx_priv,
+                       void *cmd);
+
 static inline void psb_msvdx_clearirq(struct drm_device *dev)
 {
        struct drm_psb_private *dev_priv = dev->dev_private;
@@ -1437,3 +1485,5 @@ do {                                                                      \
 } while (0)
 
 #endif
+
+#define IS_FW_UPDATED 1
diff --git a/drivers/staging/mrst/imgv/psb_msvdx_ec.c b/drivers/staging/mrst/imgv/psb_msvdx_ec.c
new file mode 100644 (file)
index 0000000..905a06c
--- /dev/null
@@ -0,0 +1,511 @@
+/**
+ * file psb_msvdx_ec.c
+ * MSVDX error concealment I/O operations
+ *
+ */
+
+/**************************************************************************
+ *
+ * Copyright (c) 2007 Intel Corporation, Hillsboro, OR, USA
+ * Copyright (c) Imagination Technologies Limited, UK
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ **************************************************************************/
+
+#include "psb_drv.h"
+#include "psb_msvdx.h"
+#include "psb_msvdx_ec.h"
+
+static inline int psb_msvdx_cmd_port_write(struct drm_psb_private *dev_priv,
+                       uint32_t offset, uint32_t value, uint32_t *cmd_space)
+{
+       uint32_t max_attempts = 0xff;
+       uint32_t attempts = 0;
+
+       max_attempts = 0xff;
+       while (*cmd_space == 0) {
+               *cmd_space = PSB_RMSVDX32(
+                       MSVDX_CORE_CR_MSVDX_COMMAND_SPACE_OFFSET +
+                       MSVDX_CORE_BASE);
+               if (*cmd_space)
+                       break;
+               PSB_UDELAY(2);
+               attempts++;
+               if (attempts > max_attempts) {
+                       printk(KERN_ERR "MSVDX: poll cmd space timeout\n");
+                       return -1;
+               }
+       }
+
+       PSB_WMSVDX32(value, offset + MSVDX_CMDS_BASE);
+       (*cmd_space)--;
+       /*
+        *printk(KERN_DEBUG "MSVDX: poll cmd space attempts %d\n", attempts);
+       */
+       return 0;
+}
+
+#define PSB_CMDPORT_WRITE(_dev_priv_, _offset_, _cmd_, _cmd_space_)    \
+       do {                                                            \
+               ret = psb_msvdx_cmd_port_write(_dev_priv_,              \
+                                _offset_, _cmd_, &_cmd_space_);        \
+               if (ret) {                                              \
+                       printk(KERN_DEBUG "write cmd fail, abort\n");   \
+                       goto ec_done;                                   \
+               }                                                       \
+       } while (0);
+
+#define PSB_CMDPORT_WRITE_FAST(_dev_priv_, _offset_, _cmd_, _cmd_space_)  \
+       psb_msvdx_cmd_port_write(_dev_priv_,                            \
+                                _offset_, _cmd_, &_cmd_space_);        \
+
+void psb_msvdx_do_concealment(struct work_struct *work)
+{
+       struct msvdx_private *msvdx_priv =
+               container_of(work, struct msvdx_private, ec_work);
+       struct drm_psb_private *dev_priv = NULL;
+       struct psb_msvdx_ec_ctx *msvdx_ec_ctx = msvdx_priv->cur_msvdx_ec_ctx;
+       drm_psb_msvdx_decode_status_t *fault_region = NULL;
+       FW_VA_DEBLOCK_MSG *deblock_cmd =
+               (FW_VA_DEBLOCK_MSG *)(msvdx_ec_ctx->unfenced_cmd +
+               msvdx_ec_ctx->deblock_cmd_offset);
+       uint32_t width_in_mb, height_in_mb, cmd;
+       int conceal_above_row = 0, loop, mb_loop;
+       uint32_t cmd_space = 0;
+       int ret = 0;
+
+       if (!ospm_power_using_hw_begin(OSPM_VIDEO_DEC_ISLAND,
+                                      OSPM_UHB_FORCE_POWER_ON)) {
+               printk(KERN_ERR, "MSVDX: fail to power on ved for ec\n");
+               return;
+       }
+
+       dev_priv = msvdx_priv->dev_priv;
+       fault_region = &msvdx_ec_ctx->decode_status;
+
+       /* Concealment should be done in time,
+        * otherwise panic msg will be signaled in msvdx
+        */
+       preempt_disable();
+
+       if (msvdx_ec_ctx->deblock_cmd_offset == PSB_MSVDX_INVALID_OFFSET) {
+               printk(KERN_ERR "invalid msg offset, abort concealment\n");
+               goto ec_done;
+       }
+
+       if (fault_region->num_region == 0) {
+               PSB_DEBUG_MSVDX("no fault region\n");
+               goto ec_done;
+       }
+
+
+       width_in_mb = deblock_cmd->pic_size.bits.pic_width_mb;
+       height_in_mb = deblock_cmd->pic_size.bits.frame_height_mb;
+
+       {
+               int i;
+               for (i = 0; i < fault_region->num_region; i++)
+                       PSB_DEBUG_MSVDX("[region %d] is %d to %d\n",
+                                        i,
+                                        fault_region->mb_regions[i].start,
+                                        fault_region->mb_regions[i].end);
+
+               PSB_DEBUG_MSVDX("deblock header is      0x%08x\n",
+                                       deblock_cmd->header);
+               PSB_DEBUG_MSVDX("deblock flags is       0x%08x\n",
+                                       deblock_cmd->flags);
+               PSB_DEBUG_MSVDX("deblock op mode is     0x%08x\n",
+                                       deblock_cmd->operating_mode);
+               PSB_DEBUG_MSVDX("deblock mmu_contex     0x%08x\n",
+                                       deblock_cmd->mmu_context);
+               PSB_DEBUG_MSVDX("deblock pic_size is    0x%08x\n",
+                                       deblock_cmd->pic_size);
+               PSB_DEBUG_MSVDX("deblock addr_a0 is     0x%08x\n",
+                                       deblock_cmd->address_a0);
+               PSB_DEBUG_MSVDX("deblock addr_a1 is     0x%08x\n",
+                                       deblock_cmd->address_a1);
+               PSB_DEBUG_MSVDX("deblock mb_param is    0x%08x\n",
+                                       deblock_cmd->mb_param_address);
+               PSB_DEBUG_MSVDX("deblock stride_a is    0x%08x\n",
+                                       deblock_cmd->ext_stride_a);
+               PSB_DEBUG_MSVDX("deblock addr_b0 is     0x%08x\n",
+                                       deblock_cmd->address_b0);
+               PSB_DEBUG_MSVDX("deblock addr_b1 is     0x%08x\n",
+                                       deblock_cmd->address_b1);
+               PSB_DEBUG_MSVDX("deblock output_fg is   0x%08x\n",
+                                       deblock_cmd->rotation_flags);
+               PSB_DEBUG_MSVDX("deblock addr_c0 is     0x%08x\n",
+                                       deblock_cmd->address_c0);
+               PSB_DEBUG_MSVDX("deblock addr_c1 is     0x%08x\n",
+                                       deblock_cmd->address_c1);
+       }
+
+       cmd = 0;
+       REGIO_WRITE_FIELD_LITE(cmd, MSVDX_CMDS,
+                              DISPLAY_PICTURE_SIZE_DISPLAY_PICTURE_HEIGHT,
+                              (height_in_mb * 16) - 1);
+       REGIO_WRITE_FIELD_LITE(cmd, MSVDX_CMDS,
+                              DISPLAY_PICTURE_SIZE_DISPLAY_PICTURE_WIDTH,
+                              (width_in_mb * 16) - 1);
+       PSB_CMDPORT_WRITE(dev_priv,
+                                MSVDX_CMDS_DISPLAY_PICTURE_SIZE_OFFSET,
+                                cmd, cmd_space);
+
+       cmd = 0;
+       REGIO_WRITE_FIELD_LITE(cmd, MSVDX_CMDS,
+                              CODED_PICTURE_SIZE_CODED_PICTURE_HEIGHT,
+                              (height_in_mb * 16) - 1);
+       REGIO_WRITE_FIELD_LITE(cmd, MSVDX_CMDS,
+                              CODED_PICTURE_SIZE_CODED_PICTURE_WIDTH,
+                              (width_in_mb * 16) - 1);
+       PSB_CMDPORT_WRITE(dev_priv,
+                                MSVDX_CMDS_CODED_PICTURE_SIZE_OFFSET,
+                                cmd, cmd_space);
+
+       cmd = deblock_cmd->operating_mode;
+       REGIO_WRITE_FIELD(cmd, MSVDX_CMDS_OPERATING_MODE,
+                         CHROMA_FORMAT, 1);
+       REGIO_WRITE_FIELD(cmd, MSVDX_CMDS_OPERATING_MODE,
+                         ASYNC_MODE, 1);
+       REGIO_WRITE_FIELD(cmd, MSVDX_CMDS_OPERATING_MODE,
+                         CODEC_MODE, 3);
+       REGIO_WRITE_FIELD(cmd, MSVDX_CMDS_OPERATING_MODE,
+                         CODEC_PROFILE, 1);
+       PSB_CMDPORT_WRITE(dev_priv,
+                                MSVDX_CMDS_OPERATING_MODE_OFFSET,
+                                cmd, cmd_space);
+
+       /* dest frame address */
+       PSB_CMDPORT_WRITE(dev_priv,
+               MSVDX_CMDS_LUMA_RECONSTRUCTED_PICTURE_BASE_ADDRESSES_OFFSET,
+                                deblock_cmd->address_a0,
+                                cmd_space);
+
+       PSB_CMDPORT_WRITE(dev_priv,
+               MSVDX_CMDS_CHROMA_RECONSTRUCTED_PICTURE_BASE_ADDRESSES_OFFSET,
+                                deblock_cmd->address_a1,
+                                cmd_space);
+
+       /* conceal frame address */
+       PSB_CMDPORT_WRITE(dev_priv,
+               MSVDX_CMDS_REFERENCE_PICTURE_BASE_ADDRESSES_OFFSET,
+                                deblock_cmd->address_b0,
+                                cmd_space);
+       PSB_CMDPORT_WRITE(dev_priv,
+               MSVDX_CMDS_REFERENCE_PICTURE_BASE_ADDRESSES_OFFSET + 4,
+                                deblock_cmd->address_b1,
+                                cmd_space);
+       cmd = 0;
+       REGIO_WRITE_FIELD(cmd, MSVDX_CMDS_SLICE_PARAMS, SLICE_FIELD_TYPE, 2);
+       REGIO_WRITE_FIELD(cmd, MSVDX_CMDS_SLICE_PARAMS, SLICE_CODE_TYPE, 1);
+
+       PSB_CMDPORT_WRITE(dev_priv,
+                                MSVDX_CMDS_SLICE_PARAMS_OFFSET,
+                                cmd, cmd_space);
+
+       cmd = deblock_cmd->rotation_flags;
+       if ((cmd & 3) != 0) {
+               PSB_DEBUG_MSVDX("MSVDX: conceal to rotate surface\n");
+       } else {
+               PSB_CMDPORT_WRITE(dev_priv,
+                       MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_OFFSET,
+                                        cmd, cmd_space);
+
+               PSB_CMDPORT_WRITE(dev_priv,
+                       MSVDX_CMDS_VC1_LUMA_RANGE_MAPPING_BASE_ADDRESS_OFFSET,
+                                0, cmd_space);
+
+               PSB_CMDPORT_WRITE(dev_priv,
+                       MSVDX_CMDS_VC1_CHROMA_RANGE_MAPPING_BASE_ADDRESS_OFFSET,
+                                0, cmd_space);
+
+               PSB_CMDPORT_WRITE(dev_priv,
+                       MSVDX_CMDS_VC1_RANGE_MAPPING_FLAGS_OFFSET,
+                                0, cmd_space);
+       }
+
+       cmd = deblock_cmd->ext_stride_a;
+       PSB_CMDPORT_WRITE(dev_priv,
+                         MSVDX_CMDS_EXTENDED_ROW_STRIDE_OFFSET,
+                         cmd, cmd_space);
+
+       for (loop = 0; loop < fault_region->num_region; loop++) {
+
+               uint32_t start = fault_region->mb_regions[loop].start;
+               uint32_t end = fault_region->mb_regions[loop].end;
+               uint32_t x, y;
+
+               PSB_DEBUG_MSVDX("MSVDX: region(%d) is %d~%d\n",
+                       loop, start, end);
+
+               if (conceal_above_row)
+                       start -= width_in_mb;
+               if (end > (width_in_mb * height_in_mb - 1))
+                       end = (width_in_mb * height_in_mb - 1);
+               if (start > end)
+                       start = 0;
+
+               PSB_DEBUG_MSVDX("MSVDX: modify region(%d) is %d~%d\n",
+                       loop, start, end);
+
+               x = start % width_in_mb;
+               y = start / width_in_mb;
+
+               for (mb_loop = start; mb_loop <= end; mb_loop++, x++) {
+                       if (x >= width_in_mb) {
+                               x = 0;
+                               y++;
+                       }
+
+                       /* PSB_DEBUG_MSVDX("MSVDX: concleament (%d,%d)\n",
+                               x, y); */
+                       if ((x == 0) && (mb_loop != start))
+                               PSB_CMDPORT_WRITE_FAST(dev_priv,
+                                       MSVDX_CMDS_END_SLICE_PICTURE_OFFSET,
+                                       0, cmd_space);
+                       cmd = 0;
+                       REGIO_WRITE_FIELD_LITE(cmd,
+                                              MSVDX_CMDS_MACROBLOCK_NUMBER,
+                                              MB_CODE_TYPE, 1);
+                       REGIO_WRITE_FIELD_LITE(cmd,
+                                              MSVDX_CMDS_MACROBLOCK_NUMBER,
+                                              MB_NO_X, x);
+                       REGIO_WRITE_FIELD_LITE(cmd,
+                                              MSVDX_CMDS_MACROBLOCK_NUMBER,
+                                              MB_NO_Y, y);
+                       PSB_CMDPORT_WRITE_FAST(dev_priv,
+                               MSVDX_CMDS_MACROBLOCK_NUMBER_OFFSET,
+                               cmd, cmd_space);
+                       PSB_CMDPORT_WRITE_FAST(dev_priv,
+                               MSVDX_CMDS_MACROBLOCK_RESIDUAL_FORMAT_OFFSET,
+                               0, cmd_space);
+                       cmd = 0;
+                       REGIO_WRITE_FIELD_LITE(cmd,
+                                       MSVDX_CMDS_INTER_BLOCK_PREDICTION,
+                                              REF_INDEX_A_VALID, 1);
+                       REGIO_WRITE_FIELD_LITE(cmd,
+                                       MSVDX_CMDS_INTER_BLOCK_PREDICTION,
+                                              INTER_PRED_BLOCK_SIZE, 0);
+                       REGIO_WRITE_FIELD_LITE(cmd,
+                                       MSVDX_CMDS_INTER_BLOCK_PREDICTION,
+                                              REF_INDEX_A, 0);
+                       REGIO_WRITE_FIELD_LITE(cmd,
+                               MSVDX_CMDS_INTER_BLOCK_PREDICTION,
+                               REF_INDEX_B, 0);
+                       PSB_CMDPORT_WRITE_FAST(dev_priv,
+                               MSVDX_CMDS_INTER_BLOCK_PREDICTION_OFFSET,
+                               cmd, cmd_space);
+                       PSB_CMDPORT_WRITE_FAST(dev_priv,
+                               MSVDX_CMDS_MOTION_VECTOR_OFFSET,
+                               0, cmd_space);
+               }
+
+               PSB_CMDPORT_WRITE(dev_priv,
+                       MSVDX_CMDS_END_SLICE_PICTURE_OFFSET,
+                       0, cmd_space);
+       }
+
+
+ec_done:
+       /* try to unblock rendec */
+       ret = PSB_CMDPORT_WRITE_FAST(dev_priv,
+               MSVDX_CMDS_END_SLICE_PICTURE_OFFSET,
+               1, cmd_space);
+
+       ospm_power_using_hw_end(OSPM_VIDEO_DEC_ISLAND);
+
+       fault_region->num_region = 0;
+
+       preempt_enable();
+
+       printk(KERN_DEBUG "MSVDX: EC done, unlock msvdx ret %d\n",
+              ret);
+
+       return;
+}
+
+struct psb_msvdx_ec_ctx *psb_msvdx_find_ec_ctx(
+                       struct msvdx_private *msvdx_priv,
+                       void *cmd)
+{
+       int i, free_idx;
+       struct psb_msvdx_ec_ctx *ec_ctx = NULL;
+       FW_VA_DEBLOCK_MSG *deblock_msg = (FW_VA_DEBLOCK_MSG *)cmd;
+
+       free_idx = -1;
+       for (i = 0; i < PSB_MAX_EC_INSTANCE; i++) {
+               if (msvdx_priv->msvdx_ec_ctx[i]->tfile == msvdx_priv->tfile)
+                       break;
+               else if (free_idx < 0 &&
+                        msvdx_priv->msvdx_ec_ctx[i]->tfile == NULL)
+                       free_idx = i;
+       }
+
+       if (i < PSB_MAX_EC_INSTANCE)
+               ec_ctx = msvdx_priv->msvdx_ec_ctx[i];
+       else if (free_idx >= 0 && cmd) {
+               PSB_DEBUG_MSVDX("acquire ec ctx idx %d for tfile 8x%08x\n",
+                               free_idx, msvdx_priv->tfile);
+               ec_ctx = msvdx_priv->msvdx_ec_ctx[free_idx];
+               memset(ec_ctx, 0, sizeof(*ec_ctx));
+               ec_ctx->tfile = msvdx_priv->tfile;
+               ec_ctx->context_id = deblock_msg->mmu_context.bits.context;
+       } else {
+               PSB_DEBUG_MSVDX("Available ec ctx is not found\n");
+       }
+
+       return ec_ctx;
+}
+
+void psb_msvdx_update_frame_info(struct msvdx_private *msvdx_priv,
+                                       void *cmd)
+{
+
+       uint8_t context_id;
+       int i, free_idx;
+       drm_psb_msvdx_frame_info_t *frame_info;
+       FW_VA_DEBLOCK_MSG *deblock_msg = (FW_VA_DEBLOCK_MSG *)cmd;
+       uint32_t buffer_handle = deblock_msg->mb_param_address;
+
+       struct psb_msvdx_ec_ctx *ec_ctx;
+
+       PSB_DEBUG_MSVDX("update frame info for ved error concealment\n");
+
+       ec_ctx = psb_msvdx_find_ec_ctx(msvdx_priv, cmd);
+
+       if (!ec_ctx)
+               return;
+
+       free_idx = -1;
+       for (i = 0; i < MAX_DECODE_BUFFERS; i++) {
+               if (buffer_handle == ec_ctx->frame_info[i].handle)
+                       break;
+               if (free_idx < 0 && ec_ctx->frame_info[i].handle == NULL)
+                       free_idx = i;
+       }
+
+       if (i < MAX_DECODE_BUFFERS)
+               frame_info = &ec_ctx->frame_info[i];
+       else if (free_idx >= 0) {
+               PSB_DEBUG_MSVDX("acquire frame_info solt idx %d\n", free_idx);
+               frame_info = &ec_ctx->frame_info[free_idx];
+       } else {
+               PSB_DEBUG_MSVDX("%d solts occupied, abort update frame_info\n",
+                               MAX_DECODE_BUFFERS);
+               return;
+       }
+
+       frame_info->fw_status = 0;
+       frame_info->handle = buffer_handle;
+       frame_info->fence = (deblock_msg->header.bits.msg_fence & 0xf);
+       ec_ctx->cur_frame_info = frame_info;
+}
+
+void psb_msvdx_backup_cmd(struct msvdx_private *msvdx_priv,
+                               void *cmd,
+                               uint32_t cmd_size,
+                               uint32_t deblock_cmd_offset)
+{
+       FW_VA_DEBLOCK_MSG *deblock_msg = NULL;
+
+       struct psb_msvdx_ec_ctx *ec_ctx;
+
+       PSB_DEBUG_MSVDX("backup cmd for ved error concealment\n");
+
+       ec_ctx = psb_msvdx_find_ec_ctx(msvdx_priv, NULL);
+
+       if (!ec_ctx) {
+               PSB_DEBUG_MSVDX("this is not a ec ctx, abort backup cmd\n");
+               return;
+       }
+
+
+       if (deblock_cmd_offset != PSB_MSVDX_INVALID_OFFSET)
+               deblock_msg = (FW_VA_DEBLOCK_MSG *)(cmd + deblock_cmd_offset);
+
+       if (deblock_msg &&
+           ec_ctx->context_id != deblock_msg->mmu_context.bits.context) {
+               PSB_DEBUG_MSVDX("backup cmd but find mis-match context id\n");
+               return;
+       }
+
+       ec_ctx->cmd_size = cmd_size;
+       ec_ctx->deblock_cmd_offset = deblock_cmd_offset;
+       memcpy(ec_ctx->unfenced_cmd, cmd, cmd_size);
+       ec_ctx->fence = PSB_MSVDX_INVALID_FENCE;
+       if (cmd_size)
+               ec_ctx->fence =
+                       MEMIO_READ_FIELD(ec_ctx->unfenced_cmd,
+                                       FW_VA_CMD_COMPLETED_MSG_ID);
+       ec_ctx->fence &= (~0xf);
+       PSB_DEBUG_MSVDX("backup cmd for ved: fence 0x%08x, cmd_size %d\n",
+                               ec_ctx->fence, cmd_size);
+}
+
+void psb_msvdx_mtx_message_dump(struct drm_device *dev)
+{
+       struct drm_psb_private *dev_priv =
+               (struct drm_psb_private *)dev->dev_private;
+
+       int i, buf_size, buf_offset;
+       buf_size = PSB_RMSVDX32(MSVDX_COMMS_TO_HOST_BUF_SIZE) & ((1 << 16) - 1);
+       buf_offset =
+               (PSB_RMSVDX32(MSVDX_COMMS_TO_HOST_BUF_SIZE) >> 16) + 0x2000;
+
+       printk(KERN_DEBUG "Dump to HOST message buffer (offset:size)%04x:%04x\n",
+              buf_offset, buf_size);
+       for (i = 0; i < buf_size; i += 4) {
+               uint32_t reg1, reg2, reg3, reg4;
+               reg1 = PSB_RMSVDX32(buf_offset + i * 4);
+               reg2 = PSB_RMSVDX32(buf_offset + i * 4 + 4);
+               reg3 = PSB_RMSVDX32(buf_offset + i * 4 + 8);
+               reg4 = PSB_RMSVDX32(buf_offset + i * 4 + 12);
+               printk(KERN_DEBUG "0x%04x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                      (buf_offset + i * 4), reg1, reg2, reg3, reg4);
+       }
+
+       buf_size = PSB_RMSVDX32(MSVDX_COMMS_TO_MTX_BUF_SIZE) & ((1 << 16) - 1);
+       buf_offset = (PSB_RMSVDX32(MSVDX_COMMS_TO_MTX_BUF_SIZE) >> 16) + 0x2000;
+
+       printk(KERN_DEBUG "Dump to MTX message buffer (offset:size)%04x:%04x\n",
+              buf_offset, buf_size);
+       for (i = 0; i < buf_size; i += 4) {
+               uint32_t reg1, reg2, reg3, reg4;
+               reg1 = PSB_RMSVDX32(buf_offset + i * 4);
+               reg2 = PSB_RMSVDX32(buf_offset + i * 4 + 4);
+               reg3 = PSB_RMSVDX32(buf_offset + i * 4 + 8);
+               reg4 = PSB_RMSVDX32(buf_offset + i * 4 + 12);
+               printk(KERN_DEBUG "0x%04x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                      (buf_offset + i * 4), reg1, reg2, reg3, reg4);
+       }
+
+       buf_size = 12;
+       buf_offset = 0xFD0 + 0x2000;
+
+       printk(KERN_DEBUG "Comm header (offset:size)%04x:%04x\n",
+              buf_offset, buf_size);
+       for (i = 0; i < buf_size; i += 4) {
+               uint32_t reg1, reg2, reg3, reg4;
+               reg1 = PSB_RMSVDX32(buf_offset + i * 4);
+               reg2 = PSB_RMSVDX32(buf_offset + i * 4 + 4);
+               reg3 = PSB_RMSVDX32(buf_offset + i * 4 + 8);
+               reg4 = PSB_RMSVDX32(buf_offset + i * 4 + 12);
+               printk(KERN_DEBUG "0x%04x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                      (buf_offset + i * 4), reg1, reg2, reg3, reg4);
+       }
+
+       printk(KERN_DEBUG "Error status 0x2cc4: 0x%08x\n",
+              PSB_RMSVDX32(0x2cc4));
+}
diff --git a/drivers/staging/mrst/imgv/psb_msvdx_ec.h b/drivers/staging/mrst/imgv/psb_msvdx_ec.h
new file mode 100644 (file)
index 0000000..5e3285d
--- /dev/null
@@ -0,0 +1,172 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2012 Intel Corporation, Hillsboro, OR, USA
+ * Copyright (c) Imagination Technologies Limited, UK
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ **************************************************************************/
+
+#ifndef _PSB_MSVDX_EC_H_
+#define _PSB_MSVDX_EC_H_
+
+#define MSVDX_CMDS_BASE 0x1000
+#define MSVDX_CMDS_DISPLAY_PICTURE_SIZE_OFFSET (0x0000)
+
+/* MSVDX_CMDS, DISPLAY_PICTURE_SIZE, DISPLAY_PICTURE_HEIGHT */
+#define MSVDX_CMDS_DISPLAY_PICTURE_SIZE_DISPLAY_PICTURE_HEIGHT_MASK (0x00FFF000)
+#define MSVDX_CMDS_DISPLAY_PICTURE_SIZE_DISPLAY_PICTURE_HEIGHT_SHIFT (12)
+
+/* MSVDX_CMDS, DISPLAY_PICTURE_SIZE, DISPLAY_PICTURE_WIDTH */
+#define MSVDX_CMDS_DISPLAY_PICTURE_SIZE_DISPLAY_PICTURE_WIDTH_MASK (0x00000FFF)
+#define MSVDX_CMDS_DISPLAY_PICTURE_SIZE_DISPLAY_PICTURE_WIDTH_SHIFT (0)
+
+#define MSVDX_CMDS_CODED_PICTURE_SIZE_OFFSET (0x0004)
+
+/* MSVDX_CMDS, CODED_PICTURE_SIZE, CODED_PICTURE_HEIGHT */
+#define MSVDX_CMDS_CODED_PICTURE_SIZE_CODED_PICTURE_HEIGHT_MASK (0x00FFF000)
+#define MSVDX_CMDS_CODED_PICTURE_SIZE_CODED_PICTURE_HEIGHT_SHIFT (12)
+
+/* MSVDX_CMDS, CODED_PICTURE_SIZE, CODED_PICTURE_WIDTH */
+#define MSVDX_CMDS_CODED_PICTURE_SIZE_CODED_PICTURE_WIDTH_MASK (0x00000FFF)
+#define MSVDX_CMDS_CODED_PICTURE_SIZE_CODED_PICTURE_WIDTH_SHIFT (0)
+
+#define MSVDX_CMDS_OPERATING_MODE_OFFSET (0x0008)
+
+/* MSVDX_CMDS, OPERATING_MODE, RPR_ENABLE */
+#define MSVDX_CMDS_OPERATING_MODE_RPR_ENABLE_MASK (0x20000000)
+#define MSVDX_CMDS_OPERATING_MODE_RPR_ENABLE_SHIFT (29)
+
+/* MSVDX_CMDS, OPERATING_MODE, USE_EXT_ROW_STRIDE */
+#define MSVDX_CMDS_OPERATING_MODE_USE_EXT_ROW_STRIDE_MASK (0x10000000)
+#define MSVDX_CMDS_OPERATING_MODE_USE_EXT_ROW_STRIDE_SHIFT (28)
+
+/* MSVDX_CMDS, OPERATING_MODE, CHROMA_INTERLEAVED */
+#define MSVDX_CMDS_OPERATING_MODE_CHROMA_INTERLEAVED_MASK (0x08000000)
+#define MSVDX_CMDS_OPERATING_MODE_CHROMA_INTERLEAVED_SHIFT (27)
+/* MSVDX_CMDS, OPERATING_MODE, ROW_STRIDE */
+#define MSVDX_CMDS_OPERATING_MODE_ROW_STRIDE_MASK (0x07000000)
+#define MSVDX_CMDS_OPERATING_MODE_ROW_STRIDE_SHIFT (24)
+
+/* MSVDX_CMDS, OPERATING_MODE, CODEC_PROFILE */
+#define MSVDX_CMDS_OPERATING_MODE_CODEC_PROFILE_MASK (0x00300000)
+#define MSVDX_CMDS_OPERATING_MODE_CODEC_PROFILE_SHIFT (20)
+
+/* MSVDX_CMDS, OPERATING_MODE, CODEC_MODE */
+#define MSVDX_CMDS_OPERATING_MODE_CODEC_MODE_MASK (0x000F0000)
+#define MSVDX_CMDS_OPERATING_MODE_CODEC_MODE_SHIFT (16)
+
+/* MSVDX_CMDS, OPERATING_MODE, ASYNC_MODE */
+#define MSVDX_CMDS_OPERATING_MODE_ASYNC_MODE_MASK (0x00006000)
+#define MSVDX_CMDS_OPERATING_MODE_ASYNC_MODE_SHIFT (13)
+
+/* MSVDX_CMDS, OPERATING_MODE, CHROMA_FORMAT */
+#define MSVDX_CMDS_OPERATING_MODE_CHROMA_FORMAT_MASK (0x00001000)
+#define MSVDX_CMDS_OPERATING_MODE_CHROMA_FORMAT_SHIFT (12)
+
+/* MSVDX_CMDS, OPERATING_MODE, INTERLACED */
+#define MSVDX_CMDS_OPERATING_MODE_INTERLACED_MASK (0x00000800)
+#define MSVDX_CMDS_OPERATING_MODE_INTERLACED_SHIFT (11)
+
+/* MSVDX_CMDS, OPERATING_MODE, OVERLAP */
+#define MSVDX_CMDS_OPERATING_MODE_OVERLAP_MASK (0x00000400)
+#define MSVDX_CMDS_OPERATING_MODE_OVERLAP_SHIFT (10)
+
+/* MSVDX_CMDS, OPERATING_MODE, PIC_CONDOVER */
+#define MSVDX_CMDS_OPERATING_MODE_PIC_CONDOVER_MASK (0x00000300)
+#define MSVDX_CMDS_OPERATING_MODE_PIC_CONDOVER_SHIFT (8)
+/* MSVDX_CMDS, OPERATING_MODE, DEBLOCK_STRENGTH */
+#define MSVDX_CMDS_OPERATING_MODE_DEBLOCK_STRENGTH_MASK (0x000000E0)
+#define MSVDX_CMDS_OPERATING_MODE_DEBLOCK_STRENGTH_SHIFT (5)
+
+/* MSVDX_CMDS, OPERATING_MODE, PIC_QUANT */
+#define MSVDX_CMDS_OPERATING_MODE_PIC_QUANT_MASK (0x0000001F)
+#define MSVDX_CMDS_OPERATING_MODE_PIC_QUANT_SHIFT (0)
+
+#define MSVDX_CMDS_LUMA_RECONSTRUCTED_PICTURE_BASE_ADDRESSES_OFFSET (0x000C)
+#define MSVDX_CMDS_CHROMA_RECONSTRUCTED_PICTURE_BASE_ADDRESSES_OFFSET (0x0010)
+
+#define MSVDX_CMDS_REFERENCE_PICTURE_BASE_ADDRESSES_OFFSET (0x0100)
+
+#define MSVDX_CMDS_SLICE_PARAMS_OFFSET (0x0400)
+
+/* MSVDX_CMDS, SLICE_PARAMS, SLICE_FIELD_TYPE */
+#define MSVDX_CMDS_SLICE_PARAMS_SLICE_FIELD_TYPE_MASK (0x0000000C)
+#define MSVDX_CMDS_SLICE_PARAMS_SLICE_FIELD_TYPE_SHIFT (2)
+
+
+/* MSVDX_CMDS, SLICE_PARAMS, SLICE_CODE_TYPE */
+#define MSVDX_CMDS_SLICE_PARAMS_SLICE_CODE_TYPE_MASK (0x00000003)
+#define MSVDX_CMDS_SLICE_PARAMS_SLICE_CODE_TYPE_SHIFT (0)
+
+#define MSVDX_CMDS_ALTERNATIVE_OUTPUT_PICTURE_ROTATION_OFFSET (0x003C)
+
+#define MSVDX_CMDS_VC1_LUMA_RANGE_MAPPING_BASE_ADDRESS_OFFSET (0x0028)
+#define MSVDX_CMDS_VC1_CHROMA_RANGE_MAPPING_BASE_ADDRESS_OFFSET (0x002C)
+#define MSVDX_CMDS_VC1_RANGE_MAPPING_FLAGS_OFFSET (0x0030)
+
+#define MSVDX_CMDS_EXTENDED_ROW_STRIDE_OFFSET (0x0040)
+
+#define MSVDX_CMDS_END_SLICE_PICTURE_OFFSET (0x0404)
+
+#define MSVDX_CMDS_MACROBLOCK_NUMBER_OFFSET (0x0408)
+
+/* MSVDX_CMDS, MACROBLOCK_NUMBER, MB_CODE_TYPE */
+#define MSVDX_CMDS_MACROBLOCK_NUMBER_MB_CODE_TYPE_MASK (0x00030000)
+#define MSVDX_CMDS_MACROBLOCK_NUMBER_MB_CODE_TYPE_SHIFT (16)
+
+/* MSVDX_CMDS, MACROBLOCK_NUMBER, MB_NO_Y */
+#define MSVDX_CMDS_MACROBLOCK_NUMBER_MB_NO_Y_MASK (0x0000FF00)
+#define MSVDX_CMDS_MACROBLOCK_NUMBER_MB_NO_Y_SHIFT (8)
+
+/* MSVDX_CMDS, MACROBLOCK_NUMBER, MB_NO_X */
+#define MSVDX_CMDS_MACROBLOCK_NUMBER_MB_NO_X_MASK (0x000000FF)
+#define MSVDX_CMDS_MACROBLOCK_NUMBER_MB_NO_X_SHIFT (0)
+
+#define MSVDX_CMDS_MACROBLOCK_RESIDUAL_FORMAT_OFFSET (0x0418)
+
+#define MSVDX_CMDS_INTER_BLOCK_PREDICTION_OFFSET (0x0430)
+
+/* MSVDX_CMDS, INTER_BLOCK_PREDICTION, REF_INDEX_A_VALID */
+#define MSVDX_CMDS_INTER_BLOCK_PREDICTION_REF_INDEX_A_VALID_MASK (0x00000020)
+#define MSVDX_CMDS_INTER_BLOCK_PREDICTION_REF_INDEX_A_VALID_SHIFT (5)
+
+/* MSVDX_CMDS, INTER_BLOCK_PREDICTION, INTER_PRED_BLOCK_SIZE */
+#define MSVDX_CMDS_INTER_BLOCK_PREDICTION_INTER_PRED_BLOCK_SIZE_MASK (0x70000)
+#define MSVDX_CMDS_INTER_BLOCK_PREDICTION_INTER_PRED_BLOCK_SIZE_SHIFT (16)
+
+/* MSVDX_CMDS, INTER_BLOCK_PREDICTION, REF_INDEX_A */
+#define MSVDX_CMDS_INTER_BLOCK_PREDICTION_REF_INDEX_A_MASK (0x0000000F)
+#define MSVDX_CMDS_INTER_BLOCK_PREDICTION_REF_INDEX_A_SHIFT (0)
+
+/* MSVDX_CMDS, INTER_BLOCK_PREDICTION, REF_INDEX_B */
+#define MSVDX_CMDS_INTER_BLOCK_PREDICTION_REF_INDEX_B_MASK (0x00000F00)
+#define MSVDX_CMDS_INTER_BLOCK_PREDICTION_REF_INDEX_B_SHIFT (8)
+
+#define MSVDX_CMDS_MOTION_VECTOR_OFFSET (0x0500)
+
+#define MSVDX_CORE_CR_MSVDX_COMMAND_SPACE_OFFSET (0x0028)
+
+#define MSVDX_CORE_BASE        (0x600)
+
+void psb_msvdx_update_frame_info(struct msvdx_private *msvdx_priv,
+                                       void *cmd);
+void psb_msvdx_backup_cmd(struct msvdx_private *msvdx_priv,
+                               void *cmd,
+                               uint32_t cmd_size,
+                               uint32_t deblock_cmd_offset);
+
+void psb_msvdx_mtx_message_dump(struct drm_device *dev);
+void psb_msvdx_do_concealment(struct work_struct *work);
+#endif
index 4a15c37..2183492 100644 (file)
@@ -24,6 +24,7 @@
 #include <drm/drm.h>
 #include "psb_drv.h"
 #include "psb_msvdx.h"
+#include "psb_msvdx_ec.h"
 #include <linux/firmware.h>
 
 #define MSVDX_REG (dev_priv->msvdx_reg)
@@ -33,7 +34,7 @@
 #define UNINITILISE_MEM        ( 0xcdcdcdcd )
 #define FIRMWAREID             ( 0x014d42ab )
 
-static uint8_t psb_rev_id;
+uint8_t psb_rev_id;
 /*MSVDX FW header*/
 struct msvdx_fw {
        uint32_t ver;
@@ -68,7 +69,7 @@ int psb_wait_for_register(struct drm_psb_private *dev_priv,
        return 1;
 }
 
-static int psb_poll_mtx_irq(struct drm_psb_private *dev_priv)
+int psb_poll_mtx_irq(struct drm_psb_private *dev_priv)
 {
        int ret = 0;
        uint32_t mtx_int = 0;
@@ -96,7 +97,7 @@ static int psb_poll_mtx_irq(struct drm_psb_private *dev_priv)
        return ret;
 }
 
-static void psb_write_mtx_core_reg(struct drm_psb_private *dev_priv,
+void psb_write_mtx_core_reg(struct drm_psb_private *dev_priv,
                            const uint32_t core_reg, const uint32_t val)
 {
        uint32_t reg = 0;
@@ -153,8 +154,6 @@ static void psb_release_mtx_control_from_dash(struct drm_psb_private *dev_priv)
        PSB_WMSVDX32(0x4, MSVDX_MTX_DEBUG);
 }
 
-
-
 static void psb_upload_fw(struct drm_psb_private *dev_priv,
                          uint32_t address, const unsigned int words, int fw_sel)
 {
@@ -252,6 +251,7 @@ static void psb_upload_fw(struct drm_psb_private *dev_priv,
        }
 
        psb_release_mtx_control_from_dash(dev_priv);
+
        PSB_DEBUG_GENERAL("MSVDX: Upload done\n");
 }
 
@@ -438,6 +438,32 @@ static int msvdx_get_fw_bo(struct drm_device *dev,
                *last_word = STACKGUARDWORD;
        }
 
+       if (IS_MRST(dev) && (fw_size < (*raw)->size)) {
+               uint32_t *last_word;
+
+               PSB_DEBUG_GENERAL("MSVDX: store error-concealment firmware\n");
+
+               ptr += ((fw_size + 0xfff) & ~0xfff);
+               gpu_addr += ((msvdx_priv->mtx_mem_size + 8192) & ~0xfff);
+
+               if (((struct msvdx_fw *) ptr)->ver != 0x4ae) {
+                       PSB_DEBUG_GENERAL("MSVDX: Error concealment firmware has wrong version num\n");
+                       PSB_DEBUG_GENERAL("MSVDX: Abort store Error concealment firmware\n");
+               } else {
+                       memset(gpu_addr, UNINITILISE_MEM, msvdx_priv->mtx_mem_size);
+
+                       memcpy(gpu_addr, ptr + sizeof(struct msvdx_fw),
+                              sizeof(uint32_t) *((struct msvdx_fw *) ptr)->text_size);
+
+                       memcpy(gpu_addr + (((struct msvdx_fw *) ptr)->data_location - MSVDX_MTX_DATA_LOCATION),
+                              (void *)ptr + sizeof(struct msvdx_fw) + sizeof(uint32_t) *((struct msvdx_fw *) ptr)->text_size,
+                              sizeof(uint32_t) *((struct msvdx_fw *) ptr)->data_size);
+
+                       last_word = (uint32_t *)(gpu_addr + msvdx_priv->mtx_mem_size - 4);
+                       *last_word = STACKGUARDWORD;
+               }
+       }
+
        ttm_bo_kunmap(&tmp_kmap);
        PSB_DEBUG_GENERAL("MSVDX: releasing firmware resouces\n");
        PSB_DEBUG_GENERAL("MSVDX: Load firmware into BO successfully\n");
@@ -514,6 +540,7 @@ int psb_setup_fw(struct drm_device *dev)
 
        /* todo : Assert the clock is on - if not turn it on to upload code */
        PSB_DEBUG_GENERAL("MSVDX: psb_setup_fw\n");
+
        PSB_WMSVDX32(clk_enable_all, MSVDX_MAN_CLK_ENABLE);
 
        if (!IS_D0(dev)) {
@@ -537,7 +564,9 @@ int psb_setup_fw(struct drm_device *dev)
          }
        */
 
-       PSB_WMSVDX32(FIRMWAREID, MSVDX_COMMS_FIRMWARE_ID);
+       if (IS_MDFLD(dev)) {
+               PSB_WMSVDX32(FIRMWAREID, MSVDX_COMMS_FIRMWARE_ID);
+       }
 
        if (!IS_D0(dev)) {
                PSB_WMSVDX32(0, MSVDX_COMMS_ERROR_TRIG);
@@ -559,6 +588,12 @@ int psb_setup_fw(struct drm_device *dev)
                /* we should restore the state, if we power down/up
                 * during EC */
                PSB_WMSVDX32(0, MSVDX_EXT_FW_ERROR_STATE); /* EXT_FW_ERROR_STATE */
+               PSB_WMSVDX32(0, MSVDX_COMMS_MSG_COUNTER);
+               PSB_WMSVDX32(0, 0x2000 + 0xcc4); /* EXT_FW_ERROR_STATE */
+               PSB_WMSVDX32(0, 0x2000 + 0xcb0); /* EXT_FW_LAST_MBS */
+               PSB_WMSVDX32(0, 0x2000 + 0xcb4); /* EXT_FW_LAST_MBS */
+               PSB_WMSVDX32(0, 0x2000 + 0xcb8); /* EXT_FW_LAST_MBS */
+               PSB_WMSVDX32(0, 0x2000 + 0xcbc); /* EXT_FW_LAST_MBS */
        }
        /* read register bank size */
        {
@@ -581,100 +616,134 @@ int psb_setup_fw(struct drm_device *dev)
         const struct firmware *raw = NULL;
         int ec_firmware = 0;
 
-       /* if FW already loaded from storage */
-       if (msvdx_priv->msvdx_fw)
-               fw_ptr = msvdx_priv->msvdx_fw;
-       else {
-               fw_ptr = msvdx_get_fw(dev, &raw, "msvdx_fw_mfld_DE2.0.bin");
-
-               PSB_DEBUG_GENERAL("MSVDX:load msvdx_fw_mfld_DE2.0.bin by udevd\n");
-       }
-
-       if (!fw_ptr) {
-               DRM_ERROR("MSVDX:load msvdx_fw.bin failed,is udevd running?\n");
-               ret = 1;
-               goto out;
-       }
-
-       if (!msvdx_priv->is_load) {/* Load firmware into BO */
-               PSB_DEBUG_GENERAL("MSVDX:load msvdx_fw.bin by udevd into BO\n");
-               ret = msvdx_get_fw_bo(dev, &raw, "msvdx_fw_mfld_DE2.0.bin");
-               msvdx_priv->is_load = 1;
-       }
-
-
-       fw = (struct msvdx_fw *) fw_ptr;
-
-       if (ec_firmware) {
-               fw_ptr += (((sizeof(struct msvdx_fw) + (fw->text_size + fw->data_size) * 4 + 0xfff) & ~0xfff) / sizeof(uint32_t));
-               fw = (struct msvdx_fw *) fw_ptr;
-       }
+        /* load error concealment firmware? */
+        if (IS_MRST(dev) && dev_priv->last_msvdx_ctx &&
+                       (((dev_priv->last_msvdx_ctx->ctx_type >> 8) & 0xff) ==
+                       VAProfileH264ConstrainedBaseline)) {
+            ec_firmware = 1;
+            PSB_DEBUG_INIT("MSVDX: load error concealment firmware\n");
+        }
+
+       /* if FW already loaded from storage */
+       if (msvdx_priv->msvdx_fw)
+               fw_ptr = msvdx_priv->msvdx_fw;
+       else {
+               if (IS_MRST(dev)) {
+                       fw_ptr = msvdx_get_fw(dev, &raw, "msvdx_fw.bin");
+                       PSB_DEBUG_GENERAL("MSVDX:load msvdx_fw.bin by udevd\n");
+               } else if (IS_MDFLD(dev)) {
+                       if (IS_FW_UPDATED)
+                               fw_ptr = msvdx_get_fw(dev, &raw, "msvdx_fw_mfld_DE2.0.bin");
+                       else
+                               fw_ptr = msvdx_get_fw(dev, &raw, "msvdx_fw_mfld.bin");
+
+                       PSB_DEBUG_GENERAL("MSVDX:load msvdx_fw_mfld_DE2.0.bin by udevd\n");
+               } else
+                       DRM_ERROR("MSVDX:HW is neither mrst nor mfld\n");
+       }
+
+       if (!fw_ptr) {
+               DRM_ERROR("MSVDX:load msvdx_fw.bin failed,is udevd running?\n");
+               ret = 1;
+               goto out;
+       }
+
+       if (!msvdx_priv->is_load) {/* Load firmware into BO */
+               PSB_DEBUG_GENERAL("MSVDX:load msvdx_fw.bin by udevd into BO\n");
+               if (IS_MRST(dev))
+                       ret = msvdx_get_fw_bo(dev, &raw, "msvdx_fw.bin");
+               else if (IS_MDFLD(dev)) {
+                       if (IS_FW_UPDATED)
+                               ret = msvdx_get_fw_bo(dev, &raw, "msvdx_fw_mfld_DE2.0.bin");
+                       else
+                               ret = msvdx_get_fw_bo(dev, &raw, "msvdx_fw_mfld.bin");
+               } else
+                       DRM_ERROR("MSVDX:HW is neither mrst nor mfld\n");
+               msvdx_priv->is_load = 1;
+       }
+
+
+       fw = (struct msvdx_fw *) fw_ptr;
+
+       if (ec_firmware) {
+               fw_ptr += (((sizeof(struct msvdx_fw) + (fw->text_size + fw->data_size) * 4 + 0xfff) & ~0xfff) / sizeof(uint32_t));
+               fw = (struct msvdx_fw *) fw_ptr;
+       }
+
+        /*
+            if (fw->ver != 0x02) {
+                DRM_ERROR("psb: msvdx_fw.bin firmware version mismatch,"
+                    "got version=%02x expected version=%02x\n",
+                    fw->ver, 0x02);
+                ret = 1;
+                goto out;
+            }
+            */
+       text_ptr =
+               (uint32_t *)((uint8_t *) fw_ptr + sizeof(struct msvdx_fw));
+       data_ptr = text_ptr + fw->text_size;
+
+       if (fw->text_size == 2858)
+               PSB_DEBUG_GENERAL(
+                       "MSVDX: FW ver 1.00.10.0187 of SliceSwitch variant\n");
+       else if (fw->text_size == 3021)
+               PSB_DEBUG_GENERAL(
+                       "MSVDX: FW ver 1.00.10.0187 of FrameSwitch variant\n");
+       else if (fw->text_size == 2841)
+               PSB_DEBUG_GENERAL("MSVDX: FW ver 1.00.10.0788\n");
+       else if (fw->text_size == 3147)
+               PSB_DEBUG_GENERAL("MSVDX: FW ver BUILD_DXVA_FW1.00.10.1042 of SliceSwitch variant\n");
+       else if (fw->text_size == 3097)
+               PSB_DEBUG_GENERAL("MSVDX: FW ver BUILD_DXVA_FW1.00.10.0963.02.0011 of FrameSwitch variant\n");
+       else
+               PSB_DEBUG_GENERAL("MSVDX: FW ver unknown\n");
+
+
+       PSB_DEBUG_GENERAL("MSVDX: Retrieved pointers for firmware\n");
+       PSB_DEBUG_GENERAL("MSVDX: text_size: %d\n", fw->text_size);
+       PSB_DEBUG_GENERAL("MSVDX: data_size: %d\n", fw->data_size);
+       PSB_DEBUG_GENERAL("MSVDX: data_location: 0x%x\n",
+                         fw->data_location);
+       PSB_DEBUG_GENERAL("MSVDX: First 4 bytes of text: 0x%x\n",
+                         *text_ptr);
+       PSB_DEBUG_GENERAL("MSVDX: First 4 bytes of data: 0x%x\n",
+                         *data_ptr);
+
+       PSB_DEBUG_GENERAL("MSVDX: Uploading firmware\n");
 
-       /*
-         if (fw->ver != 0x02) {
-         DRM_ERROR("psb: msvdx_fw.bin firmware version mismatch,"
-         "got version=%02x expected version=%02x\n",
-         fw->ver, 0x02);
-         ret = 1;
-         goto out;
-         }
-       */
-       text_ptr =
-               (uint32_t *)((uint8_t *) fw_ptr + sizeof(struct msvdx_fw));
-       data_ptr = text_ptr + fw->text_size;
-
-       if (fw->text_size == 2858)
-               PSB_DEBUG_GENERAL(
-                       "MSVDX: FW ver 1.00.10.0187 of SliceSwitch variant\n");
-       else if (fw->text_size == 3021)
-               PSB_DEBUG_GENERAL(
-                       "MSVDX: FW ver 1.00.10.0187 of FrameSwitch variant\n");
-       else if (fw->text_size == 2841)
-               PSB_DEBUG_GENERAL("MSVDX: FW ver 1.00.10.0788\n");
-       else if (fw->text_size == 3147)
-               PSB_DEBUG_GENERAL("MSVDX: FW ver BUILD_DXVA_FW1.00.10.1042 of SliceSwitch variant\n");
-       else if (fw->text_size == 3097)
-               PSB_DEBUG_GENERAL("MSVDX: FW ver BUILD_DXVA_FW1.00.10.0963.02.0011 of FrameSwitch variant\n");
-       else
-               PSB_DEBUG_GENERAL("MSVDX: FW ver unknown\n");
-
-
-       PSB_DEBUG_GENERAL("MSVDX: Retrieved pointers for firmware\n");
-       PSB_DEBUG_GENERAL("MSVDX: text_size: %d\n", fw->text_size);
-       PSB_DEBUG_GENERAL("MSVDX: data_size: %d\n", fw->data_size);
-       PSB_DEBUG_GENERAL("MSVDX: data_location: 0x%x\n",
-                         fw->data_location);
-       PSB_DEBUG_GENERAL("MSVDX: First 4 bytes of text: 0x%x\n",
-                         *text_ptr);
-       PSB_DEBUG_GENERAL("MSVDX: First 4 bytes of data: 0x%x\n",
-                         *data_ptr);
-
-       PSB_DEBUG_GENERAL("MSVDX: Uploading firmware\n");
-
-       psb_upload_fw(dev_priv, 0, msvdx_priv->mtx_mem_size / 4, ec_firmware);
+#if UPLOAD_FW_BY_DMA
+               psb_upload_fw(dev_priv, 0, msvdx_priv->mtx_mem_size / 4, ec_firmware);
+#else
+               psb_upload_fw(dev_priv, MTX_CORE_CODE_MEM, ram_bank_size,
+                               PC_START_ADDRESS - MTX_CODE_BASE, fw->text_size,
+                               text_ptr);
+               psb_upload_fw(dev_priv, MTX_CORE_DATA_MEM, ram_bank_size,
+                               fw->data_location - MTX_DATA_BASE, fw->data_size,
+                               data_ptr);
+#endif
 
 #if 0
-       /* todo :  Verify code upload possibly only in debug */
-       ret = psb_verify_fw(dev_priv, ram_bank_size,
-                           MTX_CORE_CODE_MEM,
-                           PC_START_ADDRESS - MTX_CODE_BASE,
-                           fw->text_size, text_ptr);
-       if (ret) {
-               /* Firmware code upload failed */
-               ret = 1;
-               goto out;
-       }
-
-       ret = psb_verify_fw(dev_priv, ram_bank_size, MTX_CORE_DATA_MEM,
-                           fw->data_location - MTX_DATA_BASE,
-                           fw->data_size, data_ptr);
-       if (ret) {
-               /* Firmware data upload failed */
-               ret = 1;
-               goto out;
-       }
+       /* todo :  Verify code upload possibly only in debug */
+       ret = psb_verify_fw(dev_priv, ram_bank_size,
+                           MTX_CORE_CODE_MEM,
+                           PC_START_ADDRESS - MTX_CODE_BASE,
+                           fw->text_size, text_ptr);
+       if (ret) {
+               /* Firmware code upload failed */
+               ret = 1;
+               goto out;
+       }
+
+       ret = psb_verify_fw(dev_priv, ram_bank_size, MTX_CORE_DATA_MEM,
+                           fw->data_location - MTX_DATA_BASE,
+                           fw->data_size, data_ptr);
+       if (ret) {
+               /* Firmware data upload failed */
+               ret = 1;
+               goto out;
+       }
 #else
-       (void)psb_verify_fw;
+       (void)psb_verify_fw;
 #endif
 
                /*      -- Set starting PC address      */
@@ -697,17 +766,16 @@ int psb_setup_fw(struct drm_device *dev)
        PSB_DEBUG_GENERAL("MSVDX: MSVDX_COMMS_AREA_ADDR = %08x\n",
                          MSVDX_COMMS_AREA_ADDR);
        if (IS_D0(dev)) {
+               /* send INIT cmd for RENDEC init */
+               PSB_WMSVDX32(DSIABLE_IDLE_GPIO_SIG | DSIABLE_Auto_CLOCK_GATING
+                            | RETURN_VDEB_DATA_IN_COMPLETION,
+                            MSVDX_COMMS_OFFSET_FLAGS);
                /*
                 * at this stage, FW is uplaoded successfully, can send rendec
                 * init message
                 */
                uint32_t init_msg[FW_DEVA_INIT_SIZE];
 
-               /* send INIT cmd for RENDEC init */
-               PSB_WMSVDX32(DSIABLE_IDLE_GPIO_SIG | DSIABLE_Auto_CLOCK_GATING
-                            | RETURN_VDEB_DATA_IN_COMPLETION,
-                            MSVDX_COMMS_OFFSET_FLAGS);
-
                MEMIO_WRITE_FIELD(init_msg, FWRK_GENMSG_SIZE,
                                  FW_DEVA_INIT_SIZE);
                MEMIO_WRITE_FIELD(init_msg, FWRK_GENMSG_ID,
@@ -866,12 +934,13 @@ int psb_msvdx_reset(struct drm_psb_private *dev_priv)
                }
 
        }
+
        /* Issue software reset */
        /* PSB_WMSVDX32(msvdx_sw_reset_all, MSVDX_CONTROL); */
        PSB_WMSVDX32(MSVDX_CONTROL_CR_MSVDX_SOFT_RESET_MASK, MSVDX_CONTROL);
 
        ret = psb_wait_for_register(dev_priv, MSVDX_CONTROL, 0,
-                                   MSVDX_CONTROL_CR_MSVDX_SOFT_RESET_MASK);
+                       MSVDX_CONTROL_CR_MSVDX_SOFT_RESET_MASK);
 
        if (!ret) {
                /* Clear interrupt enabled flag */
@@ -946,6 +1015,173 @@ static ssize_t psb_msvdx_pmstate_show(struct device *dev,
 
 static DEVICE_ATTR(msvdx_pmstate, 0444, psb_msvdx_pmstate_show, NULL);
 
+static void psb_msvdx_conceal_mb(char * ec_start, char * ref_start,
+                                uint32_t start_err_mb, uint32_t end_err_mb,
+                                uint32_t pic_width_mb, uint32_t stride,
+                                uint32_t mb_width, uint32_t mb_height)
+{
+       int i, offset_start, offset_end, size, full_line_start, full_line_end, extra_line_start, extra_line_end;
+       char *src, *dst;
+
+       (void)offset_end;
+       (void)offset_start;
+
+       full_line_start = (start_err_mb / pic_width_mb) * stride * mb_height;
+       full_line_end = ((end_err_mb + 1) / pic_width_mb) * stride * mb_height;
+       extra_line_start = (start_err_mb % pic_width_mb) * mb_width;
+       extra_line_end = (end_err_mb + 1) % pic_width_mb * mb_width;
+       if (extra_line_start != 0) {
+               size = stride - extra_line_start;
+               src = ref_start + full_line_start + extra_line_start;
+               dst = ec_start + full_line_start + extra_line_start;
+               for (i = 0; i < mb_height; i++) {
+                       memcpy(dst, src, size);
+                       //memset(dst, 255, size);
+                       src += stride;
+                       dst += stride;
+               }
+               full_line_start += stride * mb_height;
+       }
+       src = ref_start + full_line_start;
+       dst = ec_start + full_line_start;
+       size =  full_line_end - full_line_start;
+       memcpy(dst, src, size);
+       //memset(dst, 255, size);
+       if (extra_line_end != 0) {
+               size = extra_line_end;
+               src = ref_start + full_line_end;
+               dst = ec_start + full_line_end;
+               for (i = 0; i < mb_height; i++) {
+                       memcpy(dst, src, size);
+                       //memset(dst, 255, size);
+                       src += stride;
+                       dst += stride;
+               }
+       }
+}
+
+
+static void psb_msvdx_error_concealment(struct work_struct *data)
+{
+#if 0
+       uint32_t i;
+       int ret;
+       struct msvdx_private *msvdx_priv = container_of(data, struct msvdx_private, ec_work);
+       drm_psb_msvdx_frame_info_t *ec_frame = NULL;
+       drm_psb_msvdx_frame_info_t *ref_frame = NULL;
+       static struct ttm_bo_kmap_obj ec_kmap, ref_kmap;
+       struct ttm_buffer_object *ec_bo = NULL;
+       struct ttm_buffer_object *ref_bo = NULL;
+       struct ttm_object_file *tfile = msvdx_priv->tfile;
+       drm_psb_msvdx_decode_status_t *decode_status = NULL;
+       bool is_iomem;
+       char *ec_start, *ref_start;
+
+       if (msvdx_priv->ec_fence > 0)
+               msvdx_priv->ref_pic_fence = msvdx_priv->ec_fence - 1;
+       else {
+               DRM_ERROR("Can't do error concealment for the first frame.\n");
+               return;
+       }
+
+       /*get the frame_info struct for error concealment frame*/
+       for (i = 0; i < MAX_DECODE_BUFFERS; i++) {
+               if (msvdx_priv->frame_info[i].fence == msvdx_priv->ec_fence) {
+                       ec_frame = &msvdx_priv->frame_info[i];
+                       break;
+               }
+       }
+       if (!ec_frame) {
+               DRM_ERROR("MSVDX: didn't find frame_info which matched the ec fence\n");
+               return;
+       }
+       decode_status = &ec_frame->decode_status;
+       ec_bo = ttm_buffer_object_lookup(tfile, ec_frame->handle);
+       if (unlikely(ec_bo == NULL)) {
+               printk(KERN_ERR " : Could not find buffer object for setstatus.\n");
+               return;
+       }
+       ret = ttm_bo_reserve(ec_bo, true, true, false, 0);
+       if (ret) {
+               DRM_ERROR("MSVDX ERROR CONCEALMENT: reserver failed.\n");
+               return;
+       }
+       ret = ttm_bo_kmap(ec_bo,
+                         0,
+                         (ec_frame->buffer_size +
+                          PAGE_SIZE - 1) >> PAGE_SHIFT,
+                         &ec_kmap);
+       if (ret) {
+               printk("MSVDX ERROR CONCEALMENT: ec kmap failed, %d.\n", ret);
+               return;
+       }
+       ec_start = (unsigned char *) ttm_kmap_obj_virtual(&ec_kmap,
+                       &is_iomem);
+
+       /*get the frame_info struct for reference frame*/
+       for (i = 0; i < MAX_DECODE_BUFFERS; i++) {
+               if (msvdx_priv->frame_info[i].fence == msvdx_priv->ref_pic_fence) {
+                       ref_frame = &msvdx_priv->frame_info[i];
+                       break;
+               }
+       }
+       if (!ref_frame) {
+               DRM_ERROR("MSVDX: didn't find frame_info which matched the ref fence\n");
+               return;
+       }
+       ref_bo = ttm_buffer_object_lookup(tfile, ref_frame->handle);
+       if (unlikely(ref_bo == NULL)) {
+               printk(KERN_ERR " : Could not find buffer object for setstatus.\n");
+       }
+       ret = ttm_bo_reserve(ref_bo, true, true, false, 0);
+       if (ret) {
+               DRM_ERROR("MSVDX ERROR CONCEALMENT: reserver failed.\n");
+               return;
+       }
+       ret = ttm_bo_kmap(ref_bo,
+                         0,
+                         (ref_frame->buffer_size +
+                          PAGE_SIZE - 1) >> PAGE_SHIFT,
+                         &ref_kmap);
+       if (ret) {
+               printk("MSVDX ERROR CONCEALMENT: ref kmap failed, %d.\n", ret);
+               return;
+       }
+       ref_start = (unsigned char *) ttm_kmap_obj_virtual(&ref_kmap,
+                       &is_iomem);
+
+       /*copy missing mb from ref picture to ec picture*/
+       for (i = 0; i < decode_status->num_error_slice; i++) {
+               if ((decode_status->start_error_mb_list[i] >= ec_frame->size_mb) ||
+                   (decode_status->end_error_mb_list[i] >= ec_frame->size_mb) ||
+                   (decode_status->start_error_mb_list[i] > decode_status->end_error_mb_list[i]))
+                       continue;
+               psb_msvdx_conceal_mb(ec_start, ref_start,
+                                    decode_status->start_error_mb_list[i],
+                                    decode_status->end_error_mb_list[i],
+                                    ec_frame->picture_width_mb, ec_frame->buffer_stride,
+                                    16, 16);
+               psb_msvdx_conceal_mb(ec_start + ec_frame->buffer_size * 2 / 3,
+                                    ref_start + ec_frame->buffer_size * 2 / 3,
+                                    decode_status->start_error_mb_list[i],
+                                    decode_status->end_error_mb_list[i],
+                                    ec_frame->picture_width_mb, ec_frame->buffer_stride,
+                                    16, 8);
+       }
+
+       ttm_bo_kunmap(&ec_kmap);
+       ttm_bo_kunmap(&ref_kmap);
+       ttm_bo_unreserve(ec_bo);
+       ttm_bo_unreserve(ref_bo);
+
+       if (ec_bo)
+               ttm_bo_unref(&ec_bo);
+       if (ref_bo)
+               ttm_bo_unref(&ref_bo);
+
+#endif
+}
+
 int psb_msvdx_init(struct drm_device *dev)
 {
        struct drm_psb_private *dev_priv = dev->dev_private;
@@ -964,7 +1200,21 @@ int psb_msvdx_init(struct drm_device *dev)
 
                dev_priv->msvdx_private = msvdx_priv;
                memset(msvdx_priv, 0, sizeof(struct msvdx_private));
+               msvdx_priv->dev_priv = dev_priv;
+
+               msvdx_priv->tile_region_start0 =
+                       dev_priv->bdev.man[DRM_PSB_MEM_MMU_TILING].gpu_offset;
 
+               msvdx_priv->tile_region_end0 = msvdx_priv->tile_region_start0 +
+               (dev_priv->bdev.man[DRM_PSB_MEM_MMU_TILING].size << PAGE_SHIFT);
+
+               msvdx_priv->tile_region_start1 =
+                       dev_priv->bdev.man[TTM_PL_TT].gpu_offset;
+
+               msvdx_priv->tile_region_end1 = msvdx_priv->tile_region_start1 +
+               (dev_priv->bdev.man[TTM_PL_TT].size << PAGE_SHIFT);
+
+               drm_psb_msvdx_tiling = 0;
                /* get device --> drm_device --> drm_psb_private --> msvdx_priv
                 * for psb_msvdx_pmstate_show: msvdx_pmpolicy
                 * if not pci_set_drvdata, can't get drm_device from device
@@ -973,9 +1223,29 @@ int psb_msvdx_init(struct drm_device *dev)
                if (device_create_file(&dev->pdev->dev,
                                       &dev_attr_msvdx_pmstate))
                        DRM_ERROR("MSVDX: could not create sysfs file\n");
-               msvdx_priv->sysfs_pmstate =
-                       sysfs_get_dirent(dev->pdev->dev.kobj.sd,
-                                       NULL, "msvdx_pmstate");
+               msvdx_priv->sysfs_pmstate = sysfs_get_dirent(
+                                                   dev->pdev->dev.kobj.sd,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
+                                                   NULL,
+#endif
+                                                   "msvdx_pmstate");
+
+               msvdx_priv->msvdx_ec_ctx[0] =
+                       kzalloc(sizeof(struct psb_msvdx_ec_ctx) *
+                                       PSB_MAX_EC_INSTANCE,
+                                       GFP_KERNEL);
+               if (msvdx_priv->msvdx_ec_ctx[0] == NULL)
+                       DRM_ERROR("MSVDX:fail to allocate memory for ec ctx\n");
+               else {
+                       int i;
+                       for (i = 1; i < PSB_MAX_EC_INSTANCE; i++)
+                               msvdx_priv->msvdx_ec_ctx[i] =
+                                       msvdx_priv->msvdx_ec_ctx[0] + i;
+                       for (i = 0; i < PSB_MAX_EC_INSTANCE; i++)
+                               msvdx_priv->msvdx_ec_ctx[i]->fence =
+                                               PSB_MSVDX_INVALID_FENCE;
+               }
+               INIT_WORK(&(msvdx_priv->ec_work), psb_msvdx_do_concealment);
        }
 
        msvdx_priv = dev_priv->msvdx_private;
@@ -1003,6 +1273,7 @@ int psb_msvdx_init(struct drm_device *dev)
        PSB_DEBUG_GENERAL("Enabling clocks\n");
        PSB_WMSVDX32(clk_enable_all, MSVDX_MAN_CLK_ENABLE);
 
+
        /* Issue software reset for all but core*/
        /*
                PSB_WMSVDX32((uint32_t) ~MSVDX_CORE_CR_MSVDX_CONTROL_CR_MSVDX_SOFT_RESET_MASK, REGISTER(MSVDX_CORE, CR_MSVDX_CONTROL));
@@ -1032,6 +1303,36 @@ int psb_msvdx_init(struct drm_device *dev)
                /* Enable MMU by removing all bypass bits */
                PSB_WMSVDX32(0, MSVDX_MMU_CONTROL0);
        }
+#if 0
+       if (drm_psb_msvdx_tiling && IS_MSVDX_MEM_TILE(dev)) {
+               uint32_t tile_start =
+                       dev_priv->bdev.man[DRM_PSB_MEM_MMU_TILING].gpu_offset;
+               uint32_t tile_end = tile_start +
+               (dev_priv->bdev.man[DRM_PSB_MEM_MMU_TILING].size << PAGE_SHIFT);
+
+               /* Enable memory tiling */
+               cmd = ((tile_start >> 20) + (((tile_end >> 20) - 1) << 12) +
+                                       ((0x8 | 2) << 24)); /* 2k stride */
+
+               PSB_DEBUG_GENERAL("MSVDX: MMU Tiling register0 %08x\n", cmd);
+               PSB_DEBUG_GENERAL("       Region 0x%08x-0x%08x\n",
+                                       tile_start, tile_end);
+               PSB_WMSVDX32(cmd, MSVDX_MMU_TILE_BASE0);
+
+               tile_start =
+                       dev_priv->bdev.man[TTM_PL_TT].gpu_offset;
+               tile_end = tile_start +
+               (dev_priv->bdev.man[TTM_PL_TT].size << PAGE_SHIFT);
+
+               cmd = ((tile_start >> 20) + (((tile_end >> 20) - 1) << 12) +
+                                       ((0x8 | 2) << 24)); /* 2k stride */
+
+               PSB_DEBUG_GENERAL("MSVDX: MMU Tiling register1 %08x\n", cmd);
+               PSB_DEBUG_GENERAL("       Region 0x%08x-0x%08x\n",
+                                       tile_start, tile_end);
+               PSB_WMSVDX32(cmd, MSVDX_MMU_TILE_BASE1);
+       }
+#endif
 
        /* move firmware loading to the place receiving first command buffer */
 
@@ -1066,7 +1367,10 @@ int psb_msvdx_init(struct drm_device *dev)
                else
                        msvdx_priv->mtx_mem_size = 40 * 1024;
 
-               fw_bo_size =  msvdx_priv->mtx_mem_size + 4096;
+               if (IS_MDFLD(dev))
+                       fw_bo_size =  msvdx_priv->mtx_mem_size + 4096;
+               else
+                       fw_bo_size = ((msvdx_priv->mtx_mem_size + 8192) & ~0xfff) * 2; /* fw + ec_fw */
 
                PSB_DEBUG_INIT("MSVDX: MTX mem size is 0x%08xbytes  allocate firmware BO size 0x%08x\n", msvdx_priv->mtx_mem_size,
                               fw_bo_size);
@@ -1084,7 +1388,6 @@ int psb_msvdx_init(struct drm_device *dev)
 
        PSB_DEBUG_GENERAL("MSVDX: RENDEC A: %08x RENDEC B: %08x\n",
                          msvdx_priv->base_addr0, msvdx_priv->base_addr1);
-
        if (!IS_D0(dev)) {
                PSB_WMSVDX32(msvdx_priv->base_addr0, MSVDX_RENDEC_BASE_ADDR0);
                PSB_WMSVDX32(msvdx_priv->base_addr1, MSVDX_RENDEC_BASE_ADDR1);
@@ -1167,8 +1470,10 @@ int psb_msvdx_init(struct drm_device *dev)
        psb_msvdx_clearirq(dev);
        psb_msvdx_enableirq(dev);
 
-       PSB_DEBUG_INIT("MSDVX:old clock gating disable = 0x%08x\n",
-               PSB_RVDC32(PSB_MSVDX_CLOCKGATING));
+       if (IS_MSVDX(dev)) {
+               PSB_DEBUG_INIT("MSDVX:old clock gating disable = 0x%08x\n",
+                              PSB_RVDC32(PSB_MSVDX_CLOCKGATING));
+       }
 
        if (!IS_D0(dev)) {
                cmd = 0;
@@ -1180,6 +1485,7 @@ int psb_msvdx_init(struct drm_device *dev)
                PSB_WMSVDX32(cmd, MSVDX_VEC_SHIFTREG_CONTROL);
        }
 
+
 #if 0
        ret = psb_setup_fw(dev);
        if (ret)
@@ -1202,6 +1508,9 @@ int psb_msvdx_init(struct drm_device *dev)
                psb_poll_mtx_irq(dev_priv);
        }
 #endif
+       if (IS_MRST(dev))
+               INIT_WORK(&(msvdx_priv->ec_work), psb_msvdx_error_concealment);
+
 
        return 0;
 
@@ -1243,6 +1552,8 @@ int psb_msvdx_uninit(struct drm_device *dev)
        if (msvdx_priv->vec_local_mem_data)
                kfree(msvdx_priv->vec_local_mem_data);
 
+       kfree(msvdx_priv->msvdx_ec_ctx[0]);
+
        if (msvdx_priv) {
                /* pci_set_drvdata(dev->pdev, NULL); */
                device_remove_file(&dev->pdev->dev, &dev_attr_msvdx_pmstate);
index c2de5a3..e7c89d3 100644 (file)
@@ -56,7 +56,7 @@ static void ttm_fence_lockup(struct ttm_fence_object *fence, uint32_t mask)
  * need polling.
  */
 
-static int ttm_fence_wait_polling(struct ttm_fence_object *fence, bool lazy,
+int ttm_fence_wait_polling(struct ttm_fence_object *fence, bool lazy,
                           bool interruptible, uint32_t mask)
 {
        struct ttm_fence_class_manager *fc = ttm_fence_fc(fence);
@@ -284,7 +284,7 @@ int ttm_fence_object_flush(struct ttm_fence_object *fence, uint32_t type)
  * wrapped around and reused.
  */
 
-static void ttm_fence_flush_old(struct ttm_fence_device *fdev,
+void ttm_fence_flush_old(struct ttm_fence_device *fdev,
                         uint32_t fence_class, uint32_t sequence)
 {
        struct ttm_fence_class_manager *fc = &fdev->fence_class[fence_class];
@@ -381,7 +381,7 @@ retry:
        return ttm_fence_wait_polling(fence, lazy, interruptible, mask);
 }
 
-static int ttm_fence_object_emit(struct ttm_fence_object *fence, uint32_t fence_flags,
+int ttm_fence_object_emit(struct ttm_fence_object *fence, uint32_t fence_flags,
                          uint32_t fence_class, uint32_t type)
 {
        const struct ttm_fence_driver *driver = ttm_fence_driver(fence);
index dbce21e..3e22a15 100644 (file)
@@ -25,6 +25,7 @@
 #include "psb_page_flip.h"
 #include "psb_ttm_userobj_api.h"
 #include <linux/io.h>
+#include <asm/intel-mid.h>
 #include "psb_msvdx.h"
 #include "bufferclass_video.h"
 
@@ -65,6 +66,9 @@ int psb_open(struct inode *inode, struct file *filp)
 
        psb_fp->tfile = ttm_object_file_init(dev_priv->tdev,
                                             PSB_FILE_OBJECT_HASH_ORDER);
+       psb_fp->bcd_index = -1;
+
+       /* TODO: this list was deleted on latest UMG code */
        INIT_LIST_HEAD(&psb_fp->pending_flips);
 
        if (unlikely(psb_fp->tfile == NULL))
@@ -92,23 +96,26 @@ out_err0:
 int psb_release(struct inode *inode, struct file *filp)
 {
        struct drm_file *file_priv;
-       struct drm_device *dev;
        struct psb_fpriv *psb_fp;
        struct drm_psb_private *dev_priv;
        struct msvdx_private *msvdx_priv;
-       int ret;
+       int ret, i;
+       struct psb_msvdx_ec_ctx *ec_ctx;
+       uint32_t ui32_reg_value = 0;
        file_priv = (struct drm_file *) filp->private_data;
+       struct ttm_object_file *tfile = psb_fpriv(file_priv)->tfile;
        psb_fp = psb_fpriv(file_priv);
-       dev = file_priv->minor->dev;
-       dev_priv = psb_priv(dev);
+       dev_priv = psb_priv(file_priv->minor->dev);
+
        msvdx_priv = (struct msvdx_private *)dev_priv->msvdx_private;
 
-       psb_cleanup_pending_events(dev, psb_fp);
+       psb_cleanup_pending_events(file_priv->minor->dev, psb_fp);
 
        /* Disable asynchronous notifications for the DRM file descriptor. */
        drm_fasync(-1, filp, 0);
 
        /*cleanup for msvdx*/
+
        if (msvdx_priv->tfile == psb_fpriv(file_priv)->tfile) {
                msvdx_priv->fw_status = 0;
                msvdx_priv->host_be_opp_enabled = 0;
@@ -116,6 +123,20 @@ int psb_release(struct inode *inode, struct file *filp)
                memset(&msvdx_priv->frame_info, 0, sizeof(struct drm_psb_msvdx_frame_info) * MAX_DECODE_BUFFERS);
        }
 
+       for (i = 0; i < PSB_MAX_EC_INSTANCE; i++) {
+               if (msvdx_priv->msvdx_ec_ctx[i]->tfile == tfile)
+                       break;
+       }
+
+       if (i < PSB_MAX_EC_INSTANCE) {
+               ec_ctx = msvdx_priv->msvdx_ec_ctx[i];
+               printk(KERN_DEBUG "remove ec ctx with tfile 0x%08x\n",
+                      ec_ctx->tfile);
+               ec_ctx->tfile = NULL;
+               ec_ctx->fence = PSB_MSVDX_INVALID_FENCE;
+       }
+
+        /*this is used to cleanup bcd if app failed to call vaTerminate*/
        if (psb_fp->bcd_index >= 0 &&
            psb_fp->bcd_index < BC_VIDEO_DEVICE_MAX_ID &&
            bc_video_id_usage[psb_fp->bcd_index] == 1) {
@@ -206,7 +227,6 @@ int psb_pl_ub_create_ioctl(struct drm_device *dev, void *data,
                                      &dev_priv->bdev, &dev_priv->ttm_lock, data);
 
 }
-
 /**
  * psb_ttm_fault - Wrapper around the ttm fault method.
  *
@@ -270,6 +290,7 @@ int psb_mmap(struct file *filp, struct vm_area_struct *vma)
 
        return 0;
 }
+
 /*
 ssize_t psb_ttm_write(struct file *filp, const char __user *buf,
                      size_t count, loff_t *f_pos)
@@ -297,9 +318,9 @@ int psb_verify_access(struct ttm_buffer_object *bo,
        if (capable(CAP_SYS_ADMIN))
                return 0;
 
+       /* workaround drm authentification issue on Android for ttm_bo_mmap */
        if (unlikely(!file_priv->authenticated))
                return -EPERM;
-
        return ttm_pl_verify_access(bo, psb_fpriv(file_priv)->tfile);
 }
 
@@ -337,10 +358,10 @@ int psb_ttm_global_init(struct drm_psb_private *dev_priv)
        global->size = sizeof(struct ttm_bo_global);
        global->init = &ttm_bo_global_init;
        global->release = &ttm_bo_global_release;
-       ret = drm_global_item_ref(global);
+       ret = drm_global_item_ref((struct drm_global_reference *)global);
        if (ret != 0) {
                DRM_ERROR("Failed setting up TTM BO subsystem.\n");
-               drm_global_item_unref(global_ref);
+               drm_global_item_unref((struct drm_global_reference *)global_ref);
                return ret;
        }
 
@@ -370,7 +391,6 @@ int psb_getpageaddrs_ioctl(struct drm_device *dev, void *data,
                       "Could not find buffer object for getpageaddrs.\n");
                return -EINVAL;
        }
-
        arg->gtt_offset = bo->offset;
        ttm = bo->ttm;
        num_pages = ttm->num_pages;
@@ -381,6 +401,5 @@ int psb_getpageaddrs_ioctl(struct drm_device *dev, void *data,
 
        if (bo)
                ttm_bo_unref(&bo);
-
        return ret;
 }
index 8f5a0cf..bb18859 100644 (file)
@@ -44,7 +44,7 @@ static uint32_t psb_busy_prios[] = {
        TTM_PL_FLAG_SYSTEM
 };
 
-static const struct ttm_placement default_placement = {0, 0, 0, NULL, 5, psb_busy_prios};
+const struct ttm_placement default_placement = {0, 0, 0, NULL, 5, psb_busy_prios};
 
 static size_t ttm_pl_size(struct ttm_bo_device *bdev, unsigned long num_pages)
 {
@@ -489,21 +489,8 @@ int ttm_pl_synccpu_ioctl(struct ttm_object_file *tfile, void *data)
                ttm_base_object_unref(&base);
                break;
        case TTM_PL_SYNCCPU_OP_RELEASE:
-               bo = ttm_buffer_object_lookup(tfile, arg->handle);
-               if (unlikely(bo == NULL)) {
-                       printk(KERN_ERR "Could not find buffer object for synccpu release\n");
-                       ret = -EINVAL;
-                       goto out;
-               }
-               ret = ttm_bo_reserve(bo, true, true, false, 0);
-               if (unlikely(ret != 0)) {
-                       ttm_bo_unref(&bo);
-                       return ret;
-               }
                ret = ttm_ref_object_base_unref(tfile, arg->handle,
                                                TTM_REF_SYNCCPU_WRITE);
-               ttm_bo_unreserve(bo);
-               ttm_bo_unref(&bo);
                break;
        default:
                ret = -EINVAL;
index 1fcba8c..07bb656 100644 (file)
@@ -80,4 +80,6 @@ extern int ttm_buffer_object_create(struct ttm_bo_device *bdev,
                                    struct file *persistant_swap_storage,
                                    struct ttm_buffer_object **p_bo);
 
+extern int psb_ttm_bo_check_placement(struct ttm_buffer_object *bo,
+                                     struct ttm_placement *placement);
 #endif