int omap_rproc_activate(struct omap_device *od) { int i, ret = 0; struct rproc *rproc = platform_get_drvdata(&od->pdev); struct device *dev = rproc->dev; struct omap_rproc_pdata *pdata = dev->platform_data; struct omap_rproc_timers_info *timers = pdata->timers; struct omap_rproc_priv *rpp = rproc->priv; #ifdef CONFIG_REMOTE_PROC_AUTOSUSPEND struct iommu *iommu; if (!rpp->iommu) { iommu = iommu_get(pdata->iommu_name); if (IS_ERR(iommu)) { dev_err(dev, "iommu_get error: %ld\n", PTR_ERR(iommu)); return PTR_ERR(iommu); } rpp->iommu = iommu; } if (!rpp->mbox) rpp->mbox = omap_mbox_get(pdata->sus_mbox_name, NULL); #endif /** * explicitly configure a boot address from which remoteproc * starts executing code when taken out of reset. */ _load_boot_addr(rproc, rpp->bootaddr); /** * Domain is in HW SUP thus in hw_auto but * since remoteproc will be enabled clkdm * needs to be in sw_sup (Do not let it idle). */ if (pdata->clkdm) clkdm_wakeup(pdata->clkdm); for (i = 0; i < pdata->timers_cnt; i++) omap_dm_timer_start(timers[i].odt); for (i = 0; i < od->hwmods_cnt; i++) { ret = omap_hwmod_enable(od->hwmods[i]); if (ret) { for (i = 0; i < pdata->timers_cnt; i++) omap_dm_timer_stop(timers[i].odt); break; } } /** * Domain is in force_wkup but since remoteproc * was enabled it is safe now to switch clkdm * to hw_auto (let it idle). */ if (pdata->clkdm) clkdm_allow_idle(pdata->clkdm); return ret; }
static int _init_pm_flags(struct rproc *rproc) { struct omap_rproc_pdata *pdata = rproc->dev->platform_data; struct omap_rproc_priv *rpp = rproc->priv; struct omap_mbox *mbox; if (!rpp->mbox) { mbox = omap_mbox_get(pdata->sus_mbox_name, NULL); if (IS_ERR(mbox)) return PTR_ERR(mbox); rpp->mbox = mbox; } if (!pdata->idle_addr) goto err_idle; rpp->idle = ioremap(pdata->idle_addr, sizeof(u32)); if (!rpp->idle) goto err_idle; if (!pdata->suspend_addr) goto err_suspend; rpp->suspend = ioremap(pdata->suspend_addr, sizeof(u32)); if (!rpp->suspend) goto err_suspend; rpp->idle_mask = pdata->idle_mask; rpp->suspend_mask = pdata->suspend_mask; return 0; err_suspend: iounmap(rpp->idle); rpp->idle = NULL; err_idle: omap_mbox_put(rpp->mbox, NULL); rpp->mbox = NULL; return -EIO; }
/* Initiliaze WKUP_M3, load the binary blob and let it run */ static int wkup_m3_init(void) { struct clk *m3_clk; struct omap_hwmod *wkup_m3_oh; const struct firmware *firmware; int ret = 0; wkup_m3_oh = omap_hwmod_lookup("wkup_m3"); if (!wkup_m3_oh) { pr_err("%s: could not find omap_hwmod\n", __func__); ret = -ENODEV; goto exit; } ipc_regs = ioremap(A8_M3_IPC_REGS, 0x4*8); if (!ipc_regs) { pr_err("Could not ioremap the IPC area\b"); ret = -ENOMEM; goto exit; } m3_eoi = ioremap(M3_TXEV_EOI, 0x4); if (!m3_eoi) { pr_err("Could not ioremap the EOI register\n"); ret = -ENOMEM; goto err1; } /* Reserve the MBOX for sending messages to M3 */ m3_mbox = omap_mbox_get("wkup_m3", &wkup_m3_mbox_notifier); if (IS_ERR(m3_mbox)) { pr_err("Could not reserve mailbox for A8->M3 IPC\n"); ret = -ENODEV; goto err2; } /* Enable access to the M3 code and data area from A8 */ m3_clk = clk_get(NULL, "wkup_m3_fck"); if (IS_ERR(m3_clk)) { pr_err("%s failed to enable WKUP_M3 clock\n", __func__); goto err3; } if (clk_enable(m3_clk)) { pr_err("%s WKUP_M3: clock enable Failed\n", __func__); goto err4; } m3_code = ioremap(M3_UMEM, SZ_16K); if (!m3_code) { pr_err("%s Could not ioremap M3 code space\n", __func__); ret = -ENOMEM; goto err5; } pr_info("Trying to load am335x-pm-firmware.bin (60 secs timeout)\n"); ret = request_firmware(&firmware, "am335x-pm-firmware.bin", mpu_dev); if (ret < 0) { dev_err(mpu_dev, "request_firmware failed\n"); goto err6; } else { memcpy(m3_code, firmware->data, firmware->size); pr_info("Copied the M3 firmware to UMEM\n"); } ret = request_irq(AM33XX_IRQ_M3_M3SP_TXEV, wkup_m3_txev_handler, IRQF_DISABLED, "wkup_m3_txev", NULL); if (ret) { pr_err("%s request_irq failed for 0x%x\n", __func__, AM33XX_IRQ_M3_M3SP_TXEV); goto err6; } m3_state = M3_STATE_RESET; ret = omap_hwmod_deassert_hardreset(wkup_m3_oh, "wkup_m3"); if (ret) { pr_err("Could not deassert the reset for WKUP_M3\n"); goto err6; } else { return 0; } err6: release_firmware(firmware); iounmap(m3_code); err5: clk_disable(m3_clk); err4: clk_put(m3_clk); err3: omap_mbox_put(m3_mbox, &wkup_m3_mbox_notifier); err2: iounmap(m3_eoi); err1: iounmap(ipc_regs); exit: return ret; }
/* * ======== bridge_brd_start ======== * purpose: * Initializes DSP MMU and Starts DSP. * * Preconditions: * a) DSP domain is 'ACTIVE'. * b) DSP_RST1 is asserted. * b) DSP_RST2 is released. */ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt, u32 dsp_addr) { int status = 0; struct bridge_dev_context *dev_context = dev_ctxt; struct iommu *mmu = NULL; struct shm_segs *sm_sg; int l4_i = 0, tlb_i = 0; u32 sg0_da = 0, sg1_da = 0; struct bridge_ioctl_extproc *tlb = dev_context->atlb_entry; u32 dw_sync_addr = 0; u32 ul_shm_base; /* Gpp Phys SM base addr(byte) */ u32 ul_shm_base_virt; /* Dsp Virt SM base addr */ u32 ul_tlb_base_virt; /* Base of MMU TLB entry */ /* Offset of shm_base_virt from tlb_base_virt */ u32 ul_shm_offset_virt; struct cfg_hostres *resources = NULL; u32 temp; u32 ul_dsp_clk_rate; u32 ul_dsp_clk_addr; u32 ul_bios_gp_timer; u32 clk_cmd; struct io_mgr *hio_mgr; u32 ul_load_monitor_timer; struct omap_dsp_platform_data *pdata = omap_dspbridge_dev->dev.platform_data; /* The device context contains all the mmu setup info from when the * last dsp base image was loaded. The first entry is always * SHMMEM base. */ /* Get SHM_BEG - convert to byte address */ (void)dev_get_symbol(dev_context->hdev_obj, SHMBASENAME, &ul_shm_base_virt); ul_shm_base_virt *= DSPWORDSIZE; DBC_ASSERT(ul_shm_base_virt != 0); /* DSP Virtual address */ ul_tlb_base_virt = dev_context->sh_s.seg0_da; DBC_ASSERT(ul_tlb_base_virt <= ul_shm_base_virt); ul_shm_offset_virt = ul_shm_base_virt - (ul_tlb_base_virt * DSPWORDSIZE); /* Kernel logical address */ ul_shm_base = dev_context->sh_s.seg0_va + ul_shm_offset_virt; DBC_ASSERT(ul_shm_base != 0); /* 2nd wd is used as sync field */ dw_sync_addr = ul_shm_base + SHMSYNCOFFSET; /* Write a signature into the shm base + offset; this will * get cleared when the DSP program starts. */ if ((ul_shm_base_virt == 0) || (ul_shm_base == 0)) { pr_err("%s: Illegal SM base\n", __func__); status = -EPERM; } else __raw_writel(0xffffffff, dw_sync_addr); if (!status) { resources = dev_context->resources; if (!resources) status = -EPERM; /* Assert RST1 i.e only the RST only for DSP megacell */ if (!status) { (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST1_IVA2_MASK, OMAP3430_RST1_IVA2_MASK, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); /* Mask address with 1K for compatibility */ __raw_writel(dsp_addr & OMAP3_IVA2_BOOTADDR_MASK, OMAP343X_CTRL_REGADDR( OMAP343X_CONTROL_IVA2_BOOTADDR)); /* * Set bootmode to self loop if dsp_debug flag is true */ __raw_writel((dsp_debug) ? OMAP3_IVA2_BOOTMOD_IDLE : 0, OMAP343X_CTRL_REGADDR( OMAP343X_CONTROL_IVA2_BOOTMOD)); } } if (!status) { (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST2_IVA2_MASK, 0, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); mmu = dev_context->dsp_mmu; if (mmu) dsp_mmu_exit(mmu); mmu = dsp_mmu_init(); if (IS_ERR(mmu)) { dev_err(bridge, "dsp_mmu_init failed!\n"); dev_context->dsp_mmu = NULL; status = (int)mmu; } } if (!status) { dev_context->dsp_mmu = mmu; sm_sg = &dev_context->sh_s; sg0_da = iommu_kmap(mmu, sm_sg->seg0_da, sm_sg->seg0_pa, sm_sg->seg0_size, IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_32); if (IS_ERR_VALUE(sg0_da)) { status = (int)sg0_da; sg0_da = 0; } } if (!status) { sg1_da = iommu_kmap(mmu, sm_sg->seg1_da, sm_sg->seg1_pa, sm_sg->seg1_size, IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_32); if (IS_ERR_VALUE(sg1_da)) { status = (int)sg1_da; sg1_da = 0; } } if (!status) { u32 da; for (tlb_i = 0; tlb_i < BRDIOCTL_NUMOFMMUTLB; tlb_i++) { if (!tlb[tlb_i].ul_gpp_pa) continue; dev_dbg(bridge, "IOMMU %d GppPa: 0x%x DspVa 0x%x Size" " 0x%x\n", tlb_i, tlb[tlb_i].ul_gpp_pa, tlb[tlb_i].ul_dsp_va, tlb[tlb_i].ul_size); da = iommu_kmap(mmu, tlb[tlb_i].ul_dsp_va, tlb[tlb_i].ul_gpp_pa, PAGE_SIZE, IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_32); if (IS_ERR_VALUE(da)) { status = (int)da; break; } } } if (!status) { u32 da; l4_i = 0; while (l4_peripheral_table[l4_i].phys_addr) { da = iommu_kmap(mmu, l4_peripheral_table[l4_i]. dsp_virt_addr, l4_peripheral_table[l4_i]. phys_addr, PAGE_SIZE, IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_32); if (IS_ERR_VALUE(da)) { status = (int)da; break; } l4_i++; } } /* Lock the above TLB entries and get the BIOS and load monitor timer * information */ if (!status) { /* Enable the BIOS clock */ (void)dev_get_symbol(dev_context->hdev_obj, BRIDGEINIT_BIOSGPTIMER, &ul_bios_gp_timer); (void)dev_get_symbol(dev_context->hdev_obj, BRIDGEINIT_LOADMON_GPTIMER, &ul_load_monitor_timer); if (ul_load_monitor_timer != 0xFFFF) { clk_cmd = (BPWR_ENABLE_CLOCK << MBX_PM_CLK_CMDSHIFT) | ul_load_monitor_timer; dsp_peripheral_clk_ctrl(dev_context, &clk_cmd); } else { dev_dbg(bridge, "Not able to get the symbol for Load " "Monitor Timer\n"); } if (ul_bios_gp_timer != 0xFFFF) { clk_cmd = (BPWR_ENABLE_CLOCK << MBX_PM_CLK_CMDSHIFT) | ul_bios_gp_timer; dsp_peripheral_clk_ctrl(dev_context, &clk_cmd); } else { dev_dbg(bridge, "Not able to get the symbol for BIOS Timer\n"); } /* Set the DSP clock rate */ (void)dev_get_symbol(dev_context->hdev_obj, "_BRIDGEINIT_DSP_FREQ", &ul_dsp_clk_addr); /*Set Autoidle Mode for IVA2 PLL */ (*pdata->dsp_cm_write)(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT, OMAP3430_IVA2_MOD, OMAP3430_CM_AUTOIDLE_PLL); if ((unsigned int *)ul_dsp_clk_addr != NULL) { /* Get the clock rate */ ul_dsp_clk_rate = dsp_clk_get_iva2_rate(); dev_dbg(bridge, "%s: DSP clock rate (KHZ): 0x%x \n", __func__, ul_dsp_clk_rate); (void)bridge_brd_write(dev_context, (u8 *) &ul_dsp_clk_rate, ul_dsp_clk_addr, sizeof(u32), 0); } /* * Enable Mailbox events and also drain any pending * stale messages. */ dev_context->mbox = omap_mbox_get("dsp"); if (IS_ERR(dev_context->mbox)) { dev_context->mbox = NULL; pr_err("%s: Failed to get dsp mailbox handle\n", __func__); status = -EPERM; } } if (!status) { dev_context->mbox->rxq->callback = (int (*)(void *))io_mbox_msg; /*PM_IVA2GRPSEL_PER = 0xC0;*/ temp = readl(resources->dw_per_pm_base + 0xA8); temp = (temp & 0xFFFFFF30) | 0xC0; writel(temp, resources->dw_per_pm_base + 0xA8); /*PM_MPUGRPSEL_PER &= 0xFFFFFF3F; */ temp = readl(resources->dw_per_pm_base + 0xA4); temp = (temp & 0xFFFFFF3F); writel(temp, resources->dw_per_pm_base + 0xA4); /*CM_SLEEPDEP_PER |= 0x04; */ temp = readl(resources->dw_per_base + 0x44); temp = (temp & 0xFFFFFFFB) | 0x04; writel(temp, resources->dw_per_base + 0x44); /*CM_CLKSTCTRL_IVA2 = 0x00000003 -To Allow automatic transitions */ (*pdata->dsp_cm_write)(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, OMAP3430_IVA2_MOD, OMAP2_CM_CLKSTCTRL); /* Let DSP go */ dev_dbg(bridge, "%s Unreset\n", __func__); /* release the RST1, DSP starts executing now .. */ (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST1_IVA2_MASK, 0, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); dev_dbg(bridge, "Waiting for Sync @ 0x%x\n", dw_sync_addr); dev_dbg(bridge, "DSP c_int00 Address = 0x%x\n", dsp_addr); if (dsp_debug) while (__raw_readw(dw_sync_addr)) ;; /* Wait for DSP to clear word in shared memory */ /* Read the Location */ if (!wait_for_start(dev_context, dw_sync_addr)) status = -ETIMEDOUT; /* Start wdt */ dsp_wdt_sm_set((void *)ul_shm_base); dsp_wdt_enable(true); status = dev_get_io_mgr(dev_context->hdev_obj, &hio_mgr); if (hio_mgr) { io_sh_msetting(hio_mgr, SHM_OPPINFO, NULL); /* Write the synchronization bit to indicate the * completion of OPP table update to DSP */ __raw_writel(0XCAFECAFE, dw_sync_addr); /* update board state */ dev_context->dw_brd_state = BRD_RUNNING; return 0; } else { dev_context->dw_brd_state = BRD_UNKNOWN; } } while (tlb_i--) { if (!tlb[tlb_i].ul_gpp_pa) continue; iommu_kunmap(mmu, tlb[tlb_i].ul_gpp_va); } while (l4_i--) iommu_kunmap(mmu, l4_peripheral_table[l4_i].dsp_virt_addr); if (sg0_da) iommu_kunmap(mmu, sg0_da); if (sg1_da) iommu_kunmap(mmu, sg1_da); return status; }