Example #1
0
static void omap2_iommu_disable(struct omap_iommu *obj)
{
	struct omap_hwmod *oh;
	u32 l;

	oh = omap_hwmod_lookup(obj->name);
	if (!oh)
		return;
	/*
	 * IPU and DSP iommus are not directly connected to the processor
	 * instead they are  behind a shared MMU. Therefore in the case of
	 * a mmu fault and the mmu fault was not handled, even if the processor
	 * is under reset, the shared MMU will try to translation the address
	 * again causing that the status flag cannot be clear and therefore
	 * as soon as the clkdm wants to go to idle the clkdm will be stuck
	 * in transition state. The only way to reset the shared MMU is doing
	 * a hardreset of the L2 iommu which shared the reset line with the
	 * shared MMU. That way we can clean the status bit and turn off
	 * the iommu without any issue.
	 */
	if (!strcmp(obj->name, "ipu") || !strcmp(obj->name, "dsp")) {
		omap_hwmod_assert_hardreset(oh, oh->rst_lines->name);
		omap_hwmod_deassert_hardreset(oh, oh->rst_lines->name);
		goto out;
	}

	l = iommu_read_reg(obj, MMU_IRQSTATUS);
	iommu_write_reg(obj, l, MMU_IRQSTATUS);
	l = iommu_read_reg(obj, MMU_CNTL);
	l &= ~MMU_CNTL_MASK;
	iommu_write_reg(obj, l, MMU_CNTL);
out:
	clkdm_allow_idle(oh->clkdm);
	dev_dbg(obj->dev, "%s is shutting down\n", obj->name);
}
Example #2
0
/**
 * omap_device_deassert_hardreset - release a device's hardreset line
 * @pdev: struct platform_device * to reset
 * @name: const char * name of the reset line
 *
 * Release the hardreset line identified by @name on the IP blocks
 * associated with the hwmods backing the platform_device @pdev.  All
 * of the hwmods associated with @pdev must have the same hardreset
 * line linked to them for this to work.  Passes along the return
 * value of omap_hwmod_deassert_hardreset() in the event of any
 * failure, or returns 0 upon success.
 */
int omap_device_deassert_hardreset(struct platform_device *pdev,
                                   const char *name)
{
    struct omap_device *od = to_omap_device(pdev);
    int ret = 0;
    int i;

    for (i = 0; i < od->hwmods_cnt; i++) {
        ret = omap_hwmod_deassert_hardreset(od->hwmods[i], name);
        if (ret)
            break;
    }

    return ret;
}
Example #3
0
/**
 * omap_device_build_from_dt - build an omap_device with multiple hwmods
 * @pdev_name: name of the platform_device driver to use
 * @pdev_id: this platform_device's connection ID
 * @oh: ptr to the single omap_hwmod that backs this omap_device
 * @pdata: platform_data ptr to associate with the platform_device
 * @pdata_len: amount of memory pointed to by @pdata
 *
 * Function for building an omap_device already registered from device-tree
 *
 * Returns 0 or PTR_ERR() on error.
 */
static int omap_device_build_from_dt(struct platform_device *pdev)
{
    struct omap_hwmod **hwmods;
    struct omap_device *od;
    struct omap_hwmod *oh;
    struct device_node *node = pdev->dev.of_node;
    const char *oh_name, *rst_name;
    int oh_cnt, dstr_cnt, i, ret = 0;
    bool device_active = false;

    oh_cnt = of_property_count_strings(node, "ti,hwmods");
    if (oh_cnt <= 0) {
        dev_dbg(&pdev->dev, "No 'hwmods' to build omap_device\n");
        return -ENODEV;
    }

    hwmods = kzalloc(sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL);
    if (!hwmods) {
        ret = -ENOMEM;
        goto odbfd_exit;
    }

    for (i = 0; i < oh_cnt; i++) {
        of_property_read_string_index(node, "ti,hwmods", i, &oh_name);
        oh = omap_hwmod_lookup(oh_name);
        if (!oh) {
            dev_err(&pdev->dev, "Cannot lookup hwmod '%s'\n",
                    oh_name);
            ret = -EINVAL;
            goto odbfd_exit1;
        }
        hwmods[i] = oh;
        if (oh->flags & HWMOD_INIT_NO_IDLE)
            device_active = true;
    }

    od = omap_device_alloc(pdev, hwmods, oh_cnt);
    if (IS_ERR(od)) {
        dev_err(&pdev->dev, "Cannot allocate omap_device for :%s\n",
                oh_name);
        ret = PTR_ERR(od);
        goto odbfd_exit1;
    }

    /* Fix up missing resource names */
    for (i = 0; i < pdev->num_resources; i++) {
        struct resource *r = &pdev->resource[i];

        if (r->name == NULL)
            r->name = dev_name(&pdev->dev);
    }

    pdev->dev.pm_domain = &omap_device_pm_domain;

    if (device_active) {
        omap_device_enable(pdev);
        pm_runtime_set_active(&pdev->dev);
    }
    dstr_cnt =
        of_property_count_strings(node, "ti,deassert-hard-reset");
    if (dstr_cnt > 0) {
        for (i = 0; i < dstr_cnt; i += 2) {
            of_property_read_string_index(
                node, "ti,deassert-hard-reset", i,
                &oh_name);
            of_property_read_string_index(
                node, "ti,deassert-hard-reset", i+1,
                &rst_name);
            oh = omap_hwmod_lookup(oh_name);
            if (!oh) {
                dev_warn(&pdev->dev,
                         "Cannot parse deassert property for '%s'\n",
                         oh_name);
                break;
            }
            omap_hwmod_deassert_hardreset(oh, rst_name);
        }
    }

odbfd_exit1:
    kfree(hwmods);
odbfd_exit:
    /* if data/we are at fault.. load up a fail handler */
    if (ret)
        pdev->dev.pm_domain = &omap_device_fail_pm_domain;

    return ret;
}
/**
 * omap_device_build_from_dt - build an omap_device with multiple hwmods
 * @pdev_name: name of the platform_device driver to use
 * @pdev_id: this platform_device's connection ID
 * @oh: ptr to the single omap_hwmod that backs this omap_device
 * @pdata: platform_data ptr to associate with the platform_device
 * @pdata_len: amount of memory pointed to by @pdata
 * @pm_lats: pointer to a omap_device_pm_latency array for this device
 * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats
 * @is_early_device: should the device be registered as an early device or not
 *
 * Function for building an omap_device already registered from device-tree
 *
 * Returns 0 or PTR_ERR() on error.
 */
static int omap_device_build_from_dt(struct platform_device *pdev)
{
	struct omap_hwmod **hwmods;
	struct omap_device *od;
	struct omap_hwmod *oh;
	struct device_node *node = pdev->dev.of_node;
	const char *oh_name, *rst_name;
	int oh_cnt, dstr_cnt, i, ret = 0;

	oh_cnt = of_property_count_strings(node, "ti,hwmods");
	if (!oh_cnt || IS_ERR_VALUE(oh_cnt)) {
		dev_dbg(&pdev->dev, "No 'hwmods' to build omap_device\n");
		return -ENODEV;
	}

	hwmods = kzalloc(sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL);
	if (!hwmods) {
		ret = -ENOMEM;
		goto odbfd_exit;
	}

	for (i = 0; i < oh_cnt; i++) {
		of_property_read_string_index(node, "ti,hwmods", i, &oh_name);
		oh = omap_hwmod_lookup(oh_name);
		if (!oh) {
			dev_err(&pdev->dev, "Cannot lookup hwmod '%s'\n",
				oh_name);
			ret = -EINVAL;
			goto odbfd_exit1;
		}
		hwmods[i] = oh;
	}

	od = omap_device_alloc(pdev, hwmods, oh_cnt, NULL, 0);
	if (!od) {
		dev_err(&pdev->dev, "Cannot allocate omap_device for :%s\n",
			oh_name);
		ret = PTR_ERR(od);
		goto odbfd_exit1;
	}

	/* Fix up missing resource names */
	for (i = 0; i < pdev->num_resources; i++) {
		struct resource *r = &pdev->resource[i];

		if (r->name == NULL)
			r->name = dev_name(&pdev->dev);
	}

	if (of_get_property(node, "ti,no_idle_on_suspend", NULL))
		omap_device_disable_idle_on_suspend(pdev);

	dstr_cnt =
		of_property_count_strings(node, "ti,deassert-hard-reset");
	if (dstr_cnt > 0) {
		for (i = 0; i < dstr_cnt; i += 2) {
			of_property_read_string_index(
				node, "ti,deassert-hard-reset", i,
				&oh_name);
			of_property_read_string_index(
				node, "ti,deassert-hard-reset", i+1,
				&rst_name);
			oh = omap_hwmod_lookup(oh_name);
			if (!oh) {
				dev_warn(&pdev->dev,
				"Cannot parse deassert property for '%s'\n",
				oh_name);
				break;
			}
			omap_hwmod_deassert_hardreset(oh, rst_name);
		}
	}

	pdev->dev.pm_domain = &omap_device_pm_domain;

odbfd_exit1:
	kfree(hwmods);
odbfd_exit:
	return ret;
}
Example #5
0
/* 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;
}