bool CHNLSM_ISR(struct WMD_DEV_CONTEXT *pDevContext, bool *pfSchedDPC, u16 *pwIntrVal) { struct CFG_HOSTRES resources; u32 numMbxMsg; u32 mbxValue; DBG_Trace(DBG_ENTER, "CHNLSM_ISR(0x%x)\n", pDevContext); CFG_GetHostResources((struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources); HW_MBOX_NumMsgGet(resources.dwMboxBase, MBOX_DSP2ARM, &numMbxMsg); if (numMbxMsg > 0) { HW_MBOX_MsgRead(resources.dwMboxBase, MBOX_DSP2ARM, &mbxValue); HW_MBOX_EventAck(resources.dwMboxBase, MBOX_DSP2ARM, HW_MBOX_U0_ARM, HW_MBOX_INT_NEW_MSG); DBG_Trace(DBG_LEVEL3, "Read %x from Mailbox\n", mbxValue); *pwIntrVal = (u16) mbxValue; } /* Set *pfSchedDPC to true; */ *pfSchedDPC = true; return true; }
DSP_STATUS CHNLSM_DisableInterrupt(struct WMD_DEV_CONTEXT *pDevContext) { struct CFG_HOSTRES resources; DBG_Trace(DBG_ENTER, "CHNLSM_DisableInterrupt(0x%x)\n", pDevContext); CFG_GetHostResources((struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources); HW_MBOX_EventDisable(resources.dwMboxBase, MBOX_DSP2ARM, MBOX_ARM, HW_MBOX_INT_NEW_MSG); return DSP_SOK; }
DSP_STATUS CHNLSM_EnableInterrupt(struct WMD_DEV_CONTEXT *pDevContext) { DSP_STATUS status = DSP_SOK; u32 numMbxMsg; u32 mbxValue; struct CFG_HOSTRES resources; u32 devType; struct IO_MGR *hIOMgr; DBG_Trace(DBG_ENTER, "CHNLSM_EnableInterrupt(0x%x)\n", pDevContext); /* Read the messages in the mailbox until the message queue is empty */ CFG_GetHostResources((struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources); DEV_GetDevType(pDevContext->hDevObject, &devType); status = DEV_GetIOMgr(pDevContext->hDevObject, &hIOMgr); if (devType == DSP_UNIT) { HW_MBOX_NumMsgGet(resources.dwMboxBase, MBOX_DSP2ARM, &numMbxMsg); while (numMbxMsg != 0) { HW_MBOX_MsgRead(resources.dwMboxBase, MBOX_DSP2ARM, &mbxValue); numMbxMsg--; } /* clear the DSP mailbox as well...*/ HW_MBOX_NumMsgGet(resources.dwMboxBase, MBOX_ARM2DSP, &numMbxMsg); while (numMbxMsg != 0) { HW_MBOX_MsgRead(resources.dwMboxBase, MBOX_ARM2DSP, &mbxValue); numMbxMsg--; udelay(10); HW_MBOX_EventAck(resources.dwMboxBase, MBOX_ARM2DSP, HW_MBOX_U1_DSP1, HW_MBOX_INT_NEW_MSG); } /* Enable the new message events on this IRQ line */ HW_MBOX_EventEnable(resources.dwMboxBase, MBOX_DSP2ARM, MBOX_ARM, HW_MBOX_INT_NEW_MSG); } return status; }
/* * ======== WriteDspData ======== * purpose: * Copies buffers to the DSP internal/external memory. */ DSP_STATUS WriteDspData(struct WMD_DEV_CONTEXT *hDevContext, IN u8 *pbHostBuf, u32 dwDSPAddr, u32 ulNumBytes, u32 ulMemType) { u32 offset; u32 dwBaseAddr = hDevContext->dwDspBaseAddr; struct CFG_HOSTRES resources; DSP_STATUS status; u32 base1, base2, base3; base1 = OMAP_DSP_MEM1_SIZE; base2 = OMAP_DSP_MEM2_BASE - OMAP_DSP_MEM1_BASE; base3 = OMAP_DSP_MEM3_BASE - OMAP_DSP_MEM1_BASE; status = CFG_GetHostResources( (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources); if (DSP_FAILED(status)) return status; offset = dwDSPAddr - hDevContext->dwDSPStartAdd; if (offset < base1) { dwBaseAddr = MEM_LinearAddress(resources.dwMemBase[2], resources.dwMemLength[2]); } else if (offset > base1 && offset < base2+OMAP_DSP_MEM2_SIZE) { dwBaseAddr = MEM_LinearAddress(resources.dwMemBase[3], resources.dwMemLength[3]); offset = offset - base2; } else if (offset >= base2+OMAP_DSP_MEM2_SIZE && offset < base3 + OMAP_DSP_MEM3_SIZE) { dwBaseAddr = MEM_LinearAddress(resources.dwMemBase[4], resources.dwMemLength[4]); offset = offset - base3; } else{ return DSP_EFAIL; } if (ulNumBytes) memcpy((u8 *) (dwBaseAddr+offset), pbHostBuf, ulNumBytes); else *((u32 *) pbHostBuf) = dwBaseAddr+offset; return status; }
/* * ======== WMD_DEH_Create ======== * Creates DEH manager object. */ DSP_STATUS WMD_DEH_Create(OUT struct DEH_MGR **phDehMgr, struct DEV_OBJECT *hDevObject) { DSP_STATUS status = DSP_SOK; struct DEH_MGR *pDehMgr = NULL; struct CFG_HOSTRES cfgHostRes; struct CFG_DEVNODE *hDevNode; struct WMD_DEV_CONTEXT *hWmdContext = NULL; /* Message manager will be created when a file is loaded, since * size of message buffer in shared memory is configurable in * the base image. */ /* Get WMD context info. */ DEV_GetWMDContext(hDevObject, &hWmdContext); DBC_Assert(hWmdContext); dummyVaAddr = 0; /* Allocate IO manager object: */ MEM_AllocObject(pDehMgr, struct DEH_MGR, SIGNATURE); if (pDehMgr == NULL) { status = DSP_EMEMORY; } else { /* Create an NTFY object to manage notifications */ status = NTFY_Create(&pDehMgr->hNtfy); /* Create a MMUfault DPC */ tasklet_init(&pDehMgr->dpc_tasklet, MMU_FaultDpc, (u32)pDehMgr); if (DSP_SUCCEEDED(status)) status = DEV_GetDevNode(hDevObject, &hDevNode); if (DSP_SUCCEEDED(status)) status = CFG_GetHostResources(hDevNode, &cfgHostRes); if (DSP_SUCCEEDED(status)) { /* Fill in context structure */ pDehMgr->hWmdContext = hWmdContext; pDehMgr->errInfo.dwErrMask = 0L; pDehMgr->errInfo.dwVal1 = 0L; pDehMgr->errInfo.dwVal2 = 0L; pDehMgr->errInfo.dwVal3 = 0L; /* Install ISR function for DSP MMU fault */ if ((request_irq(INT_DSP_MMU_IRQ, MMU_FaultIsr, 0, "DspBridge\tiommu fault", (void *)pDehMgr)) == 0) status = DSP_SOK; else status = DSP_EFAIL; } } if (DSP_FAILED(status)) { /* If create failed, cleanup */ WMD_DEH_Destroy((struct DEH_MGR *)pDehMgr); *phDehMgr = NULL; } else { timer = omap_dm_timer_request_specific( GPTIMER_FOR_DSP_MMU_FAULT); if (timer) omap_dm_timer_disable(timer); else { pr_err("%s:GPTimer not available\n", __func__); return -ENODEV; } *phDehMgr = (struct DEH_MGR *)pDehMgr; } return status; }
DSP_STATUS CHNLSM_InterruptDSP2(struct WMD_DEV_CONTEXT *pDevContext, u16 wMbVal) { struct CFG_HOSTRES resources; DSP_STATUS status = DSP_SOK; unsigned long timeout; u32 temp; status = CFG_GetHostResources((struct CFG_DEVNODE *) DRV_GetFirstDevExtension(), &resources); if (DSP_FAILED(status)) return DSP_EFAIL; if (pDevContext->dwBrdState == BRD_DSP_HIBERNATION || pDevContext->dwBrdState == BRD_HIBERNATION) { #ifdef CONFIG_BRIDGE_DVFS struct dspbridge_platform_data *pdata = omap_dspbridge_dev->dev.platform_data; /* * When Smartreflex is ON, DSP requires at least OPP level 3 * to operate reliably. So boost lower OPP levels to OPP3. */ if (pdata->dsp_set_min_opp) (*pdata->dsp_set_min_opp)(min_active_opp); #endif /* Restart the peripheral clocks */ DSP_PeripheralClocks_Enable(pDevContext, NULL); /* * 2:0 AUTO_IVA2_DPLL - Enabling IVA2 DPLL auto control * in CM_AUTOIDLE_PLL_IVA2 register */ *(REG_UWORD32 *)(resources.dwCmBase + 0x34) = 0x1; /* * 7:4 IVA2_DPLL_FREQSEL - IVA2 internal frq set to * 0.75 MHz - 1.0 MHz * 2:0 EN_IVA2_DPLL - Enable IVA2 DPLL in lock mode */ temp = *(REG_UWORD32 *)(resources.dwCmBase + 0x4); temp = (temp & 0xFFFFFF08) | 0x37; *(REG_UWORD32 *)(resources.dwCmBase + 0x4) = temp; /* * This delay is needed to avoid mailbox timed out * issue experienced while SmartReflex is ON. * TODO: Instead of 1 ms calculate proper value. */ mdelay(1); /* Restore mailbox settings */ HW_MBOX_restoreSettings(resources.dwMboxBase); /* Access MMU SYS CONFIG register to generate a short wakeup */ temp = *(REG_UWORD32 *)(resources.dwDmmuBase + 0x10); pDevContext->dwBrdState = BRD_RUNNING; } timeout = jiffies + msecs_to_jiffies(1); while (fifo_full((void __iomem *) resources.dwMboxBase, 0)) { if (time_after(jiffies, timeout)) { pr_err("dspbridge: timed out waiting for mailbox\n"); return WMD_E_TIMEOUT; } } DBG_Trace(DBG_LEVEL3, "writing %x to Mailbox\n", wMbVal); HW_MBOX_MsgWrite(resources.dwMboxBase, MBOX_ARM2DSP, wMbVal); return DSP_SOK; }
DSP_STATUS CHNLSM_InterruptDSP2(struct WMD_DEV_CONTEXT *pDevContext, u16 wMbVal) { #ifndef CONFIG_DISABLE_BRIDGE_PM #ifndef CONFIG_DISABLE_BRIDGE_DVFS u32 opplevel; #endif #endif struct CFG_HOSTRES resources; unsigned long timeout; u32 temp; DSP_STATUS status = DSP_SOK; /* We are waiting indefinitely here. This needs to be fixed in the * second phase */ CFG_GetHostResources((struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources); if (pDevContext->dwBrdState == BRD_DSP_HIBERNATION || pDevContext->dwBrdState == BRD_HIBERNATION) { #ifndef CONFIG_DISABLE_BRIDGE_PM #ifndef CONFIG_DISABLE_BRIDGE_DVFS #ifndef CONFIG_OMAP3_PM opplevel = omap_pm_dsp_get_opp(); /* If OPP is at minimum level, increase it before waking up * the DSP */ if (opplevel == 1) { omap_pm_dsp_set_min_opp(opplevel+1); DBG_Trace(DBG_LEVEL7, "CHNLSM_InterruptDSP:Setting " "the vdd1 constraint level to %d before " "waking DSP \n", (opplevel + 1)); } #else opplevel = constraint_get_level(dsp_constraint_handle); /* If OPP is at minimum level, increase it before waking up * the DSP */ if (opplevel == 1) { if (constraint_set(dsp_constraint_handle, (opplevel+1)) != 0) { DBG_Trace(DBG_LEVEL7, "CHNLSM_InterruptDSP: " "Constraint set failed\n"); return DSP_EFAIL; } DBG_Trace(DBG_LEVEL7, "CHNLSM_InterruptDSP:Setting " "the vdd1 constraint level to %d before " "waking DSP \n", (opplevel + 1)); } #endif #endif #endif /* Restart the IVA clock that was disabled while * the DSP initiated Hibernation. */ if ((pDevContext->dwBrdState == BRD_DSP_HIBERNATION) || (pDevContext->dwBrdState == BRD_HIBERNATION)) { status = CLK_Enable(SERVICESCLK_iva2_ck); if (DSP_FAILED(status)) return status; } /* Read MMU register to invoke short wakeup of DSP */ temp = (u32) *((REG_UWORD32 *) ((u32) (resources.dwDmmuBase) + 0x10)); /* Restore mailbox settings */ HW_MBOX_restoreSettings(resources.dwMboxBase); DBG_Trace(DBG_LEVEL6, "MailBoxSettings: SYSCONFIG = 0x%x\n", mboxsetting.sysconfig); DBG_Trace(DBG_LEVEL6, "MailBoxSettings: IRQENABLE0 = 0x%x\n", mboxsetting.irqEnable0); DBG_Trace(DBG_LEVEL6, "MailBoxSettings: IRQENABLE1 = 0x%x\n", mboxsetting.irqEnable1); /* Restart the peripheral clocks that were disabled only * in DSP initiated Hibernation case.*/ if (pDevContext->dwBrdState == BRD_DSP_HIBERNATION) DSP_PeripheralClocks_Enable(pDevContext, NULL); pDevContext->dwBrdState = BRD_RUNNING; } timeout = jiffies + msecs_to_jiffies(35); while (HW_MBOX_IsFull(resources.dwMboxBase, MBOX_ARM2DSP)) { if (time_after(jiffies, timeout)) { printk(KERN_ERR "dspbridge: " "timed out waiting for mailbox\n"); return WMD_E_TIMEOUT; } } DBG_Trace(DBG_LEVEL3, "writing %x to Mailbox\n", wMbVal); HW_MBOX_MsgWrite(resources.dwMboxBase, MBOX_ARM2DSP, wMbVal); return DSP_SOK; }
/* * ======== WriteExtDspData ======== * purpose: * Copies buffers to the external memory. * */ DSP_STATUS WriteExtDspData(struct WMD_DEV_CONTEXT *pDevContext, IN u8 *pbHostBuf, u32 dwDSPAddr, u32 ulNumBytes, u32 ulMemType, bool bDynamicLoad) { u32 dwBaseAddr = pDevContext->dwDspExtBaseAddr; u32 dwOffset = 0; u8 bTempByte1, bTempByte2; u8 remainByte[4]; s32 i; DSP_STATUS retVal = DSP_SOK; u32 dwExtProgVirtMem; u32 ulTLBBaseVirt = 0; u32 ulShmOffsetVirt = 0; struct CFG_HOSTRES hostRes; bool bTraceLoad = false; bTempByte1 = 0x0; bTempByte2 = 0x0; if (bSymbolsReloaded) { /* Check if it is a load to Trace section */ retVal = DEV_GetSymbol(pDevContext->hDevObject, DSP_TRACESEC_BEG, &ulTraceSecBeg); if (DSP_SUCCEEDED(retVal)) retVal = DEV_GetSymbol(pDevContext->hDevObject, DSP_TRACESEC_END, &ulTraceSecEnd); } if (DSP_SUCCEEDED(retVal)) { if ((dwDSPAddr <= ulTraceSecEnd) && (dwDSPAddr >= ulTraceSecBeg)) bTraceLoad = true; } /* If dynamic, force remap/unmap */ if ((bDynamicLoad || bTraceLoad) && dwBaseAddr) { dwBaseAddr = 0; MEM_UnmapLinearAddress((void *)pDevContext->dwDspExtBaseAddr); pDevContext->dwDspExtBaseAddr = 0x0; } if (!dwBaseAddr) { if (bSymbolsReloaded) /* Get SHM_BEG EXT_BEG and EXT_END. */ retVal = DEV_GetSymbol(pDevContext->hDevObject, SHMBASENAME, &ulShmBaseVirt); DBC_Assert(ulShmBaseVirt != 0); if (bDynamicLoad) { if (DSP_SUCCEEDED(retVal)) { if (bSymbolsReloaded) retVal = DEV_GetSymbol(pDevContext-> hDevObject, DYNEXTBASE, &ulExtBase); } DBC_Assert(ulExtBase != 0); if (DSP_SUCCEEDED(retVal)) { /* DR OMAPS00013235 : DLModules array may be * in EXTMEM. It is expected that DYNEXTMEM and * EXTMEM are contiguous, so checking for the * upper bound at EXTEND should be Ok. */ if (bSymbolsReloaded) retVal = DEV_GetSymbol(pDevContext-> hDevObject, EXTEND, &ulExtEnd); } } else { if (bSymbolsReloaded) { if (DSP_SUCCEEDED(retVal)) retVal = DEV_GetSymbol(pDevContext-> hDevObject, EXTBASE, &ulExtBase); DBC_Assert(ulExtBase != 0); if (DSP_SUCCEEDED(retVal)) retVal = DEV_GetSymbol(pDevContext-> hDevObject, EXTEND, &ulExtEnd); } } /* Trace buffer it right after the SHM SEG0, so set the * base address to SHMBASE */ if (bTraceLoad) ulExtBase = ulShmBaseVirt; DBC_Assert(ulExtEnd != 0); DBC_Assert(ulExtEnd > ulExtBase); if (ulExtEnd < ulExtBase) retVal = DSP_EFAIL; if (DSP_SUCCEEDED(retVal)) { ulTLBBaseVirt = pDevContext->aTLBEntry[0].ulDspVa * DSPWORDSIZE; DBC_Assert(ulTLBBaseVirt <= ulShmBaseVirt); if (bSymbolsReloaded) { if (DSP_SUCCEEDED(retVal)) { retVal = DEV_GetSymbol(pDevContext-> hDevObject, DSP_TRACESEC_END, &ulShm0End); } if (DSP_SUCCEEDED(retVal)) { retVal = DEV_GetSymbol(pDevContext-> hDevObject, DYNEXTBASE, &ulDynExtBase); } } ulShmOffsetVirt = ulShmBaseVirt - ulTLBBaseVirt; if (bTraceLoad) { dwExtProgVirtMem = pDevContext->aTLBEntry[0]. ulGppVa; } else { CFG_GetHostResources( (struct CFG_DEVNODE *) DRV_GetFirstDevExtension(), &hostRes); dwExtProgVirtMem = hostRes.dwMemBase[1]; dwExtProgVirtMem += (ulExtBase - ulDynExtBase); } pDevContext->dwDspExtBaseAddr = (u32)MEM_LinearAddress((void *)dwExtProgVirtMem, ulExtEnd - ulExtBase); dwBaseAddr += pDevContext->dwDspExtBaseAddr; /* This dwDspExtBaseAddr will get cleared only when * the board is stopped. */ if (!pDevContext->dwDspExtBaseAddr) retVal = DSP_EFAIL; } } if (!dwBaseAddr || !ulExtBase || !ulExtEnd) retVal = DSP_EFAIL; if (DSP_SUCCEEDED(retVal)) { for (i = 0; i < 4; i++) remainByte[i] = 0x0; dwOffset = dwDSPAddr - ulExtBase; /* Also make sure the dwDSPAddr is < ulExtEnd */ if (dwDSPAddr > ulExtEnd || dwOffset > dwDSPAddr) retVal = DSP_EFAIL; } if (DSP_SUCCEEDED(retVal)) { if (ulNumBytes) memcpy((u8 *) dwBaseAddr + dwOffset, pbHostBuf, ulNumBytes); else *((u32 *) pbHostBuf) = dwBaseAddr+dwOffset; } /* Unmap here to force remap for other Ext loads */ if ((bDynamicLoad || bTraceLoad) && pDevContext->dwDspExtBaseAddr) { MEM_UnmapLinearAddress((void *) pDevContext->dwDspExtBaseAddr); pDevContext->dwDspExtBaseAddr = 0x0; } bSymbolsReloaded = false; return retVal; }
DSP_STATUS CHNLSM_InterruptDSP2(struct WMD_DEV_CONTEXT *pDevContext, u16 wMbVal) { #ifdef CONFIG_BRIDGE_DVFS struct dspbridge_platform_data *pdata = omap_dspbridge_dev->dev.platform_data; u32 opplevel = 0; #endif struct CFG_HOSTRES resources; DSP_STATUS status = DSP_SOK; unsigned long timeout; u32 temp; status = CFG_GetHostResources((struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources); if (DSP_FAILED(status)) return DSP_EFAIL; #ifdef CONFIG_BRIDGE_DVFS if (pDevContext->dwBrdState == BRD_DSP_HIBERNATION || pDevContext->dwBrdState == BRD_HIBERNATION) { if (pdata->dsp_get_opp) opplevel = (*pdata->dsp_get_opp)(); if (opplevel == 1) { if (pdata->dsp_set_min_opp) (*pdata->dsp_set_min_opp)(opplevel+1); } } #endif if (pDevContext->dwBrdState == BRD_DSP_HIBERNATION || pDevContext->dwBrdState == BRD_HIBERNATION) { /* Restart the IVA clock that was disabled while * the DSP initiated Hibernation. */ status = CLK_Enable(SERVICESCLK_iva2_ck); if (DSP_FAILED(status)) return status; /* Restore mailbox settings */ /* Restart the peripheral clocks that were disabled only * in DSP initiated Hibernation case.*/ if (pDevContext->dwBrdState == BRD_DSP_HIBERNATION) { DSP_PeripheralClocks_Enable(pDevContext, NULL); /* Enabling Dpll in lock mode*/ temp = (u32) *((REG_UWORD32 *) ((u32) (resources.dwCmBase) + 0x34)); temp = (temp & 0xFFFFFFFE) | 0x1; *((REG_UWORD32 *) ((u32) (resources.dwCmBase) + 0x34)) = (u32) temp; temp = (u32) *((REG_UWORD32 *) ((u32) (resources.dwCmBase) + 0x4)); temp = (temp & 0xFFFFFC8) | 0x37; *((REG_UWORD32 *) ((u32) (resources.dwCmBase) + 0x4)) = (u32) temp; } HW_MBOX_restoreSettings(resources.dwMboxBase); /* Access MMU SYS CONFIG register to generate a short wakeup */ temp = (u32) *((REG_UWORD32 *) ((u32) (resources.dwDmmuBase) + 0x10)); pDevContext->dwBrdState = BRD_RUNNING; } timeout = jiffies + msecs_to_jiffies(1); while (fifo_full((void __iomem *) resources.dwMboxBase, 0)) { if (time_after(jiffies, timeout)) { printk(KERN_ERR "dspbridge: timed out waiting for mailbox\n"); return WMD_E_TIMEOUT; } } DBG_Trace(DBG_LEVEL3, "writing %x to Mailbox\n", wMbVal); HW_MBOX_MsgWrite(resources.dwMboxBase, MBOX_ARM2DSP, wMbVal); return DSP_SOK; }