Пример #1
0
/*
 *  ======== dsp_clk_exit ========
 *  Purpose:
 *      Cleanup CLK module.
 */
void dsp_clk_exit(void)
{
	dsp_clock_disable_all(dsp_clocks);

	clk_put(iva2_clk);
	clk_put(ssi.sst_fck);
	clk_put(ssi.ssr_fck);
	clk_put(ssi.ick);
}
Пример #2
0
void bridge_deh_notify(struct deh_mgr *deh, int event, int info)
{
	struct bridge_dev_context *dev_context;
	const char *str = event_to_string(event);

	if (!deh)
		return;

	dev_dbg(bridge, "%s: device exception", __func__);
	dev_context = deh->bridge_context;

	switch (event) {
	case DSP_SYSERROR:
		dev_err(bridge, "%s: %s, info=0x%x", __func__,
				str, info);
#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
		dump_dl_modules(dev_context);
		dump_dsp_stack(dev_context);
#endif
		break;
	case DSP_MMUFAULT:
		dev_err(bridge, "%s: %s, addr=0x%x", __func__,
				str, fault_addr);
#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
		print_dsp_trace_buffer(dev_context);
		dump_dl_modules(dev_context);
		mmu_fault_print_stack(dev_context);
#endif
		break;
	default:
		dev_err(bridge, "%s: %s", __func__, str);
		break;
	}

	/* Filter subsequent notifications when an error occurs */
	if (dev_context->brd_state != BRD_ERROR) {
		ntfy_notify(deh->ntfy_obj, event);
#ifdef CONFIG_TIDSPBRIDGE_RECOVERY
		bridge_recover_schedule();
#endif
	}

	/* Set the Board state as ERROR */
	dev_context->brd_state = BRD_ERROR;
	/* Disable all the clocks that were enabled by DSP */
	dsp_clock_disable_all(dev_context->dsp_per_clks);
	/*
	 * Avoid the subsequent WDT if it happens once,
	 * also if fatal error occurs.
	 */
	dsp_wdt_enable(false);
}
Пример #3
0
/*
 *  ======== sleep_dsp ========
 *  	Put DSP in low power consuming state.
 */
int sleep_dsp(struct bridge_dev_context *dev_context, u32 dw_cmd,
		     void *pargs)
{
	int status = 0;
#ifdef CONFIG_PM
#ifdef CONFIG_TIDSPBRIDGE_NTFY_PWRERR
	struct deh_mgr *hdeh_mgr;
#endif /* CONFIG_TIDSPBRIDGE_NTFY_PWRERR */
	u16 timeout = PWRSTST_TIMEOUT / 10;
	u32 pwr_state, target_pwr_state;
	struct omap_dsp_platform_data *pdata =
		omap_dspbridge_dev->dev.platform_data;

	/* Check if sleep code is valid */
	if ((dw_cmd != PWR_DEEPSLEEP) && (dw_cmd != PWR_EMERGENCYDEEPSLEEP))
		return -EINVAL;

	switch (dev_context->brd_state) {
	case BRD_RUNNING:
		omap_mbox_save_ctx(dev_context->mbox);
		if (dsp_test_sleepstate == PWRDM_POWER_OFF) {
			sm_interrupt_dsp(dev_context, MBX_PM_DSPHIBERNATE);
			dev_dbg(bridge, "PM: %s - sent hibernate cmd to DSP\n",
				__func__);
			target_pwr_state = PWRDM_POWER_OFF;
		} else {
			sm_interrupt_dsp(dev_context, MBX_PM_DSPRETENTION);
			target_pwr_state = PWRDM_POWER_RET;
		}
		break;
	case BRD_RETENTION:
		omap_mbox_save_ctx(dev_context->mbox);
		if (dsp_test_sleepstate == PWRDM_POWER_OFF) {
			sm_interrupt_dsp(dev_context, MBX_PM_DSPHIBERNATE);
			target_pwr_state = PWRDM_POWER_OFF;
		} else
			return 0;
		break;
	case BRD_HIBERNATION:
	case BRD_DSP_HIBERNATION:
		/* Already in Hibernation, so just return */
		dev_dbg(bridge, "PM: %s - DSP already in hibernation\n",
			__func__);
		return 0;
	case BRD_STOPPED:
		dev_dbg(bridge, "PM: %s - Board in STOP state\n", __func__);
		return 0;
	default:
		dev_dbg(bridge, "PM: %s - Bridge in Illegal state\n", __func__);
		return -EPERM;
	}

	/* Get the PRCM DSP power domain status */
	pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD, OMAP2_PM_PWSTST) &
						OMAP_POWERSTATEST_MASK;

	/* Wait for DSP to move into target power state */
	while ((pwr_state != target_pwr_state) && --timeout) {
		if (msleep_interruptible(10)) {
			pr_err("Waiting for DSP to Suspend interrupted\n");
			return -EPERM;
		}
		pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD,
					OMAP2_PM_PWSTST) & OMAP_POWERSTATEST_MASK;
	}

	if (!timeout) {
		pr_err("%s: Timed out waiting for DSP off mode, state %x\n",
		       __func__, pwr_state);
#ifdef CONFIG_TIDSPBRIDGE_NTFY_PWRERR
		dev_get_deh_mgr(dev_context->dev_obj, &hdeh_mgr);
		bridge_deh_notify(hdeh_mgr, DSP_PWRERROR, 0);
#endif /* CONFIG_TIDSPBRIDGE_NTFY_PWRERR */
		return -ETIMEDOUT;
	} else {
		/* Update the Bridger Driver state */
		if (dsp_test_sleepstate == PWRDM_POWER_OFF)
			dev_context->brd_state = BRD_HIBERNATION;
		else
			dev_context->brd_state = BRD_RETENTION;

		/* Disable wdt on hibernation. */
		dsp_wdt_enable(false);

		/* Turn off DSP Peripheral clocks */
		status = dsp_clock_disable_all(dev_context->dsp_per_clks);
		if (status)
			return status;
#ifdef CONFIG_TIDSPBRIDGE_DVFS
		else if (target_pwr_state == PWRDM_POWER_OFF) {
			/*
			 * Set the OPP to low level before moving to OFF mode
			 */
			if (pdata->dsp_set_min_opp)
				(*pdata->dsp_set_min_opp) (VDD1_OPP1);
		}
#endif /* CONFIG_TIDSPBRIDGE_DVFS */
	}
#endif /* CONFIG_PM */
	return status;
}
Пример #4
0
/*
 *  ======== handle_hibernation_from_dsp ========
 *  	Handle Hibernation requested from DSP
 */
int handle_hibernation_from_dsp(struct bridge_dev_context *dev_context)
{
	int status = 0;
#ifdef CONFIG_PM
	u16 timeout = PWRSTST_TIMEOUT / 10;
	u32 pwr_state;
#ifdef CONFIG_TIDSPBRIDGE_DVFS
	u32 opplevel;
	struct io_mgr *hio_mgr;
#endif
	struct omap_dsp_platform_data *pdata =
		omap_dspbridge_dev->dev.platform_data;

	pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD, OMAP2_PM_PWSTST) &
						OMAP_POWERSTATEST_MASK;
	/* Wait for DSP to move into OFF state */
	while ((pwr_state != PWRDM_POWER_OFF) && --timeout) {
		if (msleep_interruptible(10)) {
			pr_err("Waiting for DSP OFF mode interrupted\n");
			return -EPERM;
		}
		pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD,
					OMAP2_PM_PWSTST) & OMAP_POWERSTATEST_MASK;
	}
	if (timeout == 0) {
		pr_err("%s: Timed out waiting for DSP off mode\n", __func__);
		status = -ETIMEDOUT;
		return status;
	} else {

		/* Save mailbox settings */
		omap_mbox_save_ctx(dev_context->mbox);

		/* Turn off DSP Peripheral clocks and DSP Load monitor timer */
		status = dsp_clock_disable_all(dev_context->dsp_per_clks);

		/* Disable wdt on hibernation. */
		dsp_wdt_enable(false);

		if (!status) {
			/* Update the Bridger Driver state */
			dev_context->brd_state = BRD_DSP_HIBERNATION;
#ifdef CONFIG_TIDSPBRIDGE_DVFS
			status =
			    dev_get_io_mgr(dev_context->dev_obj, &hio_mgr);
			if (!hio_mgr) {
				status = DSP_EHANDLE;
				return status;
			}
			io_sh_msetting(hio_mgr, SHM_GETOPP, &opplevel);

			/*
			 * Set the OPP to low level before moving to OFF
			 * mode
			 */
			if (pdata->dsp_set_min_opp)
				(*pdata->dsp_set_min_opp) (VDD1_OPP1);
			status = 0;
#endif /* CONFIG_TIDSPBRIDGE_DVFS */
		}
	}
#endif
	return status;
}
Пример #5
0
/*
 *  ======== bridge_brd_stop ========
 *  purpose:
 *      Puts DSP in self loop.
 *
 *  Preconditions :
 *  a) None
 */
static int bridge_brd_stop(struct bridge_dev_context *dev_ctxt)
{
	int status = 0;
	struct bridge_dev_context *dev_context = dev_ctxt;
	u32 dsp_pwr_state;
	int i;
	struct bridge_ioctl_extproc *tlb = dev_context->atlb_entry;
	struct omap_dsp_platform_data *pdata =
		omap_dspbridge_dev->dev.platform_data;

	if (dev_context->dw_brd_state == BRD_STOPPED)
		return status;

	/* as per TRM, it is advised to first drive the IVA2 to 'Standby' mode,
	 * before turning off the clocks.. This is to ensure that there are no
	 * pending L3 or other transactons from IVA2 */
	dsp_pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD, OMAP2_PM_PWSTST) &
					OMAP_POWERSTATEST_MASK;
	if (dsp_pwr_state != PWRDM_POWER_OFF) {
		(*pdata->dsp_prm_rmw_bits)(OMAP3430_RST2_IVA2_MASK, 0,
					OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
		sm_interrupt_dsp(dev_context, MBX_PM_DSPIDLE);
		mdelay(10);

		/* IVA2 is not in OFF state */
		/* Set PM_PWSTCTRL_IVA2  to OFF */
		(*pdata->dsp_prm_rmw_bits)(OMAP_POWERSTATEST_MASK,
			PWRDM_POWER_OFF, OMAP3430_IVA2_MOD, OMAP2_PM_PWSTCTRL);
		/* Set the SW supervised state transition for Sleep */
		(*pdata->dsp_cm_write)(OMAP34XX_CLKSTCTRL_FORCE_SLEEP,
					OMAP3430_IVA2_MOD, OMAP2_CM_CLKSTCTRL);
	}
	udelay(10);
	/* Release the Ext Base virtual Address as the next DSP Program
	 * may have a different load address */
	if (dev_context->dw_dsp_ext_base_addr)
		dev_context->dw_dsp_ext_base_addr = 0;

	dev_context->dw_brd_state = BRD_STOPPED;	/* update board state */

	dsp_wdt_enable(false);

	/* Reset DSP */
	(*pdata->dsp_prm_rmw_bits)(OMAP3430_RST1_IVA2_MASK,
		OMAP3430_RST1_IVA2_MASK, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);

	/* Disable the mailbox interrupts */
	if (dev_context->mbox) {
		omap_mbox_disable_irq(dev_context->mbox, IRQ_RX);
		omap_mbox_put(dev_context->mbox);
		dev_context->mbox = NULL;
	}
	if (dev_context->dsp_mmu) {
		pr_err("Proc stop mmu if statement\n");
		for (i = 0; i < BRDIOCTL_NUMOFMMUTLB; i++) {
			if (!tlb[i].ul_gpp_pa)
				continue;
			iommu_kunmap(dev_context->dsp_mmu, tlb[i].ul_gpp_va);
		}
		i = 0;
		while (l4_peripheral_table[i].phys_addr) {
			iommu_kunmap(dev_context->dsp_mmu,
				l4_peripheral_table[i].dsp_virt_addr);
			i++;
		}
		iommu_kunmap(dev_context->dsp_mmu, dev_context->sh_s.seg0_da);
		iommu_kunmap(dev_context->dsp_mmu, dev_context->sh_s.seg1_da);
		dsp_mmu_exit(dev_context->dsp_mmu);
		dev_context->dsp_mmu = NULL;
	}
	/* Reset IVA IOMMU*/
	(*pdata->dsp_prm_rmw_bits)(OMAP3430_RST2_IVA2_MASK,
		OMAP3430_RST2_IVA2_MASK, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);

	dsp_clock_disable_all(dev_context->dsp_per_clks);
	dsp_clk_disable(DSP_CLK_IVA2);

	return status;
}