diff options
Diffstat (limited to 'drivers/staging/cdv/imgv/psb_msvdxinit.c')
-rw-r--r-- | drivers/staging/cdv/imgv/psb_msvdxinit.c | 1164 |
1 files changed, 1164 insertions, 0 deletions
diff --git a/drivers/staging/cdv/imgv/psb_msvdxinit.c b/drivers/staging/cdv/imgv/psb_msvdxinit.c new file mode 100644 index 000000000000..5ea5c83656f6 --- /dev/null +++ b/drivers/staging/cdv/imgv/psb_msvdxinit.c @@ -0,0 +1,1164 @@ +/************************************************************************** + * psb_msvdxinit.c + * MSVDX initialization and mtx-firmware upload + * + * Copyright (c) 2011 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 <drm/drmP.h> +#include <drm/drm.h> +#include "psb_drv.h" +#include "psb_msvdx.h" +#include <linux/firmware.h> + +#define MSVDX_REG (dev_priv->msvdx_reg) +#define UPLOAD_FW_BY_DMA 1 +#define STACKGUARDWORD ( 0x10101010 ) +#define MSVDX_MTX_DATA_LOCATION ( 0x82880000 ) +#define UNINITILISE_MEM ( 0xcdcdcdcd ) +#define FIRMWAREID ( 0x014d42ab ) + +uint8_t psb_rev_id; +/*MSVDX FW header*/ +struct msvdx_fw { + uint32_t ver; + uint32_t text_size; + uint32_t data_size; + uint32_t data_location; +}; + +int psb_wait_for_register(struct drm_psb_private *dev_priv, + uint32_t offset, uint32_t value, uint32_t enable) +{ + uint32_t reg_value; + uint32_t poll_cnt = 10000; + while (poll_cnt) { + reg_value = PSB_RMSVDX32(offset); + if (value == (reg_value & enable)) /* All the bits are reset */ + return 0; /* So exit */ + + /* Wait a bit */ + DRM_UDELAY(1000); + poll_cnt--; + } + DRM_ERROR("MSVDX: Timeout while waiting for register %08x:" + " expecting %08x (mask %08x), got %08x\n", + offset, value, enable, reg_value); + + return 1; +} + +int psb_poll_mtx_irq(struct drm_psb_private *dev_priv) +{ + int ret = 0; + uint32_t mtx_int = 0; + + REGIO_WRITE_FIELD_LITE(mtx_int, MSVDX_INTERRUPT_STATUS, CR_MTX_IRQ, + 1); + + ret = psb_wait_for_register(dev_priv, MSVDX_INTERRUPT_STATUS, + /* Required value */ + mtx_int, + /* Enabled bits */ + mtx_int); + + if (ret) { + DRM_ERROR("MSVDX: Error Mtx did not return" + " int within a resonable time\n"); + return ret; + } + + PSB_DEBUG_IRQ("MSVDX: Got MTX Int\n"); + + /* Got it so clear the bit */ + PSB_WMSVDX32(mtx_int, MSVDX_INTERRUPT_CLEAR); + + return ret; +} + +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; + + /* Put data in MTX_RW_DATA */ + PSB_WMSVDX32(val, MSVDX_MTX_REGISTER_READ_WRITE_DATA); + + /* DREADY is set to 0 and request a write */ + reg = core_reg; + REGIO_WRITE_FIELD_LITE(reg, MSVDX_MTX_REGISTER_READ_WRITE_REQUEST, + MTX_RNW, 0); + REGIO_WRITE_FIELD_LITE(reg, MSVDX_MTX_REGISTER_READ_WRITE_REQUEST, + MTX_DREADY, 0); + PSB_WMSVDX32(reg, MSVDX_MTX_REGISTER_READ_WRITE_REQUEST); + + psb_wait_for_register(dev_priv, + MSVDX_MTX_REGISTER_READ_WRITE_REQUEST, + MSVDX_MTX_REGISTER_READ_WRITE_REQUEST_MTX_DREADY_MASK, + MSVDX_MTX_REGISTER_READ_WRITE_REQUEST_MTX_DREADY_MASK); +} + +#if UPLOAD_FW_BY_DMA + +static void psb_get_mtx_control_from_dash(struct drm_psb_private *dev_priv) +{ + struct msvdx_private *msvdx_priv = dev_priv->msvdx_private; + int count = 0; + uint32_t reg_val = 0; + + REGIO_WRITE_FIELD(reg_val, MSVDX_MTX_DEBUG, MTX_DBG_IS_SLAVE, 1); + REGIO_WRITE_FIELD(reg_val, MSVDX_MTX_DEBUG, MTX_DBG_GPIO_IN, 0x02); + PSB_WMSVDX32(reg_val, MSVDX_MTX_DEBUG); + + do + { + reg_val = PSB_RMSVDX32(MSVDX_MTX_DEBUG); + count++; + } while (((reg_val & 0x18) != 0) && count < 50000); + + if(count >= 50000) + PSB_DEBUG_GENERAL("TOPAZ: timeout in get_mtx_control_from_dash\n"); + + /* Save the access control register...*/ + msvdx_priv->psb_dash_access_ctrl = PSB_RMSVDX32(MSVDX_MTX_RAM_ACCESS_CONTROL); + +} + +static void psb_release_mtx_control_from_dash(struct drm_psb_private *dev_priv) +{ + struct msvdx_private *msvdx_priv = dev_priv->msvdx_private; + + /* restore access control */ + PSB_WMSVDX32(msvdx_priv->psb_dash_access_ctrl, MSVDX_MTX_RAM_ACCESS_CONTROL); + /* release bus */ + 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) +{ + 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"); + psb_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, REGISTER(MTX_CORE, CR_MTX_SYSC_CDMAA)); + + REGIO_WRITE_FIELD_LITE(reg_val, MTX_CORE_CR_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_CORE_CR_MTX_SYSC_CDMAC, RNW, 0); // false means write to mtx mem, true means read from mtx mem + REGIO_WRITE_FIELD_LITE(reg_val, MTX_CORE_CR_MTX_SYSC_CDMAC, ENABLE, 1); // begin transfer + REGIO_WRITE_FIELD_LITE(reg_val, MTX_CORE_CR_MTX_SYSC_CDMAC, LENGTH, words ); // This specifies the transfer size of the DMA operation in terms of 32-bit words + PSB_WMSVDX32(reg_val, REGISTER(MTX_CORE, CR_MTX_SYSC_CDMAC)); + + // toggle channel 0 usage between mtx and other msvdx peripherals + { + reg_val = PSB_RMSVDX32(REGISTER( MSVDX_CORE, CR_MSVDX_CONTROL)); + REGIO_WRITE_FIELD(reg_val, MSVDX_CORE_CR_MSVDX_CONTROL, DMAC_CH0_SELECT, 0 ); + PSB_WMSVDX32(reg_val, REGISTER( MSVDX_CORE, CR_MSVDX_CONTROL)); + } + + + /* Clear the DMAC Stats */ + PSB_WMSVDX32(0 , REGISTER(DMAC, DMAC_IRQ_STAT ) + 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, REGISTER(MSVDX_CORE, CR_MMU_BANK_INDEX)); + + /* Write PTD to mmu base 0*/ + mmu_ptd = psb_get_default_pd_addr(dev_priv->mmu); + PSB_WMSVDX32(mmu_ptd, REGISTER( MSVDX_CORE, CR_MMU_DIR_LIST_BASE) + 0); + + /* Invalidate */ + reg_val = PSB_RMSVDX32(REGISTER(MSVDX_CORE, CR_MMU_CONTROL0)); + reg_val &= ~0xf; + REGIO_WRITE_FIELD(reg_val, MSVDX_CORE_CR_MMU_CONTROL0, CR_MMU_INVALDC, 1 ); + PSB_WMSVDX32(reg_val, REGISTER(MSVDX_CORE, CR_MMU_CONTROL0 )); + + PSB_WMSVDX32(offset, REGISTER(DMAC, DMAC_SETUP ) + 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, REGISTER(DMAC, DMAC_COUNT ) + dma_channel); + + cmd = PSB_DMAC_VALUE_PERIPH_PARAM(PSB_DMAC_ACC_DEL_0, PSB_DMAC_INCR_OFF, PSB_DMAC_BURST_2); + PSB_WMSVDX32(cmd, REGISTER(DMAC, DMAC_PERIPH ) + dma_channel); + + /* Set destination port for dma */ + cmd = 0; + REGIO_WRITE_FIELD(cmd, DMAC_DMAC_PERIPHERAL_ADDR, ADDR, MTX_CORE_CR_MTX_SYSC_CDMAT_OFFSET); + PSB_WMSVDX32(cmd, REGISTER(DMAC, DMAC_PERIPHERAL_ADDR ) + dma_channel); + + + /* Finally, rewrite the count register with the enable bit set*/ + PSB_WMSVDX32(uCountReg | DMAC_DMAC_COUNT_EN_MASK, REGISTER(DMAC, DMAC_COUNT ) + dma_channel); + + /* Wait for all to be done */ + if(psb_wait_for_register(dev_priv, + REGISTER(DMAC, DMAC_IRQ_STAT ) + dma_channel, + DMAC_DMAC_IRQ_STAT_TRANSFER_FIN_MASK, + DMAC_DMAC_IRQ_STAT_TRANSFER_FIN_MASK )) { + psb_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, REGISTER(MTX_CORE, CR_MTX_SYSC_CDMAS0), 1, 1)) { + psb_release_mtx_control_from_dash(dev_priv); + return; + } + + psb_release_mtx_control_from_dash(dev_priv); + PSB_DEBUG_GENERAL("MSVDX: Upload done\n"); +} + +#else + +static void psb_upload_fw(struct drm_psb_private *dev_priv, + const uint32_t data_mem, uint32_t ram_bank_size, + uint32_t address, const unsigned int words, + const uint32_t * const data) +{ + uint32_t loop, ctrl, ram_id, addr, cur_bank = (uint32_t) ~0; + uint32_t access_ctrl; + + PSB_DEBUG_GENERAL("MSVDX: Upload firmware by register interface\n"); + /* Save the access control register... */ + access_ctrl = PSB_RMSVDX32(MSVDX_MTX_RAM_ACCESS_CONTROL); + + /* Wait for MCMSTAT to become be idle 1 */ + psb_wait_for_register(dev_priv, MSVDX_MTX_RAM_ACCESS_STATUS, + 1, /* Required Value */ + 0xffffffff /* Enables */); + + for (loop = 0; loop < words; loop++) { + ram_id = data_mem + (address / ram_bank_size); + if (ram_id != cur_bank) { + addr = address >> 2; + ctrl = 0; + REGIO_WRITE_FIELD_LITE(ctrl, + MSVDX_MTX_RAM_ACCESS_CONTROL, + MTX_MCMID, ram_id); + REGIO_WRITE_FIELD_LITE(ctrl, + MSVDX_MTX_RAM_ACCESS_CONTROL, + MTX_MCM_ADDR, addr); + REGIO_WRITE_FIELD_LITE(ctrl, + MSVDX_MTX_RAM_ACCESS_CONTROL, + MTX_MCMAI, 1); + PSB_WMSVDX32(ctrl, MSVDX_MTX_RAM_ACCESS_CONTROL); + cur_bank = ram_id; + } + address += 4; + + PSB_WMSVDX32(data[loop], + MSVDX_MTX_RAM_ACCESS_DATA_TRANSFER); + + /* Wait for MCMSTAT to become be idle 1 */ + psb_wait_for_register(dev_priv, MSVDX_MTX_RAM_ACCESS_STATUS, + 1, /* Required Value */ + 0xffffffff /* Enables */); + } + PSB_DEBUG_GENERAL("MSVDX: Upload done\n"); + + /* Restore the access control register... */ + PSB_WMSVDX32(access_ctrl, MSVDX_MTX_RAM_ACCESS_CONTROL); +} + +#endif + +static int psb_verify_fw(struct drm_psb_private *dev_priv, + const uint32_t ram_bank_size, + const uint32_t data_mem, uint32_t address, + const uint32_t words, const uint32_t * const data) +{ + uint32_t loop, ctrl, ram_id, addr, cur_bank = (uint32_t) ~0; + uint32_t access_ctrl; + int ret = 0; + + /* Save the access control register... */ + access_ctrl = PSB_RMSVDX32(MSVDX_MTX_RAM_ACCESS_CONTROL); + + /* Wait for MCMSTAT to become be idle 1 */ + psb_wait_for_register(dev_priv, MSVDX_MTX_RAM_ACCESS_STATUS, + 1, /* Required Value */ + 0xffffffff /* Enables */); + + for (loop = 0; loop < words; loop++) { + uint32_t reg_value; + ram_id = data_mem + (address / ram_bank_size); + + if (ram_id != cur_bank) { + addr = address >> 2; + ctrl = 0; + REGIO_WRITE_FIELD_LITE(ctrl, + MSVDX_MTX_RAM_ACCESS_CONTROL, + MTX_MCMID, ram_id); + REGIO_WRITE_FIELD_LITE(ctrl, + MSVDX_MTX_RAM_ACCESS_CONTROL, + MTX_MCM_ADDR, addr); + REGIO_WRITE_FIELD_LITE(ctrl, + MSVDX_MTX_RAM_ACCESS_CONTROL, + MTX_MCMAI, 1); + REGIO_WRITE_FIELD_LITE(ctrl, + MSVDX_MTX_RAM_ACCESS_CONTROL, + MTX_MCMR, 1); + + PSB_WMSVDX32(ctrl, MSVDX_MTX_RAM_ACCESS_CONTROL); + + cur_bank = ram_id; + } + address += 4; + + /* Wait for MCMSTAT to become be idle 1 */ + psb_wait_for_register(dev_priv, MSVDX_MTX_RAM_ACCESS_STATUS, + 1, /* Required Value */ + 0xffffffff /* Enables */); + + reg_value = PSB_RMSVDX32(MSVDX_MTX_RAM_ACCESS_DATA_TRANSFER); + if (data[loop] != reg_value) { + DRM_ERROR("psb: Firmware validation fails" + " at index=%08x\n", loop); + ret = 1; + break; + } + } + + /* Restore the access control register... */ + PSB_WMSVDX32(access_ctrl, MSVDX_MTX_RAM_ACCESS_CONTROL); + + return ret; +} + +static int msvdx_get_fw_bo(struct drm_device *dev, + const struct firmware **raw, uint8_t *name) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + int rc, fw_size; + void *ptr = NULL; + struct ttm_bo_kmap_obj tmp_kmap; + bool is_iomem; + struct msvdx_private *msvdx_priv = dev_priv->msvdx_private; + void *gpu_addr; + + rc = request_firmware(raw, name, &dev->pdev->dev); + if (rc < 0) { + DRM_ERROR("MSVDX: %s request_firmware failed: Reason %d\n", + name, rc); + return 1; + } + + if ((*raw)->size < sizeof(struct msvdx_fw)) { + DRM_ERROR("MSVDX: %s is is not correct size(%zd)\n", + name, (*raw)->size); + return 1; + } + + ptr = (void *) ((*raw))->data; + + if (!ptr) { + DRM_ERROR("MSVDX: Failed to load %s\n", name); + return 1; + } + + /* another sanity check... */ + fw_size = sizeof(struct msvdx_fw) + + sizeof(uint32_t) * ((struct msvdx_fw *) ptr)->text_size + + sizeof(uint32_t) * ((struct msvdx_fw *) ptr)->data_size; + if ((*raw)->size < fw_size) { + DRM_ERROR("MSVDX: %s is is not correct size(%zd)\n", + name, (*raw)->size); + return 1; + } + + rc = ttm_bo_kmap(msvdx_priv->fw, 0, (msvdx_priv->fw)->num_pages, &tmp_kmap); + if (rc) { + PSB_DEBUG_GENERAL("drm_bo_kmap failed: %d\n", rc); + ttm_bo_unref(&msvdx_priv->fw); + ttm_bo_kunmap(&tmp_kmap); + return 1; + } + else { + uint32_t *last_word; + gpu_addr = ttm_kmap_obj_virtual(&tmp_kmap, &is_iomem); + + 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); + /* Write a know value to last word in mtx memory*/ + /* Usefull for detection of stack overrun */ + *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"); + release_firmware(*raw); + return rc; +} + + +static uint32_t *msvdx_get_fw(struct drm_device *dev, + const struct firmware **raw, uint8_t *name) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + int rc, fw_size; + void *ptr = NULL; + struct msvdx_private *msvdx_priv = dev_priv->msvdx_private; + + rc = request_firmware(raw, name, &dev->pdev->dev); + if (rc < 0) { + DRM_ERROR("MSVDX: %s request_firmware failed: Reason %d\n", + name, rc); + return NULL; + } + + if ((*raw)->size < sizeof(struct msvdx_fw)) { + DRM_ERROR("MSVDX: %s is is not correct size(%zd)\n", + name, (*raw)->size); + return NULL; + } + + ptr = (int *) ((*raw))->data; + + if (!ptr) { + DRM_ERROR("MSVDX: Failed to load %s\n", name); + return NULL; + } + + /* another sanity check... */ + fw_size = sizeof(struct msvdx_fw) + + sizeof(uint32_t) * ((struct msvdx_fw *) ptr)->text_size + + sizeof(uint32_t) * ((struct msvdx_fw *) ptr)->data_size; + if ((*raw)->size < fw_size) { + DRM_ERROR("MSVDX: %s is is not correct size(%zd)\n", + name, (*raw)->size); + return NULL; + } + else if((*raw)->size > fw_size) { /* there is ec firmware */ + ptr += ((fw_size + 0xfff) & ~0xfff); + fw_size += (sizeof(struct msvdx_fw) + + sizeof(uint32_t) * ((struct msvdx_fw *) ptr)->text_size + + sizeof(uint32_t) * ((struct msvdx_fw *) ptr)->data_size); + + ptr = (int *) ((*raw))->data; /* Resotre ptr to start of the firmware file */ + } + + msvdx_priv->msvdx_fw = kzalloc(fw_size, GFP_KERNEL); + if (msvdx_priv->msvdx_fw == NULL) + DRM_ERROR("MSVDX: allocate FW buffer failed\n"); + else { + memcpy(msvdx_priv->msvdx_fw, ptr, fw_size); + msvdx_priv->msvdx_fw_size = fw_size; + } + + PSB_DEBUG_GENERAL("MSVDX: releasing firmware resouces\n"); + release_firmware(*raw); + + return msvdx_priv->msvdx_fw; +} + +int psb_setup_fw(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + uint32_t ram_bank_size; + struct msvdx_fw *fw; + uint32_t *fw_ptr = NULL; + uint32_t *text_ptr = NULL; + uint32_t *data_ptr = NULL; + const struct firmware *raw = NULL; + struct msvdx_private *msvdx_priv = dev_priv->msvdx_private; + int ec_firmware = 0, ret = 0; + + /* 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); + + /* Reset MTX */ + PSB_WMSVDX32(MSVDX_MTX_SOFT_RESET_MTX_RESET_MASK, + MSVDX_MTX_SOFT_RESET); + + /* Initialses Communication controll area to 0 */ +/* + if (psb_rev_id >= POULSBO_D1) { + PSB_DEBUG_GENERAL("MSVDX: Detected Poulsbo D1" + " or later revision.\n"); + PSB_WMSVDX32(MSVDX_DEVICE_NODE_FLAGS_DEFAULT_D1, + MSVDX_COMMS_OFFSET_FLAGS); + } else { + PSB_DEBUG_GENERAL("MSVDX: Detected Poulsbo D0" + " or earlier revision.\n"); + PSB_WMSVDX32(MSVDX_DEVICE_NODE_FLAGS_DEFAULT_D0, + MSVDX_COMMS_OFFSET_FLAGS); + } +*/ + + if(IS_CDV(dev)) { + PSB_WMSVDX32(FIRMWAREID, MSVDX_COMMS_FIRMWARE_ID); + } + + PSB_WMSVDX32(0, MSVDX_COMMS_ERROR_TRIG); + PSB_WMSVDX32(199, MSVDX_MTX_SYSC_TIMERDIV); /* MTX_SYSC_TIMERDIV */ + PSB_WMSVDX32(0, MSVDX_EXT_FW_ERROR_STATE); /* EXT_FW_ERROR_STATE */ + + PSB_WMSVDX32(0, MSVDX_COMMS_MSG_COUNTER); + PSB_WMSVDX32(0, MSVDX_COMMS_SIGNATURE); + PSB_WMSVDX32(0, MSVDX_COMMS_TO_HOST_RD_INDEX); + PSB_WMSVDX32(0, MSVDX_COMMS_TO_HOST_WRT_INDEX); + PSB_WMSVDX32(0, MSVDX_COMMS_TO_MTX_RD_INDEX); + PSB_WMSVDX32(0, MSVDX_COMMS_TO_MTX_WRT_INDEX); + PSB_WMSVDX32(0, MSVDX_COMMS_FW_STATUS); + PSB_WMSVDX32(DSIABLE_IDLE_GPIO_SIG | DSIABLE_Auto_CLOCK_GATING | RETURN_VDEB_DATA_IN_COMPLETION | DSIABLE_FW_WDT, + MSVDX_COMMS_OFFSET_FLAGS); + PSB_WMSVDX32(0, MSVDX_COMMS_SIGNATURE); + /* read register bank size */ + { + uint32_t bank_size, reg; + reg = PSB_RMSVDX32(MSVDX_MTX_RAM_BANK); + bank_size = + REGIO_READ_FIELD(reg, MSVDX_MTX_RAM_BANK, + CR_MTX_RAM_BANK_SIZE); + ram_bank_size = (uint32_t) (1 << (bank_size + 2)); + } + + PSB_DEBUG_GENERAL("MSVDX: RAM bank size = %d bytes\n", + ram_bank_size); + + /* if FW already loaded from storage */ + if (msvdx_priv->msvdx_fw) + fw_ptr = msvdx_priv->msvdx_fw; + else { + if (IS_CDV(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_CDV(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 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; + } +#else + (void)psb_verify_fw; +#endif + /* -- Set starting PC address */ + psb_write_mtx_core_reg(dev_priv, MTX_PC, PC_START_ADDRESS); + + /* -- Turn on the thread */ + PSB_WMSVDX32(MSVDX_MTX_ENABLE_MTX_ENABLE_MASK, MSVDX_MTX_ENABLE); + + /* Wait for the signature value to be written back */ + ret = psb_wait_for_register(dev_priv, MSVDX_COMMS_SIGNATURE, + MSVDX_COMMS_SIGNATURE_VALUE, /*Required value*/ + 0xffffffff /* Enabled bits */); + if (ret) { + DRM_ERROR("MSVDX: firmware fails to initialize.\n"); + goto out; + } + + PSB_DEBUG_GENERAL("MSVDX: MTX Initial indications OK\n"); + PSB_DEBUG_GENERAL("MSVDX: MSVDX_COMMS_AREA_ADDR = %08x\n", + MSVDX_COMMS_AREA_ADDR); +#if 0 + + /* Send test message */ + { + uint32_t msg_buf[FW_VA_DEBUG_TEST2_SIZE >> 2]; + + MEMIO_WRITE_FIELD(msg_buf, FW_VA_DEBUG_TEST2_MSG_SIZE, + FW_VA_DEBUG_TEST2_SIZE); + MEMIO_WRITE_FIELD(msg_buf, FW_VA_DEBUG_TEST2_ID, + VA_MSGID_TEST2); + + ret = psb_mtx_send(dev_priv, msg_buf); + if (ret) { + DRM_ERROR("psb: MSVDX sending fails.\n"); + goto out; + } + + /* Wait for Mtx to ack this message */ + psb_poll_mtx_irq(dev_priv); + + } +#endif +out: + + return ret; +} + + +static void psb_free_ccb(struct ttm_buffer_object **ccb) +{ + ttm_bo_unref(ccb); + *ccb = NULL; +} + +/** + * Reset chip and disable interrupts. + * Return 0 success, 1 failure + */ +int psb_msvdx_reset(struct drm_psb_private *dev_priv) +{ + int ret = 0; + + if(IS_PENWELL(dev_priv->dev)) { + int loop; + /* Enable Clocks */ + PSB_DEBUG_GENERAL("Enabling clocks\n"); + PSB_WMSVDX32(clk_enable_all, MSVDX_MAN_CLK_ENABLE); + + /* Always pause the MMU as the core may be still active when resetting. It is very bad to have memory + activity at the same time as a reset - Very Very bad */ + PSB_WMSVDX32(2, MSVDX_MMU_CONTROL0); + + for(loop = 0; loop < 50; loop++) + ret = psb_wait_for_register(dev_priv, MSVDX_MMU_MEM_REQ, 0, + 0xff); + if(ret) + return ret; + } + /* 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); + + if (!ret) { + /* Clear interrupt enabled flag */ + PSB_WMSVDX32(0, MSVDX_HOST_INTERRUPT_ENABLE); + + /* Clear any pending interrupt flags */ + PSB_WMSVDX32(0xFFFFFFFF, MSVDX_INTERRUPT_CLEAR); + } + + /* mutex_destroy(&msvdx_priv->msvdx_mutex); */ + + return ret; +} + +static int psb_allocate_ccb(struct drm_device *dev, + struct ttm_buffer_object **ccb, + uint32_t *base_addr, unsigned long size) +{ + struct drm_psb_private *dev_priv = psb_priv(dev); + struct ttm_bo_device *bdev = &dev_priv->bdev; + int ret; + struct ttm_bo_kmap_obj tmp_kmap; + bool is_iomem; + + PSB_DEBUG_INIT("MSVDX: allocate CCB\n"); + + ret = ttm_buffer_object_create(bdev, size, + ttm_bo_type_kernel, + DRM_PSB_FLAG_MEM_MMU | + TTM_PL_FLAG_NO_EVICT, 0, 0, 0, + NULL, ccb); + if (ret) { + DRM_ERROR("MSVDX:failed to allocate CCB.\n"); + *ccb = NULL; + return 1; + } + + ret = ttm_bo_kmap(*ccb, 0, (*ccb)->num_pages, &tmp_kmap); + if (ret) { + PSB_DEBUG_GENERAL("ttm_bo_kmap failed ret: %d\n", ret); + ttm_bo_unref(ccb); + *ccb = NULL; + return 1; + } +/* + memset(ttm_kmap_obj_virtual(&tmp_kmap, &is_iomem), 0, + RENDEC_A_SIZE); +*/ + memset(ttm_kmap_obj_virtual(&tmp_kmap, &is_iomem), 0, + size); + ttm_bo_kunmap(&tmp_kmap); + + *base_addr = (*ccb)->offset; + return 0; +} + +static ssize_t psb_msvdx_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 msvdx_private *msvdx_priv; + unsigned int pmstate; + unsigned long flags; + int ret = -EINVAL; + + if (drm_dev == NULL) + return 0; + + dev_priv = drm_dev->dev_private; + msvdx_priv = dev_priv->msvdx_private; + pmstate = msvdx_priv->pmstate; + + spin_lock_irqsave(&msvdx_priv->msvdx_lock, flags); + ret = snprintf(buf, 64, "%s\n", + (pmstate == PSB_PMSTATE_POWERUP) ? "powerup" + : ((pmstate == PSB_PMSTATE_POWERDOWN) ? "powerdown" + : "clockgated")); + spin_unlock_irqrestore(&msvdx_priv->msvdx_lock, flags); + + return ret; +} + +static DEVICE_ATTR(msvdx_pmstate, 0444, psb_msvdx_pmstate_show, NULL); + +int psb_msvdx_init(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + /* uint32_t clk_gate_ctrl = clk_enable_all; */ + uint32_t cmd; + int ret; + struct msvdx_private *msvdx_priv; +/* + uint32_t reg_value; + uint32_t reg_val; +*/ + if (!dev_priv->msvdx_private) { + msvdx_priv = kmalloc(sizeof(struct msvdx_private), GFP_KERNEL); + if (msvdx_priv == NULL) + goto err_exit; + + dev_priv->msvdx_private = msvdx_priv; + memset(msvdx_priv, 0, sizeof(struct msvdx_private)); + + /* 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 + */ + /* pci_set_drvdata(dev->pdev, 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 = dev_priv->msvdx_private; + if (!msvdx_priv->ccb0) { /* one for the first time */ + /* Initialize comand msvdx queueing */ + INIT_LIST_HEAD(&msvdx_priv->msvdx_queue); + INIT_LIST_HEAD(&msvdx_priv->deblock_queue); + mutex_init(&msvdx_priv->msvdx_mutex); + spin_lock_init(&msvdx_priv->msvdx_lock); + /*figure out the stepping */ + pci_read_config_byte(dev->pdev, PSB_REVID_OFFSET, &psb_rev_id); + } + + msvdx_priv->vec_local_mem_size = VEC_LOCAL_MEM_BYTE_SIZE; + if (!msvdx_priv->vec_local_mem_data) { + msvdx_priv->vec_local_mem_data = + kzalloc(msvdx_priv->vec_local_mem_size, GFP_KERNEL); + if (msvdx_priv->vec_local_mem_data == NULL) { + PSB_DEBUG_GENERAL("Vec local memory fail\n"); + goto err_exit; + } + } + + msvdx_priv->msvdx_busy = 0; + msvdx_priv->msvdx_hw_busy = 1; + + /* Enable Clocks */ + 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)); + reg_value = PSB_RMSVDX32(REGISTER(MSVDX_CORE, CR_MSVDX_CONTROL)); + PSB_WMSVDX32(0, REGISTER(MSVDX_CORE, CR_MSVDX_CONTROL)); + PSB_WMSVDX32(MSVDX_CORE_CR_MSVDX_CONTROL_CR_MSVDX_SOFT_RESET_MASK, REGISTER(MSVDX_CORE, CR_MSVDX_CONTROL)); + + reg_val = 0; + REGIO_WRITE_FIELD(reg_val, MSVDX_CORE_CR_FE_MSVDX_WDT_CONTROL, FE_WDT_CNT_CTRL, 0x3); + REGIO_WRITE_FIELD(reg_val, MSVDX_CORE_CR_FE_MSVDX_WDT_CONTROL, FE_WDT_ENABLE, 0); + REGIO_WRITE_FIELD(reg_val, MSVDX_CORE_CR_FE_MSVDX_WDT_CONTROL, FE_WDT_ACTION0, 1); + REGIO_WRITE_FIELD(reg_val, MSVDX_CORE_CR_FE_MSVDX_WDT_CONTROL, FE_WDT_CLEAR_SELECT, 1); + REGIO_WRITE_FIELD(reg_val, MSVDX_CORE_CR_FE_MSVDX_WDT_CONTROL, FE_WDT_CLKDIV_SELECT, 7); + PSB_WMSVDX32(820, REGISTER( MSVDX_CORE, CR_FE_MSVDX_WDT_COMPAREMATCH )); + PSB_WMSVDX32(reg_val, REGISTER( MSVDX_CORE, CR_FE_MSVDX_WDT_CONTROL )); + + reg_val = 0; + REGIO_WRITE_FIELD(reg_val, MSVDX_CORE_CR_BE_MSVDX_WDT_CONTROL, BE_WDT_CNT_CTRL, 0x7); + REGIO_WRITE_FIELD(reg_val, MSVDX_CORE_CR_BE_MSVDX_WDT_CONTROL, BE_WDT_ENABLE, 0); + REGIO_WRITE_FIELD(reg_val, MSVDX_CORE_CR_BE_MSVDX_WDT_CONTROL, BE_WDT_ACTION0, 1); + REGIO_WRITE_FIELD(reg_val, MSVDX_CORE_CR_BE_MSVDX_WDT_CONTROL, BE_WDT_CLEAR_SELECT, 0xd); + REGIO_WRITE_FIELD(reg_val, MSVDX_CORE_CR_BE_MSVDX_WDT_CONTROL, BE_WDT_CLKDIV_SELECT, 7); + PSB_WMSVDX32(8200, REGISTER(MSVDX_CORE, CR_BE_MSVDX_WDT_COMPAREMATCH)); + PSB_WMSVDX32(reg_val, REGISTER(MSVDX_CORE, CR_BE_MSVDX_WDT_CONTROL)); +*/ + /* Enable MMU by removing all bypass bits */ + PSB_WMSVDX32(0, MSVDX_MMU_CONTROL0); + + /* move firmware loading to the place receiving first command buffer */ + + PSB_DEBUG_GENERAL("MSVDX: Setting up RENDEC,allocate CCB 0/1\n"); + /* Allocate device virtual memory as required by rendec.... */ + if (!msvdx_priv->ccb0) { + ret = psb_allocate_ccb(dev, &msvdx_priv->ccb0, + &msvdx_priv->base_addr0, + RENDEC_A_SIZE); + if (ret) { + PSB_DEBUG_GENERAL("Allocate Rendec A fail\n"); + goto err_exit; + } + } + + if (!msvdx_priv->ccb1) { + ret = psb_allocate_ccb(dev, &msvdx_priv->ccb1, + &msvdx_priv->base_addr1, + RENDEC_B_SIZE); + if (ret) + goto err_exit; + } + + if(!msvdx_priv->fw) { + uint32_t core_rev; + uint32_t fw_bo_size; + + core_rev = PSB_RMSVDX32(MSVDX_CORE_REV); + + if( (core_rev&0xffffff ) < 0x020000 ) + msvdx_priv->mtx_mem_size = 16*1024; + else + msvdx_priv->mtx_mem_size = 40*1024; + + if(IS_CDV(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); + + ret = ttm_buffer_object_create(&dev_priv->bdev, fw_bo_size, /* DMA may run over a page */ + ttm_bo_type_kernel, + DRM_PSB_FLAG_MEM_MMU | TTM_PL_FLAG_NO_EVICT, + 0, 0, 0, NULL, &msvdx_priv->fw); + + if (ret) { + PSB_DEBUG_GENERAL("Allocate firmware BO fail\n"); + goto err_exit; + } + } + + PSB_DEBUG_GENERAL("MSVDX: RENDEC A: %08x RENDEC B: %08x\n", + msvdx_priv->base_addr0, msvdx_priv->base_addr1); + + PSB_WMSVDX32(msvdx_priv->base_addr0, MSVDX_RENDEC_BASE_ADDR0); + PSB_WMSVDX32(msvdx_priv->base_addr1, MSVDX_RENDEC_BASE_ADDR1); + + cmd = 0; + REGIO_WRITE_FIELD(cmd, MSVDX_RENDEC_BUFFER_SIZE, + RENDEC_BUFFER_SIZE0, RENDEC_A_SIZE / 4096); + REGIO_WRITE_FIELD(cmd, MSVDX_RENDEC_BUFFER_SIZE, + RENDEC_BUFFER_SIZE1, RENDEC_B_SIZE / 4096); + PSB_WMSVDX32(cmd, MSVDX_RENDEC_BUFFER_SIZE); + + if(!msvdx_priv->fw) { + uint32_t core_rev; + + core_rev = PSB_RMSVDX32(MSVDX_CORE_REV); + + if( (core_rev&0xffffff ) < 0x020000 ) + msvdx_priv->mtx_mem_size = 16*1024; + else + msvdx_priv->mtx_mem_size = 40*1024; + + PSB_DEBUG_INIT("MSVDX: MTX mem size is 0x%08xbytes allocate firmware BO size 0x%08x\n", msvdx_priv->mtx_mem_size, + msvdx_priv->mtx_mem_size + 4096); + + ret = ttm_buffer_object_create(&dev_priv->bdev, msvdx_priv->mtx_mem_size + 4096, /* DMA may run over a page */ + ttm_bo_type_kernel, + DRM_PSB_FLAG_MEM_MMU | TTM_PL_FLAG_NO_EVICT, + 0, 0, 0, NULL, &msvdx_priv->fw); + + if (ret) { + PSB_DEBUG_GENERAL("Allocate firmware BO fail\n"); + goto err_exit; + } + } + + cmd = 0; + REGIO_WRITE_FIELD(cmd, MSVDX_RENDEC_CONTROL1, + RENDEC_DECODE_START_SIZE, 0); + REGIO_WRITE_FIELD(cmd, MSVDX_RENDEC_CONTROL1, + RENDEC_BURST_SIZE_W, 1); + REGIO_WRITE_FIELD(cmd, MSVDX_RENDEC_CONTROL1, + RENDEC_BURST_SIZE_R, 1); + REGIO_WRITE_FIELD(cmd, MSVDX_RENDEC_CONTROL1, + RENDEC_EXTERNAL_MEMORY, 1); + PSB_WMSVDX32(cmd, MSVDX_RENDEC_CONTROL1); + + cmd = 0x00101010; + PSB_WMSVDX32(cmd, MSVDX_RENDEC_CONTEXT0); + PSB_WMSVDX32(cmd, MSVDX_RENDEC_CONTEXT1); + PSB_WMSVDX32(cmd, MSVDX_RENDEC_CONTEXT2); + PSB_WMSVDX32(cmd, MSVDX_RENDEC_CONTEXT3); + PSB_WMSVDX32(cmd, MSVDX_RENDEC_CONTEXT4); + PSB_WMSVDX32(cmd, MSVDX_RENDEC_CONTEXT5); + + cmd = 0; + REGIO_WRITE_FIELD(cmd, MSVDX_RENDEC_CONTROL0, RENDEC_INITIALISE, + 1); + PSB_WMSVDX32(cmd, MSVDX_RENDEC_CONTROL0); + + /* PSB_WMSVDX32(clk_enable_minimal, MSVDX_MAN_CLK_ENABLE); */ + PSB_DEBUG_INIT("MSVDX:defer firmware loading to the" + " place when receiving user space commands\n"); + + msvdx_priv->msvdx_fw_loaded = 0; /* need to load firware */ + + PSB_WMSVDX32(820, MSVDX_CORE_CR_FE_MSVDX_WDT_COMPAREMATCH); + PSB_WMSVDX32(8200, MSVDX_CORE_CR_BE_MSVDX_WDT_COMPAREMATCH); + + PSB_WMSVDX32(820, MSVDX_CORE_CR_FE_MSVDX_WDT_COMPAREMATCH); + PSB_WMSVDX32(8200, MSVDX_CORE_CR_BE_MSVDX_WDT_COMPAREMATCH); + + psb_msvdx_clearirq(dev); + psb_msvdx_enableirq(dev); + + if (IS_MSVDX(dev)) { + PSB_DEBUG_INIT("MSDVX:old clock gating disable = 0x%08x\n", + PSB_RVDC32(PSB_MSVDX_CLOCKGATING)); + } + + { + cmd = 0; + cmd = PSB_RMSVDX32(MSVDX_VEC_SHIFTREG_CONTROL); /* VEC_SHIFTREG_CONTROL */ + REGIO_WRITE_FIELD(cmd, + VEC_SHIFTREG_CONTROL, + SR_MASTER_SELECT, + 1); /* Host */ + PSB_WMSVDX32(cmd, MSVDX_VEC_SHIFTREG_CONTROL); + } + +#if 0 + ret = psb_setup_fw(dev); + if (ret) + goto err_exit; + /* Send Initialisation message to firmware */ + if (0) { + uint32_t msg_init[FW_VA_INIT_SIZE >> 2]; + MEMIO_WRITE_FIELD(msg_init, FWRK_GENMSG_SIZE, + FW_VA_INIT_SIZE); + MEMIO_WRITE_FIELD(msg_init, FWRK_GENMSG_ID, VA_MSGID_INIT); + + /* Need to set this for all but A0 */ + MEMIO_WRITE_FIELD(msg_init, FW_VA_INIT_GLOBAL_PTD, + psb_get_default_pd_addr(dev_priv->mmu)); + + ret = psb_mtx_send(dev_priv, msg_init); + if (ret) + goto err_exit; + + psb_poll_mtx_irq(dev_priv); + } +#endif + + return 0; + +err_exit: + DRM_ERROR("MSVDX: initialization failed\n"); + if (msvdx_priv && msvdx_priv->ccb0) + psb_free_ccb(&msvdx_priv->ccb0); + if (msvdx_priv && msvdx_priv->ccb1) + psb_free_ccb(&msvdx_priv->ccb1); + if (dev_priv->msvdx_private) { + kfree(dev_priv->msvdx_private); + dev_priv->msvdx_private = NULL; + } + return 1; +} + +int psb_msvdx_uninit(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct msvdx_private *msvdx_priv = dev_priv->msvdx_private; + + /* Reset MSVDX chip */ + psb_msvdx_reset(dev_priv); + + /* PSB_WMSVDX32 (clk_enable_minimal, MSVDX_MAN_CLK_ENABLE); */ + PSB_DEBUG_INIT("MSVDX:set the msvdx clock to 0\n"); + PSB_WMSVDX32(0, MSVDX_MAN_CLK_ENABLE); + + if (NULL == msvdx_priv) + { + DRM_ERROR("MSVDX: psb_msvdx_uninit: msvdx_priv is NULL!\n"); + return -1; + } + + if (msvdx_priv->ccb0) + psb_free_ccb(&msvdx_priv->ccb0); + if (msvdx_priv->ccb1) + psb_free_ccb(&msvdx_priv->ccb1); + if (msvdx_priv->msvdx_fw) + kfree(msvdx_priv->msvdx_fw + ); + if (msvdx_priv->vec_local_mem_data) + kfree(msvdx_priv->vec_local_mem_data); + + if (msvdx_priv) { + /* pci_set_drvdata(dev->pdev, NULL); */ + device_remove_file(&dev->pdev->dev, &dev_attr_msvdx_pmstate); + sysfs_put(msvdx_priv->sysfs_pmstate); + msvdx_priv->sysfs_pmstate = NULL; + + kfree(msvdx_priv); + dev_priv->msvdx_private = NULL; + } + + return 0; +} |