linux/drivers/pmdomain/imx/scu-pd.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2016 Freescale Semiconductor, Inc.
 * Copyright 2017-2018 NXP
 *	Dong Aisheng <[email protected]>
 *
 * Implementation of the SCU based Power Domains
 *
 * NOTE: a better implementation suggested by Ulf Hansson is using a
 * single global power domain and implement the ->attach|detach_dev()
 * callback for the genpd and use the regular of_genpd_add_provider_simple().
 * From within the ->attach_dev(), we could get the OF node for
 * the device that is being attached and then parse the power-domain
 * cell containing the "resource id" and store that in the per device
 * struct generic_pm_domain_data (we have void pointer there for
 * storing these kind of things).
 *
 * Additionally, we need to implement the ->stop() and ->start()
 * callbacks of genpd, which is where you "power on/off" devices,
 * rather than using the above ->power_on|off() callbacks.
 *
 * However, there're two known issues:
 * 1. The ->attach_dev() of power domain infrastructure still does
 *    not support multi domains case as the struct device *dev passed
 *    in is a virtual PD device, it does not help for parsing the real
 *    device resource id from device tree, so it's unware of which
 *    real sub power domain of device should be attached.
 *
 *    The framework needs some proper extension to support multi power
 *    domain cases.
 *
 *    Update: Genpd assigns the ->of_node for the virtual device before it
 *    invokes ->attach_dev() callback, hence parsing for device resources via
 *    DT should work fine.
 *
 * 2. It also breaks most of current drivers as the driver probe sequence
 *    behavior changed if removing ->power_on|off() callback and use
 *    ->start() and ->stop() instead. genpd_dev_pm_attach will only power
 *    up the domain and attach device, but will not call .start() which
 *    relies on device runtime pm. That means the device power is still
 *    not up before running driver probe function. For SCU enabled
 *    platforms, all device drivers accessing registers/clock without power
 *    domain enabled will trigger a HW access error. That means we need fix
 *    most drivers probe sequence with proper runtime pm.
 *
 *    Update: Runtime PM support isn't necessary. Instead, this can easily be
 *    fixed in drivers by adding a call to dev_pm_domain_start() during probe.
 *
 * In summary, the second part needs to be addressed via minor updates to the
 * relevant drivers, before the "single global power domain" model can be used.
 *
 */

#include <dt-bindings/firmware/imx/rsrc.h>
#include <linux/console.h>
#include <linux/firmware/imx/sci.h>
#include <linux/firmware/imx/svc/rm.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_domain.h>
#include <linux/slab.h>

/* SCU Power Mode Protocol definition */
struct imx_sc_msg_req_set_resource_power_mode {} __packed __aligned();

struct req_get_resource_mode {};

struct resp_get_resource_mode {};

struct imx_sc_msg_req_get_resource_power_mode {} __packed __aligned();

#define IMX_SCU_PD_NAME_SIZE
struct imx_sc_pm_domain {};

struct imx_sc_pd_range {};

struct imx_sc_pd_soc {};

static int imx_con_rsrc;

/* Align with the IMX_SC_PM_PW_MODE_[OFF,STBY,LP,ON] macros */
static const char * const imx_sc_pm_mode[] =;

static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] =;

static const struct imx_sc_pd_soc imx8qxp_scu_pd =;

static struct imx_sc_ipc *pm_ipc_handle;

static inline struct imx_sc_pm_domain *
to_imx_sc_pd(struct generic_pm_domain *genpd)
{}

static void imx_sc_pd_get_console_rsrc(void)
{}

static int imx_sc_get_pd_power(struct device *dev, u32 rsrc)
{}

static int imx_sc_pd_power(struct generic_pm_domain *domain, bool power_on)
{}

static int imx_sc_pd_power_on(struct generic_pm_domain *domain)
{}

static int imx_sc_pd_power_off(struct generic_pm_domain *domain)
{}

static struct generic_pm_domain *imx_scu_pd_xlate(const struct of_phandle_args *spec,
						  void *data)
{}

static struct imx_sc_pm_domain *
imx_scu_add_pm_domain(struct device *dev, int idx,
		      const struct imx_sc_pd_range *pd_ranges)
{}

static int imx_scu_init_pm_domains(struct device *dev,
				    const struct imx_sc_pd_soc *pd_soc)
{}

static int imx_sc_pd_probe(struct platform_device *pdev)
{}

static const struct of_device_id imx_sc_pd_match[] =;

static struct platform_driver imx_sc_pd_driver =;
builtin_platform_driver();

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();