diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2009-03-20 15:38:05 +1100 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2009-03-20 15:38:05 +1100 |
commit | debd9c0359e33f23ef54533d370b03516d54d4a5 (patch) | |
tree | 268bc28ce02382c58aa6a14b0f1012c839696ca7 /drivers/staging/psb/lnc_topaz.c | |
parent | c2ced7afe298f12721337baee6b10cbc56da5c8b (diff) | |
parent | 5e2d7851a34c18f03ed2fd1c0784a54dca44460c (diff) |
Merge branch 'quilt/staging'
Conflicts:
drivers/gpu/drm/Makefile
Diffstat (limited to 'drivers/staging/psb/lnc_topaz.c')
-rw-r--r-- | drivers/staging/psb/lnc_topaz.c | 695 |
1 files changed, 695 insertions, 0 deletions
diff --git a/drivers/staging/psb/lnc_topaz.c b/drivers/staging/psb/lnc_topaz.c new file mode 100644 index 000000000000..b0383ca79a39 --- /dev/null +++ b/drivers/staging/psb/lnc_topaz.c @@ -0,0 +1,695 @@ +/** + * 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 + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* include headers */ +/* #define DRM_DEBUG_CODE 2 */ + +#include <drm/drmP.h> +#include <drm/drm_os_linux.h> + +#include "psb_drv.h" +#include "psb_drm.h" +#include "lnc_topaz.h" + +#include <linux/io.h> +#include <linux/delay.h> + +static int drm_psb_ospmxxx = 0x0; + +/* 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); + +void lnc_topaz_interrupt(struct drm_device *dev, uint32_t topaz_stat) +{ + struct drm_psb_private *dev_priv = + (struct drm_psb_private *)dev->dev_private; + uint32_t 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; + + dev_priv->topaz_current_sequence = + *(uint32_t *)dev_priv->topaz_sync_addr; + + PSB_DEBUG_IRQ("TOPAZ:Got SYNC IRQ,sync seq:0x%08x (MTX) vs 0x%08x\n", + dev_priv->topaz_current_sequence, + dev_priv->sequence[LNC_ENGINE_ENCODE]); + + psb_fence_handler(dev, LNC_ENGINE_ENCODE); + + dev_priv->topaz_busy = 1; + lnc_topaz_dequeue_send(dev); +} + +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 sequence = dev_priv->sequence[LNC_ENGINE_ENCODE]; + + PSB_DEBUG_GENERAL("TOPAZ: command submit\n"); + + /* # lock topaz's mutex [msvdx_mutex] */ + mutex_lock(&dev_priv->topaz_mutex); + + PSB_DEBUG_GENERAL("TOPAZ: topaz busy = %d\n", dev_priv->topaz_busy); + + if (dev_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) { + mutex_unlock(&dev_priv->topaz_mutex); + + /* FIXME: find a proper return value */ + DRM_ERROR("TOPAX:load /lib/firmware/topaz_fw.bin fail," + "ensure udevd is configured correctly!\n"); + + return -EFAULT; + } + dev_priv->topaz_fw_loaded = 1; + } else { + /* OSPM power state change */ + /* FIXME: why here? why not in the NEW_CODEC case? */ + if (drm_psb_ospmxxx & ENABLE_TOPAZ_OSPM_D0IX) { + psb_power_up_topaz(dev); + lnc_topaz_restore_mtx_state(dev); + } + } + + /* # schedule watchdog */ + /* psb_schedule_watchdog(dev_priv); */ + + /* # spin lock irq save [msvdx_lock] */ + spin_lock_irqsave(&dev_priv->topaz_lock, irq_flags); + + /* # if topaz need to reset, reset it */ + if (dev_priv->topaz_needs_reset) { + /* #.# reset it */ + spin_unlock_irqrestore(&dev_priv->topaz_lock, irq_flags); + PSB_DEBUG_GENERAL("TOPAZ: needs reset.\n"); + + if (lnc_topaz_reset(dev_priv)) { + mutex_unlock(&dev_priv->topaz_mutex); + ret = -EBUSY; + DRM_ERROR("TOPAZ: reset failed.\n"); + return ret; + } + + PSB_DEBUG_GENERAL("TOPAZ: reset ok.\n"); + + /* #.# reset any related flags */ + dev_priv->topaz_needs_reset = 0; + dev_priv->topaz_busy = 0; + PSB_DEBUG_GENERAL("XXX: does we need idle flag??\n"); + dev_priv->topaz_start_idle = 0; + + /* #.# init topaz */ + lnc_topaz_init(dev); + + /* avoid another fw init */ + dev_priv->topaz_fw_loaded = 1; + + spin_lock_irqsave(&dev_priv->topaz_lock, irq_flags); + } + + if (!dev_priv->topaz_busy) { + /* # direct map topaz command if topaz is free */ + PSB_DEBUG_GENERAL("TOPAZ:direct send command,sequence %08x \n", + sequence); + + dev_priv->topaz_busy = 1; + spin_unlock_irqrestore(&dev_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"); + mutex_unlock(&dev_priv->topaz_mutex); + return ret; + } + } else { + PSB_DEBUG_GENERAL("TOPAZ: queue command,sequence %08x \n", + sequence); + cmd = NULL; + + spin_unlock_irqrestore(&dev_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"); + mutex_unlock(&dev_priv->topaz_mutex); + return ret; + } + + ret = lnc_topaz_save_command(dev, cmd, cmd_size, sequence); + if (ret) + DRM_ERROR("TOPAZ: save command failed\n"); + } + + /* OPSM D0IX power state change */ + if (drm_psb_ospmxxx & ENABLE_TOPAZ_OSPM_D0IX) + lnc_topaz_save_mtx_state(dev); + + mutex_unlock(&dev_priv->topaz_mutex); + + 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; + + PSB_DEBUG_GENERAL("TOPAZ: queue command,sequence: %08x..\n", + sequence); + + topaz_cmd = drm_calloc(1, sizeof(struct lnc_topaz_cmd_queue), + DRM_MEM_DRIVER); + if (topaz_cmd == NULL) { + mutex_unlock(&dev_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(&dev_priv->topaz_lock, irq_flags); + list_add_tail(&topaz_cmd->head, &dev_priv->topaz_queue); + if (!dev_priv->topaz_busy) { + /* dev_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(&dev_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; + +#if LNC_TOPAZ_NO_IRQ /* 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); +#endif + + mutex_lock(&cmd_buffer->mutex); + if (cmd_buffer->sync_obj != NULL) + ttm_fence_sync_obj_unref(&cmd_buffer->sync_obj); + mutex_unlock(&cmd_buffer->mutex); + + 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]; + int count = 10000; +#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 + uint32_t *sync_p = (uint32_t *)dev_priv->topaz_sync_addr; + + /* insert a SYNC command here */ + dev_priv->topaz_sync_cmd_seq = (1 << 15) | dev_priv->topaz_cmd_seq++; + sync_cmd[0] = MTX_CMDID_SYNC | (3 << 8) | + (dev_priv->topaz_sync_cmd_seq << 16); + sync_cmd[1] = dev_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", + dev_priv->topaz_sync_cmd_seq, sync_seq); + + 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); + + dev_priv->topaz_busy = 0; + + /* XXX: check psb_fence_handler is suitable for topaz */ + dev_priv->topaz_current_sequence = *sync_p; +#if 0 + write_lock_irqsave(&fc->lock, irq_flags); + ttm_fence_handler(fdev, LNC_ENGINE_ENCODE, + dev_priv->topaz_current_sequence, + _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 = drm_calloc(1, cmd_size, DRM_MEM_DRIVER); + 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; + + 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; + } + + dev_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 & + dev_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); + 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; + + int ret = 0; + + /* <msvdx does> # enable all clock */ + + write_index = dev_priv->topaz_cmd_windex; + if (write_index + cmd_size + 1 > dev_priv->topaz_ccb_size) { + int free_space = dev_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 & dev_priv->topaz_cmd_seq++; + + PSB_DEBUG_GENERAL("TOPAZ: MTX_CMDID_NULL:" + " size(%d),seq (0x%04x)\n", + pad_cmd.size, pad_cmd.seq); + + TOPAZ_BEGIN_CCB(dev_priv); + TOPAZ_OUT_CCB(dev_priv, pad_cmd.val); + TOPAZ_END_CCB(dev_priv, 1); + } + POLL_WB_RINDEX(dev_priv, 0); + if (ret == 0) + dev_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 = dev_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)); + TOPAZ_BEGIN_CCB(dev_priv); + while (cmd_size > 0) { + TOPAZ_OUT_CCB(dev_priv, *cmd_pointer++); + --cmd_size; + } + TOPAZ_END_CCB(dev_priv, 1); + + POLL_WB_RINDEX(dev_priv, dev_priv->topaz_cmd_windex); + +#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; + + PSB_DEBUG_GENERAL("TOPAZ: dequeue command and send it to topaz\n"); + + if (list_empty(&dev_priv->topaz_queue)) { + dev_priv->topaz_busy = 0; + return 0; + } + + topaz_cmd = list_first_entry(&dev_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); + drm_free(topaz_cmd, sizeof(struct lnc_topaz_cmd_queue), + DRM_MEM_DRIVER); + + return ret; +} + +void +lnc_topaz_lockup(struct drm_psb_private *dev_priv, + int *topaz_lockup, int *topaz_idle) +{ + unsigned long irq_flags; + uint32_t tmp; + + /* if have printk in this function, you will have plenties here */ + spin_lock_irqsave(&dev_priv->topaz_lock, irq_flags); + *topaz_lockup = 0; + *topaz_idle = 1; + + if (!dev_priv->has_topaz) { + spin_unlock_irqrestore(&dev_priv->topaz_lock, irq_flags); + return; + } + + tmp = dev_priv->topaz_current_sequence + - dev_priv->sequence[LNC_ENGINE_ENCODE]; + if (tmp > 0x0FFFFFFF) { + if (dev_priv->topaz_current_sequence == + dev_priv->topaz_last_sequence) { + *topaz_lockup = 1; + } else { + dev_priv->topaz_last_sequence = + dev_priv->topaz_current_sequence; + *topaz_idle = 0; + } + + if (dev_priv->topaz_start_idle) + dev_priv->topaz_start_idle = 0; + } else { + if (dev_priv->topaz_needs_reset == 0) { + if (dev_priv->topaz_start_idle && + (dev_priv->topaz_finished_sequence + == dev_priv->topaz_current_sequence)) { + if (time_after_eq(jiffies, + dev_priv->topaz_idle_start_jiffies + + TOPAZ_MAX_IDELTIME)) { + + /* XXX: disable clock <msvdx does> */ + dev_priv->topaz_needs_reset = 1; + } else + *topaz_idle = 0; + } else { + dev_priv->topaz_start_idle = 1; + dev_priv->topaz_idle_start_jiffies = jiffies; + dev_priv->topaz_finished_sequence = + dev_priv->topaz_current_sequence; + *topaz_idle = 0; + } + } + } + spin_unlock_irqrestore(&dev_priv->topaz_lock, irq_flags); +} + + +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); +} + +/* power up msvdx, OSPM function */ +int psb_power_up_topaz(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = + (struct drm_psb_private *)dev->dev_private; + + if (dev_priv->topaz_power_state == LNC_TOPAZ_POWERON) + return 0; + + psb_up_island_power(dev, PSB_VIDEO_ENC_ISLAND); + + PSB_DEBUG_GENERAL("FIXME: how to write clock state for topaz?" + " so many clock\n"); + /* PSB_WMSVDX32(dev_priv->topaz_clk_state, MSVDX_MAN_CLK_ENABLE); */ + + PSB_DEBUG_GENERAL("FIXME restore registers or init msvdx\n"); + + PSB_DEBUG_GENERAL("FIXME: flush all mmu\n"); + + dev_priv->topaz_power_state = LNC_TOPAZ_POWERON; + + return 0; +} + +int psb_power_down_topaz(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = + (struct drm_psb_private *)dev->dev_private; + + if (dev_priv->topaz_power_state == LNC_TOPAZ_POWEROFF) + return 0; + + if (dev_priv->topaz_busy) { + PSB_DEBUG_GENERAL("FIXME: MSVDX is busy, should wait it\n"); + return -EBUSY; + } + PSB_DEBUG_GENERAL("FIXME: how to read clock state for topaz?" + " so many clock\n"); + /* dev_priv->topaz_clk_state = PSB_RMSVDX32(MSVDX_MAN_CLK_ENABLE); */ + PSB_DEBUG_GENERAL("FIXME: save MSVDX register\n"); + PSB_DEBUG_GENERAL("FIXME: save MSVDX context\n"); + + psb_down_island_power(dev, PSB_VIDEO_ENC_ISLAND); + + dev_priv->topaz_power_state = LNC_TOPAZ_POWEROFF; + + return 0; +} + +int lnc_prepare_topaz_suspend(struct drm_device *dev) +{ + /* FIXME: need reset when resume? + * Is mtx restore enough for encoder continue run? */ + /* dev_priv->topaz_needs_reset = 1; */ + + /* make sure all IRQs are seviced */ + + /* make sure all the fence is signaled */ + + /* save mtx context into somewhere */ + /* lnc_topaz_save_mtx_state(dev); */ + + return 0; +} + +int lnc_prepare_topaz_resume(struct drm_device *dev) +{ + /* FIXME: need reset when resume? + * Is mtx restore enough for encoder continue run? */ + /* dev_priv->topaz_needs_reset = 1; */ + + /* make sure IRQ is open */ + + /* restore mtx context */ + /* lnc_topaz_restore_mtx_state(dev); */ + + return 0; +} |