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"); }