int vsp_setup_fw(struct drm_psb_private *dev_priv)
{
	struct vsp_private *vsp_priv = dev_priv->vsp_private;
	uint32_t pd_addr;

	/* set MMU */
	pd_addr = psb_get_default_pd_addr(dev_priv->vsp_mmu);
	SET_MMU_PTD(pd_addr >> PAGE_TABLE_SHIFT);
	SET_MMU_PTD(pd_addr >> PAGE_SHIFT);

	/* vsp setting */
	vsp_priv->setting->command_queue_size = VSP_CMD_QUEUE_SIZE;
	vsp_priv->setting->command_queue_addr = vsp_priv->cmd_queue_bo->offset;
	vsp_priv->setting->response_queue_size = VSP_ACK_QUEUE_SIZE;
	vsp_priv->setting->response_queue_addr = vsp_priv->ack_queue_bo->offset;

	vsp_priv->ctrl->setting_addr = vsp_priv->setting_bo->offset;
	vsp_priv->ctrl->mmu_tlb_soft_invalidate = 0;
	vsp_priv->ctrl->cmd_rd = 0;
	vsp_priv->ctrl->cmd_wr = 0;
	vsp_priv->ctrl->ack_rd = 0;
	vsp_priv->ctrl->ack_wr = 0;

	VSP_DEBUG("setup firmware\n");

	/* Set power-saving mode */
	if (drm_vsp_pmpolicy == PSB_PMPOLICY_NOPM)
		vsp_priv->ctrl->power_saving_mode = vsp_always_on;
	else if (drm_vsp_pmpolicy == PSB_PMPOLICY_POWERDOWN ||
			drm_vsp_pmpolicy == PSB_PMPOLICY_CLOCKGATING)
		vsp_priv->ctrl->power_saving_mode = vsp_suspend_on_empty_queue;
	else
		vsp_priv->ctrl->power_saving_mode =
			vsp_suspend_and_hw_idle_on_empty_queue;

	/* communicate the type of init
	 * this is the last value to write
	 * it will cause the VSP to read all other settings as wll
	 */
	vsp_priv->ctrl->entry_kind = vsp_entry_init;

	vsp_priv->vsp_state = VSP_STATE_ACTIVE;

	/* enable irq */
	psb_irq_preinstall_islands(dev_priv->dev, OSPM_VIDEO_VPP_ISLAND);
	psb_irq_postinstall_islands(dev_priv->dev, OSPM_VIDEO_VPP_ISLAND);

	return 0;
}
int vsp_resume_function(struct drm_psb_private *dev_priv)
{
	struct vsp_private *vsp_priv = dev_priv->vsp_private;
	struct pci_dev *pdev = vsp_priv->dev->pdev;
	uint32_t pd_addr, mmadr;

	/* FIXME, change should be removed once bz 120324 is fixed */
	pci_read_config_dword(pdev, 0x10, &mmadr);
	if (mmadr == 0) {
		DRM_ERROR("Bad PCI config!\n");
		return -1;
	}

	vsp_priv->ctrl = (struct vsp_ctrl_reg *) (dev_priv->vsp_reg +
						  VSP_CONFIG_REG_SDRAM_BASE +
						  VSP_CONFIG_REG_START);

	/* Set MMU */
	pd_addr = psb_get_default_pd_addr(dev_priv->vsp_mmu);
	SET_MMU_PTD(pd_addr >> PAGE_TABLE_SHIFT);
	SET_MMU_PTD(pd_addr >> PAGE_SHIFT);

	/* enable irq */
	psb_irq_preinstall_islands(dev_priv->dev, OSPM_VIDEO_VPP_ISLAND);
	psb_irq_postinstall_islands(dev_priv->dev, OSPM_VIDEO_VPP_ISLAND);

	/* restore the config regs */
	CONFIG_REG_WRITE32(VSP_SETTING_ADDR_REG,
			vsp_priv->saved_config_regs[VSP_SETTING_ADDR_REG]);
	CONFIG_REG_WRITE32(VSP_POWER_SAVING_MODE_REG,
			vsp_priv->saved_config_regs[VSP_POWER_SAVING_MODE_REG]);
	CONFIG_REG_WRITE32(VSP_CMD_QUEUE_RD_REG,
			vsp_priv->saved_config_regs[VSP_CMD_QUEUE_RD_REG]);
	CONFIG_REG_WRITE32(VSP_CMD_QUEUE_WR_REG,
			vsp_priv->saved_config_regs[VSP_CMD_QUEUE_WR_REG]);
	CONFIG_REG_WRITE32(VSP_ACK_QUEUE_RD_REG,
			vsp_priv->saved_config_regs[VSP_ACK_QUEUE_RD_REG]);
	CONFIG_REG_WRITE32(VSP_ACK_QUEUE_WR_REG,
			vsp_priv->saved_config_regs[VSP_ACK_QUEUE_WR_REG]);

	vsp_priv->ctrl->entry_kind = vsp_entry_resume;

	vsp_priv->vsp_state = VSP_STATE_ACTIVE;

	return 0;
}
static void msvdx_upload_fw(struct drm_psb_private *dev_priv,
			  uint32_t address, const unsigned int words, int fw_sel)
{
	uint32_t reg_val = 0;
	uint32_t cmd;
	uint32_t uCountReg, offset, mmu_ptd;
	uint32_t size = (words * 4); /* byte count */
	uint32_t dma_channel = 0; /* Setup a Simple DMA for Ch0 */
	struct msvdx_private *msvdx_priv = dev_priv->msvdx_private;

	PSB_DEBUG_GENERAL("MSVDX: Upload firmware by DMA\n");
	msvdx_get_mtx_control_from_dash(dev_priv);

	/* dma transfers to/from the mtx have to be 32-bit aligned and in multiples of 32 bits */
	PSB_WMSVDX32(address, MTX_SYSC_CDMAA_OFFSET);

	REGIO_WRITE_FIELD_LITE(reg_val, MTX_SYSC_CDMAC, BURSTSIZE,	4); /* burst size in multiples of 64 bits (allowed values are 2 or 4) */
	REGIO_WRITE_FIELD_LITE(reg_val, MTX_SYSC_CDMAC, RNW, 0);	/* false means write to mtx mem, true means read from mtx mem */
	REGIO_WRITE_FIELD_LITE(reg_val, MTX_SYSC_CDMAC, ENABLE,	1);				/* begin transfer */
	REGIO_WRITE_FIELD_LITE(reg_val, MTX_SYSC_CDMAC, LENGTH,	words);		/* This specifies the transfer size of the DMA operation in terms of 32-bit words */
	PSB_WMSVDX32(reg_val, MTX_SYSC_CDMAC_OFFSET);

	/* toggle channel 0 usage between mtx and other msvdx peripherals */
	{
		reg_val = PSB_RMSVDX32(MSVDX_CONTROL_OFFSET);
		REGIO_WRITE_FIELD(reg_val, MSVDX_CONTROL, DMAC_CH0_SELECT,  0);
		PSB_WMSVDX32(reg_val, MSVDX_CONTROL_OFFSET);
	}


	/* Clear the DMAC Stats */
	PSB_WMSVDX32(0 , DMAC_DMAC_IRQ_STAT_OFFSET + dma_channel);

	offset = msvdx_priv->fw->offset;

	if (fw_sel)
		offset += ((msvdx_priv->mtx_mem_size + 8192) & ~0xfff);

	/* use bank 0 */
	cmd = 0;
	PSB_WMSVDX32(cmd, MSVDX_MMU_BANK_INDEX_OFFSET);

	/* Write PTD to mmu base 0*/
	mmu_ptd = psb_get_default_pd_addr(dev_priv->mmu);
	PSB_WMSVDX32(mmu_ptd, MSVDX_MMU_DIR_LIST_BASE_OFFSET + 0);

	/* Invalidate */
	reg_val = PSB_RMSVDX32(MSVDX_MMU_CONTROL0_OFFSET);
	reg_val &= ~0xf;
	REGIO_WRITE_FIELD(reg_val, MSVDX_MMU_CONTROL0, MMU_INVALDC, 1);
	PSB_WMSVDX32(reg_val, MSVDX_MMU_CONTROL0_OFFSET);

	PSB_WMSVDX32(offset, DMAC_DMAC_SETUP_OFFSET + dma_channel);

	/* Only use a single dma - assert that this is valid */
	if ((size / 4) >= (1 << 15)) {
		DRM_ERROR("psb: DMA size beyond limited, aboart firmware uploading\n");
		return;
	}

	uCountReg = PSB_DMAC_VALUE_COUNT(PSB_DMAC_BSWAP_NO_SWAP,
					 0,  /* 32 bits */
					 PSB_DMAC_DIR_MEM_TO_PERIPH,
					 0,
					 (size / 4));
	/* Set the number of bytes to dma*/
	PSB_WMSVDX32(uCountReg, DMAC_DMAC_COUNT_OFFSET + dma_channel);

	cmd = PSB_DMAC_VALUE_PERIPH_PARAM(PSB_DMAC_ACC_DEL_0, PSB_DMAC_INCR_OFF, PSB_DMAC_BURST_2);
	PSB_WMSVDX32(cmd, DMAC_DMAC_PERIPH_OFFSET + dma_channel);

	/* Set destination port for dma */
	cmd = 0;
	REGIO_WRITE_FIELD(cmd, DMAC_DMAC_PERIPHERAL_ADDR, ADDR, MTX_SYSC_CDMAT_OFFSET);
	PSB_WMSVDX32(cmd, DMAC_DMAC_PERIPHERAL_ADDR_OFFSET + dma_channel);


	/* Finally, rewrite the count register with the enable bit set*/
	PSB_WMSVDX32(uCountReg | DMAC_DMAC_COUNT_EN_MASK, DMAC_DMAC_COUNT_OFFSET + dma_channel);

	/* Wait for all to be done */
	if (psb_wait_for_register(dev_priv,
				  DMAC_DMAC_IRQ_STAT_OFFSET + dma_channel,
				  DMAC_DMAC_IRQ_STAT_TRANSFER_FIN_MASK,
				  DMAC_DMAC_IRQ_STAT_TRANSFER_FIN_MASK,
				  2000000, 5)) {
		psb_setup_fw_dump(dev_priv, dma_channel);
		msvdx_release_mtx_control_from_dash(dev_priv);
		return;
	}

	/* Assert that the MTX DMA port is all done aswell */
	if (psb_wait_for_register(dev_priv,
			MTX_SYSC_CDMAS0_OFFSET,
			1, 1, 2000000, 5)) {
		msvdx_release_mtx_control_from_dash(dev_priv);
		return;
	}

	msvdx_release_mtx_control_from_dash(dev_priv);

	PSB_DEBUG_GENERAL("MSVDX: Upload done\n");
}