cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

omap_device.c (16906B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * omap_device implementation
      4 *
      5 * Copyright (C) 2009-2010 Nokia Corporation
      6 * Paul Walmsley, Kevin Hilman
      7 *
      8 * Developed in collaboration with (alphabetical order): Benoit
      9 * Cousson, Thara Gopinath, Tony Lindgren, Rajendra Nayak, Vikram
     10 * Pandita, Sakari Poussa, Anand Sawant, Santosh Shilimkar, Richard
     11 * Woodruff
     12 *
     13 * This code provides a consistent interface for OMAP device drivers
     14 * to control power management and interconnect properties of their
     15 * devices.
     16 *
     17 * In the medium- to long-term, this code should be implemented as a
     18 * proper omap_bus/omap_device in Linux, no more platform_data func
     19 * pointers
     20 */
     21#undef DEBUG
     22
     23#include <linux/kernel.h>
     24#include <linux/platform_device.h>
     25#include <linux/slab.h>
     26#include <linux/err.h>
     27#include <linux/io.h>
     28#include <linux/clk.h>
     29#include <linux/clkdev.h>
     30#include <linux/pm_domain.h>
     31#include <linux/pm_runtime.h>
     32#include <linux/of.h>
     33#include <linux/of_address.h>
     34#include <linux/of_irq.h>
     35#include <linux/notifier.h>
     36
     37#include "common.h"
     38#include "soc.h"
     39#include "omap_device.h"
     40#include "omap_hwmod.h"
     41
     42/* Private functions */
     43
     44static void _add_clkdev(struct omap_device *od, const char *clk_alias,
     45		       const char *clk_name)
     46{
     47	struct clk *r;
     48	int rc;
     49
     50	if (!clk_alias || !clk_name)
     51		return;
     52
     53	dev_dbg(&od->pdev->dev, "Creating %s -> %s\n", clk_alias, clk_name);
     54
     55	r = clk_get_sys(dev_name(&od->pdev->dev), clk_alias);
     56	if (!IS_ERR(r)) {
     57		dev_dbg(&od->pdev->dev,
     58			 "alias %s already exists\n", clk_alias);
     59		clk_put(r);
     60		return;
     61	}
     62
     63	r = clk_get_sys(NULL, clk_name);
     64
     65	if (IS_ERR(r)) {
     66		struct of_phandle_args clkspec;
     67
     68		clkspec.np = of_find_node_by_name(NULL, clk_name);
     69
     70		r = of_clk_get_from_provider(&clkspec);
     71
     72		rc = clk_register_clkdev(r, clk_alias,
     73					 dev_name(&od->pdev->dev));
     74	} else {
     75		rc = clk_add_alias(clk_alias, dev_name(&od->pdev->dev),
     76				   clk_name, NULL);
     77	}
     78
     79	if (rc) {
     80		if (rc == -ENODEV || rc == -ENOMEM)
     81			dev_err(&od->pdev->dev,
     82				"clkdev_alloc for %s failed\n", clk_alias);
     83		else
     84			dev_err(&od->pdev->dev,
     85				"clk_get for %s failed\n", clk_name);
     86	}
     87}
     88
     89/**
     90 * _add_hwmod_clocks_clkdev - Add clkdev entry for hwmod optional clocks
     91 * and main clock
     92 * @od: struct omap_device *od
     93 * @oh: struct omap_hwmod *oh
     94 *
     95 * For the main clock and every optional clock present per hwmod per
     96 * omap_device, this function adds an entry in the clkdev table of the
     97 * form <dev-id=dev_name, con-id=role> if it does not exist already.
     98 *
     99 * This allows drivers to get a pointer to its optional clocks based on its role
    100 * by calling clk_get(<dev*>, <role>).
    101 * In the case of the main clock, a "fck" alias is used.
    102 *
    103 * No return value.
    104 */
    105static void _add_hwmod_clocks_clkdev(struct omap_device *od,
    106				     struct omap_hwmod *oh)
    107{
    108	int i;
    109
    110	_add_clkdev(od, "fck", oh->main_clk);
    111
    112	for (i = 0; i < oh->opt_clks_cnt; i++)
    113		_add_clkdev(od, oh->opt_clks[i].role, oh->opt_clks[i].clk);
    114}
    115
    116
    117/**
    118 * omap_device_build_from_dt - build an omap_device with multiple hwmods
    119 * @pdev: The platform device to update.
    120 *
    121 * Function for building an omap_device already registered from device-tree
    122 *
    123 * Returns 0 or PTR_ERR() on error.
    124 */
    125static int omap_device_build_from_dt(struct platform_device *pdev)
    126{
    127	struct omap_hwmod **hwmods;
    128	struct omap_device *od;
    129	struct omap_hwmod *oh;
    130	struct device_node *node = pdev->dev.of_node;
    131	struct resource res;
    132	const char *oh_name;
    133	int oh_cnt, i, ret = 0;
    134	bool device_active = false, skip_pm_domain = false;
    135
    136	oh_cnt = of_property_count_strings(node, "ti,hwmods");
    137	if (oh_cnt <= 0) {
    138		dev_dbg(&pdev->dev, "No 'hwmods' to build omap_device\n");
    139		return -ENODEV;
    140	}
    141
    142	/* SDMA still needs special handling for omap_device_build() */
    143	ret = of_property_read_string_index(node, "ti,hwmods", 0, &oh_name);
    144	if (!ret && (!strncmp("dma_system", oh_name, 10) ||
    145		     !strncmp("dma", oh_name, 3)))
    146		skip_pm_domain = true;
    147
    148	/* Use ti-sysc driver instead of omap_device? */
    149	if (!skip_pm_domain &&
    150	    !omap_hwmod_parse_module_range(NULL, node, &res))
    151		return -ENODEV;
    152
    153	hwmods = kcalloc(oh_cnt, sizeof(struct omap_hwmod *), GFP_KERNEL);
    154	if (!hwmods) {
    155		ret = -ENOMEM;
    156		goto odbfd_exit;
    157	}
    158
    159	for (i = 0; i < oh_cnt; i++) {
    160		of_property_read_string_index(node, "ti,hwmods", i, &oh_name);
    161		oh = omap_hwmod_lookup(oh_name);
    162		if (!oh) {
    163			dev_err(&pdev->dev, "Cannot lookup hwmod '%s'\n",
    164				oh_name);
    165			ret = -EINVAL;
    166			goto odbfd_exit1;
    167		}
    168		hwmods[i] = oh;
    169		if (oh->flags & HWMOD_INIT_NO_IDLE)
    170			device_active = true;
    171	}
    172
    173	od = omap_device_alloc(pdev, hwmods, oh_cnt);
    174	if (IS_ERR(od)) {
    175		dev_err(&pdev->dev, "Cannot allocate omap_device for :%s\n",
    176			oh_name);
    177		ret = PTR_ERR(od);
    178		goto odbfd_exit1;
    179	}
    180
    181	/* Fix up missing resource names */
    182	for (i = 0; i < pdev->num_resources; i++) {
    183		struct resource *r = &pdev->resource[i];
    184
    185		if (r->name == NULL)
    186			r->name = dev_name(&pdev->dev);
    187	}
    188
    189	if (!skip_pm_domain) {
    190		dev_pm_domain_set(&pdev->dev, &omap_device_pm_domain);
    191		if (device_active) {
    192			omap_device_enable(pdev);
    193			pm_runtime_set_active(&pdev->dev);
    194		}
    195	}
    196
    197odbfd_exit1:
    198	kfree(hwmods);
    199odbfd_exit:
    200	/* if data/we are at fault.. load up a fail handler */
    201	if (ret)
    202		dev_pm_domain_set(&pdev->dev, &omap_device_fail_pm_domain);
    203
    204	return ret;
    205}
    206
    207static int _omap_device_notifier_call(struct notifier_block *nb,
    208				      unsigned long event, void *dev)
    209{
    210	struct platform_device *pdev = to_platform_device(dev);
    211	struct omap_device *od;
    212	int err;
    213
    214	switch (event) {
    215	case BUS_NOTIFY_REMOVED_DEVICE:
    216		if (pdev->archdata.od)
    217			omap_device_delete(pdev->archdata.od);
    218		break;
    219	case BUS_NOTIFY_UNBOUND_DRIVER:
    220		od = to_omap_device(pdev);
    221		if (od && (od->_state == OMAP_DEVICE_STATE_ENABLED)) {
    222			dev_info(dev, "enabled after unload, idling\n");
    223			err = omap_device_idle(pdev);
    224			if (err)
    225				dev_err(dev, "failed to idle\n");
    226		}
    227		break;
    228	case BUS_NOTIFY_BIND_DRIVER:
    229		od = to_omap_device(pdev);
    230		if (od) {
    231			od->_driver_status = BUS_NOTIFY_BIND_DRIVER;
    232			if (od->_state == OMAP_DEVICE_STATE_ENABLED &&
    233			    pm_runtime_status_suspended(dev)) {
    234				pm_runtime_set_active(dev);
    235			}
    236		}
    237		break;
    238	case BUS_NOTIFY_ADD_DEVICE:
    239		if (pdev->dev.of_node)
    240			omap_device_build_from_dt(pdev);
    241		omap_auxdata_legacy_init(dev);
    242		fallthrough;
    243	default:
    244		od = to_omap_device(pdev);
    245		if (od)
    246			od->_driver_status = event;
    247	}
    248
    249	return NOTIFY_DONE;
    250}
    251
    252/**
    253 * _omap_device_enable_hwmods - call omap_hwmod_enable() on all hwmods
    254 * @od: struct omap_device *od
    255 *
    256 * Enable all underlying hwmods.  Returns 0.
    257 */
    258static int _omap_device_enable_hwmods(struct omap_device *od)
    259{
    260	int ret = 0;
    261	int i;
    262
    263	for (i = 0; i < od->hwmods_cnt; i++)
    264		ret |= omap_hwmod_enable(od->hwmods[i]);
    265
    266	return ret;
    267}
    268
    269/**
    270 * _omap_device_idle_hwmods - call omap_hwmod_idle() on all hwmods
    271 * @od: struct omap_device *od
    272 *
    273 * Idle all underlying hwmods.  Returns 0.
    274 */
    275static int _omap_device_idle_hwmods(struct omap_device *od)
    276{
    277	int ret = 0;
    278	int i;
    279
    280	for (i = 0; i < od->hwmods_cnt; i++)
    281		ret |= omap_hwmod_idle(od->hwmods[i]);
    282
    283	return ret;
    284}
    285
    286/* Public functions for use by core code */
    287
    288/**
    289 * omap_device_get_context_loss_count - get lost context count
    290 * @pdev: The platform device to update.
    291 *
    292 * Using the primary hwmod, query the context loss count for this
    293 * device.
    294 *
    295 * Callers should consider context for this device lost any time this
    296 * function returns a value different than the value the caller got
    297 * the last time it called this function.
    298 *
    299 * If any hwmods exist for the omap_device associated with @pdev,
    300 * return the context loss counter for that hwmod, otherwise return
    301 * zero.
    302 */
    303int omap_device_get_context_loss_count(struct platform_device *pdev)
    304{
    305	struct omap_device *od;
    306	u32 ret = 0;
    307
    308	od = to_omap_device(pdev);
    309
    310	if (od->hwmods_cnt)
    311		ret = omap_hwmod_get_context_loss_count(od->hwmods[0]);
    312
    313	return ret;
    314}
    315
    316/**
    317 * omap_device_alloc - allocate an omap_device
    318 * @pdev: platform_device that will be included in this omap_device
    319 * @ohs: ptr to the omap_hwmod for this omap_device
    320 * @oh_cnt: the size of the ohs list
    321 *
    322 * Convenience function for allocating an omap_device structure and filling
    323 * hwmods, and resources.
    324 *
    325 * Returns an struct omap_device pointer or ERR_PTR() on error;
    326 */
    327struct omap_device *omap_device_alloc(struct platform_device *pdev,
    328					struct omap_hwmod **ohs, int oh_cnt)
    329{
    330	int ret = -ENOMEM;
    331	struct omap_device *od;
    332	int i;
    333	struct omap_hwmod **hwmods;
    334
    335	od = kzalloc(sizeof(struct omap_device), GFP_KERNEL);
    336	if (!od)
    337		goto oda_exit1;
    338
    339	od->hwmods_cnt = oh_cnt;
    340
    341	hwmods = kmemdup(ohs, sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL);
    342	if (!hwmods)
    343		goto oda_exit2;
    344
    345	od->hwmods = hwmods;
    346	od->pdev = pdev;
    347	pdev->archdata.od = od;
    348
    349	for (i = 0; i < oh_cnt; i++) {
    350		hwmods[i]->od = od;
    351		_add_hwmod_clocks_clkdev(od, hwmods[i]);
    352	}
    353
    354	return od;
    355
    356oda_exit2:
    357	kfree(od);
    358oda_exit1:
    359	dev_err(&pdev->dev, "omap_device: build failed (%d)\n", ret);
    360
    361	return ERR_PTR(ret);
    362}
    363
    364void omap_device_delete(struct omap_device *od)
    365{
    366	if (!od)
    367		return;
    368
    369	od->pdev->archdata.od = NULL;
    370	kfree(od->hwmods);
    371	kfree(od);
    372}
    373
    374#ifdef CONFIG_PM
    375static int _od_runtime_suspend(struct device *dev)
    376{
    377	struct platform_device *pdev = to_platform_device(dev);
    378	int ret;
    379
    380	ret = pm_generic_runtime_suspend(dev);
    381	if (ret)
    382		return ret;
    383
    384	return omap_device_idle(pdev);
    385}
    386
    387static int _od_runtime_resume(struct device *dev)
    388{
    389	struct platform_device *pdev = to_platform_device(dev);
    390	int ret;
    391
    392	ret = omap_device_enable(pdev);
    393	if (ret) {
    394		dev_err(dev, "use pm_runtime_put_sync_suspend() in driver?\n");
    395		return ret;
    396	}
    397
    398	return pm_generic_runtime_resume(dev);
    399}
    400
    401static int _od_fail_runtime_suspend(struct device *dev)
    402{
    403	dev_warn(dev, "%s: FIXME: missing hwmod/omap_dev info\n", __func__);
    404	return -ENODEV;
    405}
    406
    407static int _od_fail_runtime_resume(struct device *dev)
    408{
    409	dev_warn(dev, "%s: FIXME: missing hwmod/omap_dev info\n", __func__);
    410	return -ENODEV;
    411}
    412
    413#endif
    414
    415#ifdef CONFIG_SUSPEND
    416static int _od_suspend_noirq(struct device *dev)
    417{
    418	struct platform_device *pdev = to_platform_device(dev);
    419	struct omap_device *od = to_omap_device(pdev);
    420	int ret;
    421
    422	/* Don't attempt late suspend on a driver that is not bound */
    423	if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER)
    424		return 0;
    425
    426	ret = pm_generic_suspend_noirq(dev);
    427
    428	if (!ret && !pm_runtime_status_suspended(dev)) {
    429		if (pm_generic_runtime_suspend(dev) == 0) {
    430			omap_device_idle(pdev);
    431			od->flags |= OMAP_DEVICE_SUSPENDED;
    432		}
    433	}
    434
    435	return ret;
    436}
    437
    438static int _od_resume_noirq(struct device *dev)
    439{
    440	struct platform_device *pdev = to_platform_device(dev);
    441	struct omap_device *od = to_omap_device(pdev);
    442
    443	if (od->flags & OMAP_DEVICE_SUSPENDED) {
    444		od->flags &= ~OMAP_DEVICE_SUSPENDED;
    445		omap_device_enable(pdev);
    446		pm_generic_runtime_resume(dev);
    447	}
    448
    449	return pm_generic_resume_noirq(dev);
    450}
    451#else
    452#define _od_suspend_noirq NULL
    453#define _od_resume_noirq NULL
    454#endif
    455
    456struct dev_pm_domain omap_device_fail_pm_domain = {
    457	.ops = {
    458		SET_RUNTIME_PM_OPS(_od_fail_runtime_suspend,
    459				   _od_fail_runtime_resume, NULL)
    460	}
    461};
    462
    463struct dev_pm_domain omap_device_pm_domain = {
    464	.ops = {
    465		SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume,
    466				   NULL)
    467		USE_PLATFORM_PM_SLEEP_OPS
    468		SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(_od_suspend_noirq,
    469					      _od_resume_noirq)
    470	}
    471};
    472
    473/* Public functions for use by device drivers through struct platform_data */
    474
    475/**
    476 * omap_device_enable - fully activate an omap_device
    477 * @pdev: the platform device to activate
    478 *
    479 * Do whatever is necessary for the hwmods underlying omap_device @od
    480 * to be accessible and ready to operate.  This generally involves
    481 * enabling clocks, setting SYSCONFIG registers; and in the future may
    482 * involve remuxing pins.  Device drivers should call this function
    483 * indirectly via pm_runtime_get*().  Returns -EINVAL if called when
    484 * the omap_device is already enabled, or passes along the return
    485 * value of _omap_device_enable_hwmods().
    486 */
    487int omap_device_enable(struct platform_device *pdev)
    488{
    489	int ret;
    490	struct omap_device *od;
    491
    492	od = to_omap_device(pdev);
    493
    494	if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
    495		dev_warn(&pdev->dev,
    496			 "omap_device: %s() called from invalid state %d\n",
    497			 __func__, od->_state);
    498		return -EINVAL;
    499	}
    500
    501	ret = _omap_device_enable_hwmods(od);
    502
    503	if (ret == 0)
    504		od->_state = OMAP_DEVICE_STATE_ENABLED;
    505
    506	return ret;
    507}
    508
    509/**
    510 * omap_device_idle - idle an omap_device
    511 * @pdev: The platform_device (omap_device) to idle
    512 *
    513 * Idle omap_device @od.  Device drivers call this function indirectly
    514 * via pm_runtime_put*().  Returns -EINVAL if the omap_device is not
    515 * currently enabled, or passes along the return value of
    516 * _omap_device_idle_hwmods().
    517 */
    518int omap_device_idle(struct platform_device *pdev)
    519{
    520	int ret;
    521	struct omap_device *od;
    522
    523	od = to_omap_device(pdev);
    524
    525	if (od->_state != OMAP_DEVICE_STATE_ENABLED) {
    526		dev_warn(&pdev->dev,
    527			 "omap_device: %s() called from invalid state %d\n",
    528			 __func__, od->_state);
    529		return -EINVAL;
    530	}
    531
    532	ret = _omap_device_idle_hwmods(od);
    533
    534	if (ret == 0)
    535		od->_state = OMAP_DEVICE_STATE_IDLE;
    536
    537	return ret;
    538}
    539
    540/**
    541 * omap_device_assert_hardreset - set a device's hardreset line
    542 * @pdev: struct platform_device * to reset
    543 * @name: const char * name of the reset line
    544 *
    545 * Set the hardreset line identified by @name on the IP blocks
    546 * associated with the hwmods backing the platform_device @pdev.  All
    547 * of the hwmods associated with @pdev must have the same hardreset
    548 * line linked to them for this to work.  Passes along the return value
    549 * of omap_hwmod_assert_hardreset() in the event of any failure, or
    550 * returns 0 upon success.
    551 */
    552int omap_device_assert_hardreset(struct platform_device *pdev, const char *name)
    553{
    554	struct omap_device *od = to_omap_device(pdev);
    555	int ret = 0;
    556	int i;
    557
    558	for (i = 0; i < od->hwmods_cnt; i++) {
    559		ret = omap_hwmod_assert_hardreset(od->hwmods[i], name);
    560		if (ret)
    561			break;
    562	}
    563
    564	return ret;
    565}
    566
    567/**
    568 * omap_device_deassert_hardreset - release a device's hardreset line
    569 * @pdev: struct platform_device * to reset
    570 * @name: const char * name of the reset line
    571 *
    572 * Release the hardreset line identified by @name on the IP blocks
    573 * associated with the hwmods backing the platform_device @pdev.  All
    574 * of the hwmods associated with @pdev must have the same hardreset
    575 * line linked to them for this to work.  Passes along the return
    576 * value of omap_hwmod_deassert_hardreset() in the event of any
    577 * failure, or returns 0 upon success.
    578 */
    579int omap_device_deassert_hardreset(struct platform_device *pdev,
    580				   const char *name)
    581{
    582	struct omap_device *od = to_omap_device(pdev);
    583	int ret = 0;
    584	int i;
    585
    586	for (i = 0; i < od->hwmods_cnt; i++) {
    587		ret = omap_hwmod_deassert_hardreset(od->hwmods[i], name);
    588		if (ret)
    589			break;
    590	}
    591
    592	return ret;
    593}
    594
    595/**
    596 * omap_device_get_by_hwmod_name() - convert a hwmod name to
    597 * device pointer.
    598 * @oh_name: name of the hwmod device
    599 *
    600 * Returns back a struct device * pointer associated with a hwmod
    601 * device represented by a hwmod_name
    602 */
    603struct device *omap_device_get_by_hwmod_name(const char *oh_name)
    604{
    605	struct omap_hwmod *oh;
    606
    607	if (!oh_name) {
    608		WARN(1, "%s: no hwmod name!\n", __func__);
    609		return ERR_PTR(-EINVAL);
    610	}
    611
    612	oh = omap_hwmod_lookup(oh_name);
    613	if (!oh) {
    614		WARN(1, "%s: no hwmod for %s\n", __func__,
    615			oh_name);
    616		return ERR_PTR(-ENODEV);
    617	}
    618	if (!oh->od) {
    619		WARN(1, "%s: no omap_device for %s\n", __func__,
    620			oh_name);
    621		return ERR_PTR(-ENODEV);
    622	}
    623
    624	return &oh->od->pdev->dev;
    625}
    626
    627static struct notifier_block platform_nb = {
    628	.notifier_call = _omap_device_notifier_call,
    629};
    630
    631static int __init omap_device_init(void)
    632{
    633	bus_register_notifier(&platform_bus_type, &platform_nb);
    634	return 0;
    635}
    636omap_postcore_initcall(omap_device_init);
    637
    638/**
    639 * omap_device_late_idle - idle devices without drivers
    640 * @dev: struct device * associated with omap_device
    641 * @data: unused
    642 *
    643 * Check the driver bound status of this device, and idle it
    644 * if there is no driver attached.
    645 */
    646static int __init omap_device_late_idle(struct device *dev, void *data)
    647{
    648	struct platform_device *pdev = to_platform_device(dev);
    649	struct omap_device *od = to_omap_device(pdev);
    650	int i;
    651
    652	if (!od)
    653		return 0;
    654
    655	/*
    656	 * If omap_device state is enabled, but has no driver bound,
    657	 * idle it.
    658	 */
    659
    660	/*
    661	 * Some devices (like memory controllers) are always kept
    662	 * enabled, and should not be idled even with no drivers.
    663	 */
    664	for (i = 0; i < od->hwmods_cnt; i++)
    665		if (od->hwmods[i]->flags & HWMOD_INIT_NO_IDLE)
    666			return 0;
    667
    668	if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER &&
    669	    od->_driver_status != BUS_NOTIFY_BIND_DRIVER) {
    670		if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
    671			dev_warn(dev, "%s: enabled but no driver.  Idling\n",
    672				 __func__);
    673			omap_device_idle(pdev);
    674		}
    675	}
    676
    677	return 0;
    678}
    679
    680static int __init omap_device_late_init(void)
    681{
    682	bus_for_each_dev(&platform_bus_type, NULL, NULL, omap_device_late_idle);
    683
    684	return 0;
    685}
    686omap_late_initcall_sync(omap_device_late_init);