2018-09-07 09:04:19 +07:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2014-01-15 14:43:08 +07:00
|
|
|
/*
|
|
|
|
* R-Car SYSC Power management support
|
|
|
|
*
|
|
|
|
* Copyright (C) 2014 Magnus Damm
|
2017-03-31 16:01:55 +07:00
|
|
|
* Copyright (C) 2015-2017 Glider bvba
|
2014-01-15 14:43:08 +07:00
|
|
|
*/
|
|
|
|
|
2016-04-20 19:02:40 +07:00
|
|
|
#include <linux/clk/renesas.h>
|
2014-01-15 14:43:08 +07:00
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/err.h>
|
|
|
|
#include <linux/mm.h>
|
2016-04-20 19:02:38 +07:00
|
|
|
#include <linux/of_address.h>
|
|
|
|
#include <linux/pm_domain.h>
|
|
|
|
#include <linux/slab.h>
|
2014-01-15 14:43:08 +07:00
|
|
|
#include <linux/spinlock.h>
|
2015-08-11 10:07:05 +07:00
|
|
|
#include <linux/io.h>
|
2016-04-20 19:02:36 +07:00
|
|
|
#include <linux/soc/renesas/rcar-sysc.h>
|
2014-01-15 14:43:08 +07:00
|
|
|
|
2016-04-20 19:02:38 +07:00
|
|
|
#include "rcar-sysc.h"
|
|
|
|
|
2015-06-05 01:22:27 +07:00
|
|
|
/* SYSC Common */
|
|
|
|
#define SYSCSR 0x00 /* SYSC Status Register */
|
|
|
|
#define SYSCISR 0x04 /* Interrupt Status Register */
|
|
|
|
#define SYSCISCR 0x08 /* Interrupt Status Clear Register */
|
|
|
|
#define SYSCIER 0x0c /* Interrupt Enable Register */
|
|
|
|
#define SYSCIMR 0x10 /* Interrupt Mask Register */
|
2014-01-15 14:43:08 +07:00
|
|
|
|
2015-06-05 01:22:27 +07:00
|
|
|
/* SYSC Status Register */
|
|
|
|
#define SYSCSR_PONENB 1 /* Ready for power resume requests */
|
|
|
|
#define SYSCSR_POFFENB 0 /* Ready for power shutoff requests */
|
2014-01-15 14:43:08 +07:00
|
|
|
|
2015-06-05 01:22:27 +07:00
|
|
|
/*
|
|
|
|
* Power Control Register Offsets inside the register block for each domain
|
|
|
|
* Note: The "CR" registers for ARM cores exist on H1 only
|
2016-04-20 19:02:38 +07:00
|
|
|
* Use WFI to power off, CPG/APMU to resume ARM cores on R-Car Gen2
|
|
|
|
* Use PSCI on R-Car Gen3
|
2015-06-05 01:22:27 +07:00
|
|
|
*/
|
|
|
|
#define PWRSR_OFFS 0x00 /* Power Status Register */
|
|
|
|
#define PWROFFCR_OFFS 0x04 /* Power Shutoff Control Register */
|
|
|
|
#define PWROFFSR_OFFS 0x08 /* Power Shutoff Status Register */
|
|
|
|
#define PWRONCR_OFFS 0x0c /* Power Resume Control Register */
|
|
|
|
#define PWRONSR_OFFS 0x10 /* Power Resume Status Register */
|
|
|
|
#define PWRER_OFFS 0x14 /* Power Shutoff/Resume Error */
|
|
|
|
|
|
|
|
|
|
|
|
#define SYSCSR_RETRIES 100
|
|
|
|
#define SYSCSR_DELAY_US 1
|
2014-01-15 14:43:08 +07:00
|
|
|
|
2015-06-05 01:22:29 +07:00
|
|
|
#define PWRER_RETRIES 100
|
|
|
|
#define PWRER_DELAY_US 1
|
|
|
|
|
2015-06-05 01:22:27 +07:00
|
|
|
#define SYSCISR_RETRIES 1000
|
|
|
|
#define SYSCISR_DELAY_US 1
|
2014-01-15 14:43:08 +07:00
|
|
|
|
2016-04-20 19:02:38 +07:00
|
|
|
#define RCAR_PD_ALWAYS_ON 32 /* Always-on power area */
|
|
|
|
|
2018-05-30 22:25:16 +07:00
|
|
|
struct rcar_sysc_ch {
|
|
|
|
u16 chan_offs;
|
|
|
|
u8 chan_bit;
|
|
|
|
u8 isr_bit;
|
|
|
|
};
|
|
|
|
|
2014-02-24 12:52:12 +07:00
|
|
|
static void __iomem *rcar_sysc_base;
|
2014-01-15 14:43:08 +07:00
|
|
|
static DEFINE_SPINLOCK(rcar_sysc_lock); /* SMP CPUs + I/O devices */
|
2019-08-28 18:36:12 +07:00
|
|
|
static u32 rcar_sysc_extmask_offs, rcar_sysc_extmask_val;
|
2014-01-15 14:43:08 +07:00
|
|
|
|
2015-06-05 01:22:32 +07:00
|
|
|
static int rcar_sysc_pwr_on_off(const struct rcar_sysc_ch *sysc_ch, bool on)
|
2014-01-15 14:43:08 +07:00
|
|
|
{
|
2015-06-05 01:22:32 +07:00
|
|
|
unsigned int sr_bit, reg_offs;
|
2014-01-15 14:43:08 +07:00
|
|
|
int k;
|
|
|
|
|
2015-06-05 01:22:32 +07:00
|
|
|
if (on) {
|
|
|
|
sr_bit = SYSCSR_PONENB;
|
|
|
|
reg_offs = PWRONCR_OFFS;
|
|
|
|
} else {
|
|
|
|
sr_bit = SYSCSR_POFFENB;
|
|
|
|
reg_offs = PWROFFCR_OFFS;
|
|
|
|
}
|
|
|
|
|
2015-06-05 01:22:27 +07:00
|
|
|
/* Wait until SYSC is ready to accept a power request */
|
2014-01-15 14:43:08 +07:00
|
|
|
for (k = 0; k < SYSCSR_RETRIES; k++) {
|
2015-06-05 01:22:31 +07:00
|
|
|
if (ioread32(rcar_sysc_base + SYSCSR) & BIT(sr_bit))
|
2014-01-15 14:43:08 +07:00
|
|
|
break;
|
|
|
|
udelay(SYSCSR_DELAY_US);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (k == SYSCSR_RETRIES)
|
|
|
|
return -EAGAIN;
|
|
|
|
|
2015-06-05 01:22:27 +07:00
|
|
|
/* Submit power shutoff or power resume request */
|
2015-06-05 01:22:31 +07:00
|
|
|
iowrite32(BIT(sysc_ch->chan_bit),
|
2014-01-15 14:43:08 +07:00
|
|
|
rcar_sysc_base + sysc_ch->chan_offs + reg_offs);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-05 01:22:32 +07:00
|
|
|
static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on)
|
2014-01-15 14:43:08 +07:00
|
|
|
{
|
2015-06-05 01:22:31 +07:00
|
|
|
unsigned int isr_mask = BIT(sysc_ch->isr_bit);
|
|
|
|
unsigned int chan_mask = BIT(sysc_ch->chan_bit);
|
2014-01-15 14:43:08 +07:00
|
|
|
unsigned int status;
|
|
|
|
unsigned long flags;
|
|
|
|
int ret = 0;
|
|
|
|
int k;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&rcar_sysc_lock, flags);
|
|
|
|
|
2019-08-28 18:36:12 +07:00
|
|
|
/*
|
|
|
|
* Mask external power requests for CPU or 3DG domains
|
|
|
|
*/
|
|
|
|
if (rcar_sysc_extmask_val) {
|
|
|
|
iowrite32(rcar_sysc_extmask_val,
|
|
|
|
rcar_sysc_base + rcar_sysc_extmask_offs);
|
|
|
|
}
|
|
|
|
|
soc: renesas: rcar-sysc: Fix power domain control after system resume
To control power to a power domain, the System Controller (SYSC) needs
the corresponding interrupt source to be enabled, but masked, to prevent
the CPU from receiving it.
Currently this is handled in the driver's probe() routine, and set up
for every domain present, even if it will not be controlled directly by
SYSC (CPU domains are powered through the APMU on R-Car Gen2 and later).
On R-Car Gen3, PSCI powers down the SoC during system suspend, thus
losing any configured interrupt state. Hence after system resume, power
domains not controlled through the APMU (e.g. A3IR, A3VC, A3VP) fail to
power up.
Fix this by replacing the global interrupt setup in the probe() routine
by a domain-specific interrupt setup in rcar_sysc_power(), where the
domain's power is actually controlled. This brings the code more in
line with the flowchart in the Hardware User's Manual.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
2018-12-05 22:39:45 +07:00
|
|
|
/*
|
|
|
|
* The interrupt source needs to be enabled, but masked, to prevent the
|
|
|
|
* CPU from receiving it.
|
|
|
|
*/
|
|
|
|
iowrite32(ioread32(rcar_sysc_base + SYSCIMR) | isr_mask,
|
|
|
|
rcar_sysc_base + SYSCIMR);
|
|
|
|
iowrite32(ioread32(rcar_sysc_base + SYSCIER) | isr_mask,
|
|
|
|
rcar_sysc_base + SYSCIER);
|
|
|
|
|
2014-01-15 14:43:08 +07:00
|
|
|
iowrite32(isr_mask, rcar_sysc_base + SYSCISCR);
|
|
|
|
|
2015-06-05 01:22:27 +07:00
|
|
|
/* Submit power shutoff or resume request until it was accepted */
|
2015-06-05 01:22:29 +07:00
|
|
|
for (k = 0; k < PWRER_RETRIES; k++) {
|
2015-06-05 01:22:32 +07:00
|
|
|
ret = rcar_sysc_pwr_on_off(sysc_ch, on);
|
2014-01-15 14:43:08 +07:00
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
status = ioread32(rcar_sysc_base +
|
|
|
|
sysc_ch->chan_offs + PWRER_OFFS);
|
2015-06-05 01:22:29 +07:00
|
|
|
if (!(status & chan_mask))
|
|
|
|
break;
|
|
|
|
|
|
|
|
udelay(PWRER_DELAY_US);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (k == PWRER_RETRIES) {
|
|
|
|
ret = -EIO;
|
|
|
|
goto out;
|
|
|
|
}
|
2014-01-15 14:43:08 +07:00
|
|
|
|
2015-06-05 01:22:27 +07:00
|
|
|
/* Wait until the power shutoff or resume request has completed * */
|
2014-01-15 14:43:08 +07:00
|
|
|
for (k = 0; k < SYSCISR_RETRIES; k++) {
|
|
|
|
if (ioread32(rcar_sysc_base + SYSCISR) & isr_mask)
|
|
|
|
break;
|
|
|
|
udelay(SYSCISR_DELAY_US);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (k == SYSCISR_RETRIES)
|
|
|
|
ret = -EIO;
|
|
|
|
|
|
|
|
iowrite32(isr_mask, rcar_sysc_base + SYSCISCR);
|
|
|
|
|
|
|
|
out:
|
2019-08-28 18:36:12 +07:00
|
|
|
if (rcar_sysc_extmask_val)
|
|
|
|
iowrite32(0, rcar_sysc_base + rcar_sysc_extmask_offs);
|
|
|
|
|
2014-01-15 14:43:08 +07:00
|
|
|
spin_unlock_irqrestore(&rcar_sysc_lock, flags);
|
|
|
|
|
2016-04-20 19:02:37 +07:00
|
|
|
pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off",
|
2014-01-15 14:43:08 +07:00
|
|
|
sysc_ch->isr_bit, ioread32(rcar_sysc_base + SYSCISR), ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-04-20 19:02:39 +07:00
|
|
|
static bool rcar_sysc_power_is_off(const struct rcar_sysc_ch *sysc_ch)
|
2014-01-15 14:43:08 +07:00
|
|
|
{
|
|
|
|
unsigned int st;
|
|
|
|
|
|
|
|
st = ioread32(rcar_sysc_base + sysc_ch->chan_offs + PWRSR_OFFS);
|
2015-06-05 01:22:31 +07:00
|
|
|
if (st & BIT(sysc_ch->chan_bit))
|
2014-01-15 14:43:08 +07:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-04-20 19:02:38 +07:00
|
|
|
struct rcar_sysc_pd {
|
|
|
|
struct generic_pm_domain genpd;
|
|
|
|
struct rcar_sysc_ch ch;
|
|
|
|
unsigned int flags;
|
2019-06-17 19:00:56 +07:00
|
|
|
char name[];
|
2016-04-20 19:02:38 +07:00
|
|
|
};
|
|
|
|
|
|
|
|
static inline struct rcar_sysc_pd *to_rcar_pd(struct generic_pm_domain *d)
|
|
|
|
{
|
|
|
|
return container_of(d, struct rcar_sysc_pd, genpd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rcar_sysc_pd_power_off(struct generic_pm_domain *genpd)
|
|
|
|
{
|
|
|
|
struct rcar_sysc_pd *pd = to_rcar_pd(genpd);
|
|
|
|
|
|
|
|
pr_debug("%s: %s\n", __func__, genpd->name);
|
2018-12-05 22:39:43 +07:00
|
|
|
return rcar_sysc_power(&pd->ch, false);
|
2016-04-20 19:02:38 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static int rcar_sysc_pd_power_on(struct generic_pm_domain *genpd)
|
|
|
|
{
|
|
|
|
struct rcar_sysc_pd *pd = to_rcar_pd(genpd);
|
|
|
|
|
|
|
|
pr_debug("%s: %s\n", __func__, genpd->name);
|
2018-12-05 22:39:43 +07:00
|
|
|
return rcar_sysc_power(&pd->ch, true);
|
2016-04-20 19:02:38 +07:00
|
|
|
}
|
|
|
|
|
2016-04-20 19:02:40 +07:00
|
|
|
static bool has_cpg_mstp;
|
|
|
|
|
2018-06-05 22:05:15 +07:00
|
|
|
static int __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd)
|
2016-04-20 19:02:38 +07:00
|
|
|
{
|
|
|
|
struct generic_pm_domain *genpd = &pd->genpd;
|
|
|
|
const char *name = pd->genpd.name;
|
2018-06-05 22:05:15 +07:00
|
|
|
int error;
|
2016-04-20 19:02:38 +07:00
|
|
|
|
|
|
|
if (pd->flags & PD_CPU) {
|
|
|
|
/*
|
|
|
|
* This domain contains a CPU core and therefore it should
|
|
|
|
* only be turned off if the CPU is not in use.
|
|
|
|
*/
|
|
|
|
pr_debug("PM domain %s contains %s\n", name, "CPU");
|
2017-06-12 16:23:45 +07:00
|
|
|
genpd->flags |= GENPD_FLAG_ALWAYS_ON;
|
2016-04-20 19:02:38 +07:00
|
|
|
} else if (pd->flags & PD_SCU) {
|
|
|
|
/*
|
|
|
|
* This domain contains an SCU and cache-controller, and
|
|
|
|
* therefore it should only be turned off if the CPU cores are
|
|
|
|
* not in use.
|
|
|
|
*/
|
|
|
|
pr_debug("PM domain %s contains %s\n", name, "SCU");
|
2017-06-12 16:23:45 +07:00
|
|
|
genpd->flags |= GENPD_FLAG_ALWAYS_ON;
|
2016-04-20 19:02:38 +07:00
|
|
|
} else if (pd->flags & PD_NO_CR) {
|
|
|
|
/*
|
|
|
|
* This domain cannot be turned off.
|
|
|
|
*/
|
2017-06-12 16:23:45 +07:00
|
|
|
genpd->flags |= GENPD_FLAG_ALWAYS_ON;
|
2016-04-20 19:02:38 +07:00
|
|
|
}
|
|
|
|
|
2016-04-20 19:02:40 +07:00
|
|
|
if (!(pd->flags & (PD_CPU | PD_SCU))) {
|
|
|
|
/* Enable Clock Domain for I/O devices */
|
2017-11-09 20:27:02 +07:00
|
|
|
genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
|
2016-04-20 19:02:40 +07:00
|
|
|
if (has_cpg_mstp) {
|
|
|
|
genpd->attach_dev = cpg_mstp_attach_dev;
|
|
|
|
genpd->detach_dev = cpg_mstp_detach_dev;
|
|
|
|
} else {
|
|
|
|
genpd->attach_dev = cpg_mssr_attach_dev;
|
|
|
|
genpd->detach_dev = cpg_mssr_detach_dev;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-20 19:02:38 +07:00
|
|
|
genpd->power_off = rcar_sysc_pd_power_off;
|
|
|
|
genpd->power_on = rcar_sysc_pd_power_on;
|
|
|
|
|
|
|
|
if (pd->flags & (PD_CPU | PD_NO_CR)) {
|
|
|
|
/* Skip CPUs (handled by SMP code) and areas without control */
|
|
|
|
pr_debug("%s: Not touching %s\n", __func__, genpd->name);
|
|
|
|
goto finalize;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!rcar_sysc_power_is_off(&pd->ch)) {
|
|
|
|
pr_debug("%s: %s is already powered\n", __func__, genpd->name);
|
|
|
|
goto finalize;
|
|
|
|
}
|
|
|
|
|
2018-12-05 22:39:43 +07:00
|
|
|
rcar_sysc_power(&pd->ch, true);
|
2016-04-20 19:02:38 +07:00
|
|
|
|
|
|
|
finalize:
|
2019-08-09 21:14:32 +07:00
|
|
|
error = pm_genpd_init(genpd, &simple_qos_governor, false);
|
2018-06-05 22:05:15 +07:00
|
|
|
if (error)
|
|
|
|
pr_err("Failed to init PM domain %s: %d\n", name, error);
|
|
|
|
|
|
|
|
return error;
|
2016-04-20 19:02:38 +07:00
|
|
|
}
|
|
|
|
|
2017-12-19 22:54:44 +07:00
|
|
|
static const struct of_device_id rcar_sysc_matches[] __initconst = {
|
soc: renesas: Rework Kconfig and Makefile logic
The goals are to:
- Allow precise control over and automatic selection of which
(sub)drivers are used for which SoC,
- Allow adding support for new SoCs easily,
- Allow compile-testing of all (sub)drivers,
- Keep driver selection logic in the subsystem-specific Kconfig,
independent from the architecture-specific Kconfig (i.e. no "select"
from arch/arm64/Kconfig.platforms), to avoid dependencies.
This is implemented by:
- Introducing Kconfig symbols for all drivers and sub-drivers,
- Introducing the Kconfig symbol SOC_RENESAS, which is enabled
automatically when building for a Renesas ARM platform, and which
enables all required drivers without interaction of the user, based
on SoC-specific ARCH_* symbols,
- Allowing the user to enable any Kconfig symbol manually if
COMPILE_TEST is enabled,
- Using the new Kconfig symbols instead of the ARCH_* symbols to
control compilation in the Makefile,
- Always entering drivers/soc/renesas/ during the build.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
2017-05-19 15:35:10 +07:00
|
|
|
#ifdef CONFIG_SYSC_R8A7743
|
2016-10-06 04:35:01 +07:00
|
|
|
{ .compatible = "renesas,r8a7743-sysc", .data = &r8a7743_sysc_info },
|
2018-09-11 17:12:44 +07:00
|
|
|
/* RZ/G1N is identical to RZ/G2M w.r.t. power domains. */
|
|
|
|
{ .compatible = "renesas,r8a7744-sysc", .data = &r8a7743_sysc_info },
|
2016-10-06 04:35:01 +07:00
|
|
|
#endif
|
soc: renesas: Rework Kconfig and Makefile logic
The goals are to:
- Allow precise control over and automatic selection of which
(sub)drivers are used for which SoC,
- Allow adding support for new SoCs easily,
- Allow compile-testing of all (sub)drivers,
- Keep driver selection logic in the subsystem-specific Kconfig,
independent from the architecture-specific Kconfig (i.e. no "select"
from arch/arm64/Kconfig.platforms), to avoid dependencies.
This is implemented by:
- Introducing Kconfig symbols for all drivers and sub-drivers,
- Introducing the Kconfig symbol SOC_RENESAS, which is enabled
automatically when building for a Renesas ARM platform, and which
enables all required drivers without interaction of the user, based
on SoC-specific ARCH_* symbols,
- Allowing the user to enable any Kconfig symbol manually if
COMPILE_TEST is enabled,
- Using the new Kconfig symbols instead of the ARCH_* symbols to
control compilation in the Makefile,
- Always entering drivers/soc/renesas/ during the build.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
2017-05-19 15:35:10 +07:00
|
|
|
#ifdef CONFIG_SYSC_R8A7745
|
2016-11-05 04:46:13 +07:00
|
|
|
{ .compatible = "renesas,r8a7745-sysc", .data = &r8a7745_sysc_info },
|
|
|
|
#endif
|
2018-03-29 02:26:09 +07:00
|
|
|
#ifdef CONFIG_SYSC_R8A77470
|
|
|
|
{ .compatible = "renesas,r8a77470-sysc", .data = &r8a77470_sysc_info },
|
|
|
|
#endif
|
2018-08-02 21:53:19 +07:00
|
|
|
#ifdef CONFIG_SYSC_R8A774A1
|
|
|
|
{ .compatible = "renesas,r8a774a1-sysc", .data = &r8a774a1_sysc_info },
|
|
|
|
#endif
|
2019-09-23 14:29:40 +07:00
|
|
|
#ifdef CONFIG_SYSC_R8A774B1
|
|
|
|
{ .compatible = "renesas,r8a774b1-sysc", .data = &r8a774b1_sysc_info },
|
|
|
|
#endif
|
2018-09-10 21:41:27 +07:00
|
|
|
#ifdef CONFIG_SYSC_R8A774C0
|
|
|
|
{ .compatible = "renesas,r8a774c0-sysc", .data = &r8a774c0_sysc_info },
|
|
|
|
#endif
|
soc: renesas: Rework Kconfig and Makefile logic
The goals are to:
- Allow precise control over and automatic selection of which
(sub)drivers are used for which SoC,
- Allow adding support for new SoCs easily,
- Allow compile-testing of all (sub)drivers,
- Keep driver selection logic in the subsystem-specific Kconfig,
independent from the architecture-specific Kconfig (i.e. no "select"
from arch/arm64/Kconfig.platforms), to avoid dependencies.
This is implemented by:
- Introducing Kconfig symbols for all drivers and sub-drivers,
- Introducing the Kconfig symbol SOC_RENESAS, which is enabled
automatically when building for a Renesas ARM platform, and which
enables all required drivers without interaction of the user, based
on SoC-specific ARCH_* symbols,
- Allowing the user to enable any Kconfig symbol manually if
COMPILE_TEST is enabled,
- Using the new Kconfig symbols instead of the ARCH_* symbols to
control compilation in the Makefile,
- Always entering drivers/soc/renesas/ during the build.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
2017-05-19 15:35:10 +07:00
|
|
|
#ifdef CONFIG_SYSC_R8A7779
|
2016-04-20 19:02:41 +07:00
|
|
|
{ .compatible = "renesas,r8a7779-sysc", .data = &r8a7779_sysc_info },
|
2016-04-20 19:02:42 +07:00
|
|
|
#endif
|
soc: renesas: Rework Kconfig and Makefile logic
The goals are to:
- Allow precise control over and automatic selection of which
(sub)drivers are used for which SoC,
- Allow adding support for new SoCs easily,
- Allow compile-testing of all (sub)drivers,
- Keep driver selection logic in the subsystem-specific Kconfig,
independent from the architecture-specific Kconfig (i.e. no "select"
from arch/arm64/Kconfig.platforms), to avoid dependencies.
This is implemented by:
- Introducing Kconfig symbols for all drivers and sub-drivers,
- Introducing the Kconfig symbol SOC_RENESAS, which is enabled
automatically when building for a Renesas ARM platform, and which
enables all required drivers without interaction of the user, based
on SoC-specific ARCH_* symbols,
- Allowing the user to enable any Kconfig symbol manually if
COMPILE_TEST is enabled,
- Using the new Kconfig symbols instead of the ARCH_* symbols to
control compilation in the Makefile,
- Always entering drivers/soc/renesas/ during the build.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
2017-05-19 15:35:10 +07:00
|
|
|
#ifdef CONFIG_SYSC_R8A7790
|
2016-04-20 19:02:42 +07:00
|
|
|
{ .compatible = "renesas,r8a7790-sysc", .data = &r8a7790_sysc_info },
|
2016-04-20 19:02:43 +07:00
|
|
|
#endif
|
soc: renesas: Rework Kconfig and Makefile logic
The goals are to:
- Allow precise control over and automatic selection of which
(sub)drivers are used for which SoC,
- Allow adding support for new SoCs easily,
- Allow compile-testing of all (sub)drivers,
- Keep driver selection logic in the subsystem-specific Kconfig,
independent from the architecture-specific Kconfig (i.e. no "select"
from arch/arm64/Kconfig.platforms), to avoid dependencies.
This is implemented by:
- Introducing Kconfig symbols for all drivers and sub-drivers,
- Introducing the Kconfig symbol SOC_RENESAS, which is enabled
automatically when building for a Renesas ARM platform, and which
enables all required drivers without interaction of the user, based
on SoC-specific ARCH_* symbols,
- Allowing the user to enable any Kconfig symbol manually if
COMPILE_TEST is enabled,
- Using the new Kconfig symbols instead of the ARCH_* symbols to
control compilation in the Makefile,
- Always entering drivers/soc/renesas/ during the build.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
2017-05-19 15:35:10 +07:00
|
|
|
#ifdef CONFIG_SYSC_R8A7791
|
2016-04-20 19:02:43 +07:00
|
|
|
{ .compatible = "renesas,r8a7791-sysc", .data = &r8a7791_sysc_info },
|
2016-04-20 19:02:44 +07:00
|
|
|
/* R-Car M2-N is identical to R-Car M2-W w.r.t. power domains. */
|
|
|
|
{ .compatible = "renesas,r8a7793-sysc", .data = &r8a7791_sysc_info },
|
2016-04-20 19:02:45 +07:00
|
|
|
#endif
|
soc: renesas: Rework Kconfig and Makefile logic
The goals are to:
- Allow precise control over and automatic selection of which
(sub)drivers are used for which SoC,
- Allow adding support for new SoCs easily,
- Allow compile-testing of all (sub)drivers,
- Keep driver selection logic in the subsystem-specific Kconfig,
independent from the architecture-specific Kconfig (i.e. no "select"
from arch/arm64/Kconfig.platforms), to avoid dependencies.
This is implemented by:
- Introducing Kconfig symbols for all drivers and sub-drivers,
- Introducing the Kconfig symbol SOC_RENESAS, which is enabled
automatically when building for a Renesas ARM platform, and which
enables all required drivers without interaction of the user, based
on SoC-specific ARCH_* symbols,
- Allowing the user to enable any Kconfig symbol manually if
COMPILE_TEST is enabled,
- Using the new Kconfig symbols instead of the ARCH_* symbols to
control compilation in the Makefile,
- Always entering drivers/soc/renesas/ during the build.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
2017-05-19 15:35:10 +07:00
|
|
|
#ifdef CONFIG_SYSC_R8A7792
|
|
|
|
{ .compatible = "renesas,r8a7792-sysc", .data = &r8a7792_sysc_info },
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_SYSC_R8A7794
|
2016-04-20 19:02:45 +07:00
|
|
|
{ .compatible = "renesas,r8a7794-sysc", .data = &r8a7794_sysc_info },
|
2016-04-20 19:02:46 +07:00
|
|
|
#endif
|
soc: renesas: Rework Kconfig and Makefile logic
The goals are to:
- Allow precise control over and automatic selection of which
(sub)drivers are used for which SoC,
- Allow adding support for new SoCs easily,
- Allow compile-testing of all (sub)drivers,
- Keep driver selection logic in the subsystem-specific Kconfig,
independent from the architecture-specific Kconfig (i.e. no "select"
from arch/arm64/Kconfig.platforms), to avoid dependencies.
This is implemented by:
- Introducing Kconfig symbols for all drivers and sub-drivers,
- Introducing the Kconfig symbol SOC_RENESAS, which is enabled
automatically when building for a Renesas ARM platform, and which
enables all required drivers without interaction of the user, based
on SoC-specific ARCH_* symbols,
- Allowing the user to enable any Kconfig symbol manually if
COMPILE_TEST is enabled,
- Using the new Kconfig symbols instead of the ARCH_* symbols to
control compilation in the Makefile,
- Always entering drivers/soc/renesas/ during the build.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
2017-05-19 15:35:10 +07:00
|
|
|
#ifdef CONFIG_SYSC_R8A7795
|
2016-04-20 19:02:46 +07:00
|
|
|
{ .compatible = "renesas,r8a7795-sysc", .data = &r8a7795_sysc_info },
|
2016-05-31 00:05:11 +07:00
|
|
|
#endif
|
2019-10-23 19:33:32 +07:00
|
|
|
#ifdef CONFIG_SYSC_R8A77960
|
|
|
|
{ .compatible = "renesas,r8a7796-sysc", .data = &r8a77960_sysc_info },
|
2017-07-20 19:34:53 +07:00
|
|
|
#endif
|
2019-10-23 19:33:37 +07:00
|
|
|
#ifdef CONFIG_SYSC_R8A77961
|
|
|
|
{ .compatible = "renesas,r8a77961-sysc", .data = &r8a77961_sysc_info },
|
|
|
|
#endif
|
2018-02-20 22:12:06 +07:00
|
|
|
#ifdef CONFIG_SYSC_R8A77965
|
|
|
|
{ .compatible = "renesas,r8a77965-sysc", .data = &r8a77965_sysc_info },
|
|
|
|
#endif
|
2017-09-13 03:37:20 +07:00
|
|
|
#ifdef CONFIG_SYSC_R8A77970
|
|
|
|
{ .compatible = "renesas,r8a77970-sysc", .data = &r8a77970_sysc_info },
|
|
|
|
#endif
|
2018-02-17 01:28:02 +07:00
|
|
|
#ifdef CONFIG_SYSC_R8A77980
|
|
|
|
{ .compatible = "renesas,r8a77980-sysc", .data = &r8a77980_sysc_info },
|
|
|
|
#endif
|
2018-05-15 19:07:38 +07:00
|
|
|
#ifdef CONFIG_SYSC_R8A77990
|
|
|
|
{ .compatible = "renesas,r8a77990-sysc", .data = &r8a77990_sysc_info },
|
|
|
|
#endif
|
2017-07-20 19:34:53 +07:00
|
|
|
#ifdef CONFIG_SYSC_R8A77995
|
|
|
|
{ .compatible = "renesas,r8a77995-sysc", .data = &r8a77995_sysc_info },
|
2016-04-20 19:02:41 +07:00
|
|
|
#endif
|
2016-04-20 19:02:38 +07:00
|
|
|
{ /* sentinel */ }
|
|
|
|
};
|
|
|
|
|
|
|
|
struct rcar_pm_domains {
|
|
|
|
struct genpd_onecell_data onecell_data;
|
|
|
|
struct generic_pm_domain *domains[RCAR_PD_ALWAYS_ON + 1];
|
|
|
|
};
|
|
|
|
|
2018-05-30 22:25:13 +07:00
|
|
|
static struct genpd_onecell_data *rcar_sysc_onecell_data;
|
|
|
|
|
2016-04-20 19:02:38 +07:00
|
|
|
static int __init rcar_sysc_pd_init(void)
|
|
|
|
{
|
|
|
|
const struct rcar_sysc_info *info;
|
|
|
|
const struct of_device_id *match;
|
|
|
|
struct rcar_pm_domains *domains;
|
|
|
|
struct device_node *np;
|
|
|
|
void __iomem *base;
|
|
|
|
unsigned int i;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
np = of_find_matching_node_and_match(NULL, rcar_sysc_matches, &match);
|
|
|
|
if (!np)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
info = match->data;
|
|
|
|
|
2017-03-31 16:01:55 +07:00
|
|
|
if (info->init) {
|
|
|
|
error = info->init();
|
|
|
|
if (error)
|
2019-08-15 13:13:54 +07:00
|
|
|
goto out_put;
|
2017-03-31 16:01:55 +07:00
|
|
|
}
|
|
|
|
|
2016-04-20 19:02:40 +07:00
|
|
|
has_cpg_mstp = of_find_compatible_node(NULL, NULL,
|
|
|
|
"renesas,cpg-mstp-clocks");
|
|
|
|
|
2016-04-20 19:02:38 +07:00
|
|
|
base = of_iomap(np, 0);
|
|
|
|
if (!base) {
|
2017-07-19 04:43:29 +07:00
|
|
|
pr_warn("%pOF: Cannot map regs\n", np);
|
2016-04-20 19:02:38 +07:00
|
|
|
error = -ENOMEM;
|
|
|
|
goto out_put;
|
|
|
|
}
|
|
|
|
|
|
|
|
rcar_sysc_base = base;
|
|
|
|
|
2019-08-28 18:36:12 +07:00
|
|
|
/* Optional External Request Mask Register */
|
|
|
|
rcar_sysc_extmask_offs = info->extmask_offs;
|
|
|
|
rcar_sysc_extmask_val = info->extmask_val;
|
|
|
|
|
2016-04-20 19:02:38 +07:00
|
|
|
domains = kzalloc(sizeof(*domains), GFP_KERNEL);
|
|
|
|
if (!domains) {
|
|
|
|
error = -ENOMEM;
|
|
|
|
goto out_put;
|
|
|
|
}
|
|
|
|
|
|
|
|
domains->onecell_data.domains = domains->domains;
|
|
|
|
domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains);
|
2018-05-30 22:25:13 +07:00
|
|
|
rcar_sysc_onecell_data = &domains->onecell_data;
|
2016-04-20 19:02:38 +07:00
|
|
|
|
|
|
|
for (i = 0; i < info->num_areas; i++) {
|
|
|
|
const struct rcar_sysc_area *area = &info->areas[i];
|
|
|
|
struct rcar_sysc_pd *pd;
|
|
|
|
|
2017-03-31 16:01:55 +07:00
|
|
|
if (!area->name) {
|
|
|
|
/* Skip NULLified area */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-04-20 19:02:38 +07:00
|
|
|
pd = kzalloc(sizeof(*pd) + strlen(area->name) + 1, GFP_KERNEL);
|
|
|
|
if (!pd) {
|
|
|
|
error = -ENOMEM;
|
|
|
|
goto out_put;
|
|
|
|
}
|
|
|
|
|
|
|
|
strcpy(pd->name, area->name);
|
|
|
|
pd->genpd.name = pd->name;
|
|
|
|
pd->ch.chan_offs = area->chan_offs;
|
|
|
|
pd->ch.chan_bit = area->chan_bit;
|
|
|
|
pd->ch.isr_bit = area->isr_bit;
|
|
|
|
pd->flags = area->flags;
|
|
|
|
|
2018-06-05 22:05:15 +07:00
|
|
|
error = rcar_sysc_pd_setup(pd);
|
|
|
|
if (error)
|
|
|
|
goto out_put;
|
2016-04-20 19:02:38 +07:00
|
|
|
|
|
|
|
domains->domains[area->isr_bit] = &pd->genpd;
|
|
|
|
|
2018-12-05 22:39:44 +07:00
|
|
|
if (area->parent < 0)
|
2018-06-05 22:05:15 +07:00
|
|
|
continue;
|
|
|
|
|
|
|
|
error = pm_genpd_add_subdomain(domains->domains[area->parent],
|
2018-12-05 22:39:44 +07:00
|
|
|
&pd->genpd);
|
|
|
|
if (error) {
|
2018-06-05 22:05:15 +07:00
|
|
|
pr_warn("Failed to add PM subdomain %s to parent %u\n",
|
|
|
|
area->name, area->parent);
|
2018-12-05 22:39:44 +07:00
|
|
|
goto out_put;
|
|
|
|
}
|
2018-06-05 22:05:15 +07:00
|
|
|
}
|
|
|
|
|
2016-06-28 21:10:31 +07:00
|
|
|
error = of_genpd_add_provider_onecell(np, &domains->onecell_data);
|
2016-04-20 19:02:38 +07:00
|
|
|
|
|
|
|
out_put:
|
|
|
|
of_node_put(np);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
early_initcall(rcar_sysc_pd_init);
|
2016-06-28 21:10:32 +07:00
|
|
|
|
2017-03-31 16:01:55 +07:00
|
|
|
void __init rcar_sysc_nullify(struct rcar_sysc_area *areas,
|
|
|
|
unsigned int num_areas, u8 id)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < num_areas; i++)
|
|
|
|
if (areas[i].isr_bit == id) {
|
|
|
|
areas[i].name = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-30 22:25:13 +07:00
|
|
|
#ifdef CONFIG_ARCH_R8A7779
|
|
|
|
static int rcar_sysc_power_cpu(unsigned int idx, bool on)
|
2016-06-28 21:10:32 +07:00
|
|
|
{
|
2018-05-30 22:25:13 +07:00
|
|
|
struct generic_pm_domain *genpd;
|
|
|
|
struct rcar_sysc_pd *pd;
|
|
|
|
unsigned int i;
|
2016-06-28 21:10:34 +07:00
|
|
|
|
2018-05-30 22:25:13 +07:00
|
|
|
if (!rcar_sysc_onecell_data)
|
|
|
|
return -ENODEV;
|
2016-06-28 21:10:32 +07:00
|
|
|
|
2018-05-30 22:25:13 +07:00
|
|
|
for (i = 0; i < rcar_sysc_onecell_data->num_domains; i++) {
|
|
|
|
genpd = rcar_sysc_onecell_data->domains[i];
|
|
|
|
if (!genpd)
|
|
|
|
continue;
|
soc: renesas: rcar-sysc: Move SYSC interrupt config to rcar-sysc driver
On R-Car H1 and Gen2, the SYSC interrupt registers are always configured
using hardcoded values in platform code. For R-Car Gen2, values are
provided for H2 and M2-W only, other SoCs are not yet supported, and
never will be.
Move this configuration from SoC-specific platform code to the
rcar_sysc_init() wrapper, so it can be skipped if the SYSC is configured
from DT. This would be the case not only for H1, H2, and M2-W using a
modern DTS, but also for other R-Car Gen2 SoCs not supported by the
platform code, relying purely on DT.
There is no longer a need to return the mapped register block, hence
make the function return void.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: Ulrich Hecht <ulrich.hecht+renesas@gmail.com>
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
2016-06-28 21:10:33 +07:00
|
|
|
|
2018-05-30 22:25:13 +07:00
|
|
|
pd = to_rcar_pd(genpd);
|
|
|
|
if (!(pd->flags & PD_CPU) || pd->ch.chan_bit != idx)
|
|
|
|
continue;
|
2016-06-28 21:10:34 +07:00
|
|
|
|
2018-12-05 22:39:43 +07:00
|
|
|
return rcar_sysc_power(&pd->ch, on);
|
2018-05-30 22:25:13 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rcar_sysc_power_down_cpu(unsigned int cpu)
|
|
|
|
{
|
|
|
|
return rcar_sysc_power_cpu(cpu, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
int rcar_sysc_power_up_cpu(unsigned int cpu)
|
|
|
|
{
|
|
|
|
return rcar_sysc_power_cpu(cpu, true);
|
2016-06-28 21:10:32 +07:00
|
|
|
}
|
2018-05-30 22:25:13 +07:00
|
|
|
#endif /* CONFIG_ARCH_R8A7779 */
|