linux/drivers/clk/renesas/renesas-cpg-mssr.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Renesas Clock Pulse Generator / Module Standby and Software Reset
 *
 * Copyright (C) 2015 Glider bvba
 *
 * Based on clk-mstp.c, clk-rcar-gen2.c, and clk-rcar-gen3.c
 *
 * Copyright (C) 2013 Ideas On Board SPRL
 * Copyright (C) 2015 Renesas Electronics Corp.
 */

#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clk/renesas.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/pm_clock.h>
#include <linux/pm_domain.h>
#include <linux/psci.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>

#include <dt-bindings/clock/renesas-cpg-mssr.h>

#include "renesas-cpg-mssr.h"
#include "clk-div6.h"

#ifdef DEBUG
#define WARN_DEBUG
#else
#define WARN_DEBUG(x)
#endif


/*
 * Module Standby and Software Reset register offets.
 *
 * If the registers exist, these are valid for SH-Mobile, R-Mobile,
 * R-Car Gen2, R-Car Gen3, and RZ/G1.
 * These are NOT valid for R-Car Gen1 and RZ/A1!
 */

/*
 * Module Stop Status Register offsets
 */

static const u16 mstpsr[] =;

static const u16 mstpsr_for_gen4[] =;

/*
 * System Module Stop Control Register offsets
 */

static const u16 smstpcr[] =;

static const u16 mstpcr_for_gen4[] =;

/*
 * Standby Control Register offsets (RZ/A)
 * Base address is FRQCR register
 */

static const u16 stbcr[] =;

/*
 * Software Reset Register offsets
 */

static const u16 srcr[] =;

static const u16 srcr_for_gen4[] =;

/*
 * Software Reset Clearing Register offsets
 */

static const u16 srstclr[] =;

static const u16 srstclr_for_gen4[] =;

/**
 * struct cpg_mssr_priv - Clock Pulse Generator / Module Standby
 *                        and Software Reset Private Data
 *
 * @rcdev: Optional reset controller entity
 * @dev: CPG/MSSR device
 * @base: CPG/MSSR register block base address
 * @reg_layout: CPG/MSSR register layout
 * @rmw_lock: protects RMW register accesses
 * @np: Device node in DT for this CPG/MSSR module
 * @num_core_clks: Number of Core Clocks in clks[]
 * @num_mod_clks: Number of Module Clocks in clks[]
 * @last_dt_core_clk: ID of the last Core Clock exported to DT
 * @notifiers: Notifier chain to save/restore clock state for system resume
 * @status_regs: Pointer to status registers array
 * @control_regs: Pointer to control registers array
 * @reset_regs: Pointer to reset registers array
 * @reset_clear_regs:  Pointer to reset clearing registers array
 * @smstpcr_saved: [].mask: Mask of SMSTPCR[] bits under our control
 *                 [].val: Saved values of SMSTPCR[]
 * @reserved_ids: Temporary used, reserved id list
 * @num_reserved_ids: Temporary used, number of reserved id list
 * @clks: Array containing all Core and Module Clocks
 */
struct cpg_mssr_priv {};

static struct cpg_mssr_priv *cpg_mssr_priv;

/**
 * struct mstp_clock - MSTP gating clock
 * @hw: handle between common and hardware-specific interfaces
 * @index: MSTP clock number
 * @priv: CPG/MSSR private data
 */
struct mstp_clock {};

#define to_mstp_clock(_hw)

static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
{}

static int cpg_mstp_clock_enable(struct clk_hw *hw)
{}

static void cpg_mstp_clock_disable(struct clk_hw *hw)
{}

static int cpg_mstp_clock_is_enabled(struct clk_hw *hw)
{}

static const struct clk_ops cpg_mstp_clock_ops =;

static
struct clk *cpg_mssr_clk_src_twocell_get(struct of_phandle_args *clkspec,
					 void *data)
{}

static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core,
					      const struct cpg_mssr_info *info,
					      struct cpg_mssr_priv *priv)
{}

static void __init cpg_mssr_register_mod_clk(const struct mssr_mod_clk *mod,
					     const struct cpg_mssr_info *info,
					     struct cpg_mssr_priv *priv)
{}

struct cpg_mssr_clk_domain {};

static struct cpg_mssr_clk_domain *cpg_mssr_clk_domain;

static bool cpg_mssr_is_pm_clk(const struct of_phandle_args *clkspec,
			       struct cpg_mssr_clk_domain *pd)
{}

int cpg_mssr_attach_dev(struct generic_pm_domain *unused, struct device *dev)
{}

void cpg_mssr_detach_dev(struct generic_pm_domain *unused, struct device *dev)
{}

static void cpg_mssr_genpd_remove(void *data)
{}

static int __init cpg_mssr_add_clk_domain(struct device *dev,
					  const unsigned int *core_pm_clks,
					  unsigned int num_core_pm_clks)
{}

#ifdef CONFIG_RESET_CONTROLLER

#define rcdev_to_priv(x)

static int cpg_mssr_reset(struct reset_controller_dev *rcdev,
			  unsigned long id)
{}

static int cpg_mssr_assert(struct reset_controller_dev *rcdev, unsigned long id)
{}

static int cpg_mssr_deassert(struct reset_controller_dev *rcdev,
			     unsigned long id)
{}

static int cpg_mssr_status(struct reset_controller_dev *rcdev,
			   unsigned long id)
{}

static const struct reset_control_ops cpg_mssr_reset_ops =;

static int cpg_mssr_reset_xlate(struct reset_controller_dev *rcdev,
				const struct of_phandle_args *reset_spec)
{}

static int cpg_mssr_reset_controller_register(struct cpg_mssr_priv *priv)
{}

#else /* !CONFIG_RESET_CONTROLLER */
static inline int cpg_mssr_reset_controller_register(struct cpg_mssr_priv *priv)
{
	return 0;
}
#endif /* !CONFIG_RESET_CONTROLLER */


static const struct of_device_id cpg_mssr_match[] =;

static void cpg_mssr_del_clk_provider(void *data)
{}

#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM_PSCI_FW)
static int cpg_mssr_suspend_noirq(struct device *dev)
{
	struct cpg_mssr_priv *priv = dev_get_drvdata(dev);
	unsigned int reg;

	/* This is the best we can do to check for the presence of PSCI */
	if (!psci_ops.cpu_suspend)
		return 0;

	/* Save module registers with bits under our control */
	for (reg = 0; reg < ARRAY_SIZE(priv->smstpcr_saved); reg++) {
		if (priv->smstpcr_saved[reg].mask)
			priv->smstpcr_saved[reg].val =
				priv->reg_layout == CLK_REG_LAYOUT_RZ_A ?
				readb(priv->base + priv->control_regs[reg]) :
				readl(priv->base + priv->control_regs[reg]);
	}

	/* Save core clocks */
	raw_notifier_call_chain(&priv->notifiers, PM_EVENT_SUSPEND, NULL);

	return 0;
}

static int cpg_mssr_resume_noirq(struct device *dev)
{
	struct cpg_mssr_priv *priv = dev_get_drvdata(dev);
	unsigned int reg;
	u32 mask, oldval, newval;
	int error;

	/* This is the best we can do to check for the presence of PSCI */
	if (!psci_ops.cpu_suspend)
		return 0;

	/* Restore core clocks */
	raw_notifier_call_chain(&priv->notifiers, PM_EVENT_RESUME, NULL);

	/* Restore module clocks */
	for (reg = 0; reg < ARRAY_SIZE(priv->smstpcr_saved); reg++) {
		mask = priv->smstpcr_saved[reg].mask;
		if (!mask)
			continue;

		if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A)
			oldval = readb(priv->base + priv->control_regs[reg]);
		else
			oldval = readl(priv->base + priv->control_regs[reg]);
		newval = oldval & ~mask;
		newval |= priv->smstpcr_saved[reg].val & mask;
		if (newval == oldval)
			continue;

		if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) {
			writeb(newval, priv->base + priv->control_regs[reg]);
			/* dummy read to ensure write has completed */
			readb(priv->base + priv->control_regs[reg]);
			barrier_data(priv->base + priv->control_regs[reg]);
			continue;
		} else
			writel(newval, priv->base + priv->control_regs[reg]);

		/* Wait until enabled clocks are really enabled */
		mask &= ~priv->smstpcr_saved[reg].val;
		if (!mask)
			continue;

		error = readl_poll_timeout_atomic(priv->base + priv->status_regs[reg],
						oldval, !(oldval & mask), 0, 10);
		if (error)
			dev_warn(dev, "Failed to enable SMSTP%u[0x%x]\n", reg,
				 oldval & mask);
	}

	return 0;
}

static const struct dev_pm_ops cpg_mssr_pm = {
	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(cpg_mssr_suspend_noirq,
				      cpg_mssr_resume_noirq)
};
#define DEV_PM_OPS
#else
#define DEV_PM_OPS
#endif /* CONFIG_PM_SLEEP && CONFIG_ARM_PSCI_FW */

static void __init cpg_mssr_reserved_exit(struct cpg_mssr_priv *priv)
{}

static int __init cpg_mssr_reserved_init(struct cpg_mssr_priv *priv,
					 const struct cpg_mssr_info *info)
{}

static int __init cpg_mssr_common_init(struct device *dev,
				       struct device_node *np,
				       const struct cpg_mssr_info *info)
{}

void __init cpg_mssr_early_init(struct device_node *np,
				const struct cpg_mssr_info *info)
{}

static int __init cpg_mssr_probe(struct platform_device *pdev)
{}

static struct platform_driver cpg_mssr_driver =;

static int __init cpg_mssr_init(void)
{}

subsys_initcall(cpg_mssr_init);

void __init mssr_mod_nullify(struct mssr_mod_clk *mod_clks,
			     unsigned int num_mod_clks,
			     const unsigned int *clks, unsigned int n)
{}

MODULE_DESCRIPTION();