mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-28 11:18:45 +07:00
bcb8243792
Simplify the power request code by passing an "on" flag, and picking the right status bit and register offset in the innermost function, based on this flag. This allows to remove the rcar_sysc_pwr_{off,on}() helper functions, and the function pointer through which they were called. Make sr_bit and reg_offs unsigned while we're at it. Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
165 lines
4.1 KiB
C
165 lines
4.1 KiB
C
/*
|
|
* R-Car SYSC Power management support
|
|
*
|
|
* Copyright (C) 2014 Magnus Damm
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
* License. See the file "COPYING" in the main directory of this archive
|
|
* for more details.
|
|
*/
|
|
|
|
#include <linux/delay.h>
|
|
#include <linux/err.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/spinlock.h>
|
|
#include <asm/io.h>
|
|
#include "pm-rcar.h"
|
|
|
|
/* 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 */
|
|
|
|
/* SYSC Status Register */
|
|
#define SYSCSR_PONENB 1 /* Ready for power resume requests */
|
|
#define SYSCSR_POFFENB 0 /* Ready for power shutoff requests */
|
|
|
|
/*
|
|
* Power Control Register Offsets inside the register block for each domain
|
|
* Note: The "CR" registers for ARM cores exist on H1 only
|
|
* Use WFI to power off, CPG/APMU to resume ARM cores on R-Car Gen2
|
|
*/
|
|
#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
|
|
|
|
#define PWRER_RETRIES 100
|
|
#define PWRER_DELAY_US 1
|
|
|
|
#define SYSCISR_RETRIES 1000
|
|
#define SYSCISR_DELAY_US 1
|
|
|
|
static void __iomem *rcar_sysc_base;
|
|
static DEFINE_SPINLOCK(rcar_sysc_lock); /* SMP CPUs + I/O devices */
|
|
|
|
static int rcar_sysc_pwr_on_off(const struct rcar_sysc_ch *sysc_ch, bool on)
|
|
{
|
|
unsigned int sr_bit, reg_offs;
|
|
int k;
|
|
|
|
if (on) {
|
|
sr_bit = SYSCSR_PONENB;
|
|
reg_offs = PWRONCR_OFFS;
|
|
} else {
|
|
sr_bit = SYSCSR_POFFENB;
|
|
reg_offs = PWROFFCR_OFFS;
|
|
}
|
|
|
|
/* Wait until SYSC is ready to accept a power request */
|
|
for (k = 0; k < SYSCSR_RETRIES; k++) {
|
|
if (ioread32(rcar_sysc_base + SYSCSR) & BIT(sr_bit))
|
|
break;
|
|
udelay(SYSCSR_DELAY_US);
|
|
}
|
|
|
|
if (k == SYSCSR_RETRIES)
|
|
return -EAGAIN;
|
|
|
|
/* Submit power shutoff or power resume request */
|
|
iowrite32(BIT(sysc_ch->chan_bit),
|
|
rcar_sysc_base + sysc_ch->chan_offs + reg_offs);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on)
|
|
{
|
|
unsigned int isr_mask = BIT(sysc_ch->isr_bit);
|
|
unsigned int chan_mask = BIT(sysc_ch->chan_bit);
|
|
unsigned int status;
|
|
unsigned long flags;
|
|
int ret = 0;
|
|
int k;
|
|
|
|
spin_lock_irqsave(&rcar_sysc_lock, flags);
|
|
|
|
iowrite32(isr_mask, rcar_sysc_base + SYSCISCR);
|
|
|
|
/* Submit power shutoff or resume request until it was accepted */
|
|
for (k = 0; k < PWRER_RETRIES; k++) {
|
|
ret = rcar_sysc_pwr_on_off(sysc_ch, on);
|
|
if (ret)
|
|
goto out;
|
|
|
|
status = ioread32(rcar_sysc_base +
|
|
sysc_ch->chan_offs + PWRER_OFFS);
|
|
if (!(status & chan_mask))
|
|
break;
|
|
|
|
udelay(PWRER_DELAY_US);
|
|
}
|
|
|
|
if (k == PWRER_RETRIES) {
|
|
ret = -EIO;
|
|
goto out;
|
|
}
|
|
|
|
/* Wait until the power shutoff or resume request has completed * */
|
|
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:
|
|
spin_unlock_irqrestore(&rcar_sysc_lock, flags);
|
|
|
|
pr_debug("sysc power domain %d: %08x -> %d\n",
|
|
sysc_ch->isr_bit, ioread32(rcar_sysc_base + SYSCISR), ret);
|
|
return ret;
|
|
}
|
|
|
|
int rcar_sysc_power_down(const struct rcar_sysc_ch *sysc_ch)
|
|
{
|
|
return rcar_sysc_power(sysc_ch, false);
|
|
}
|
|
|
|
int rcar_sysc_power_up(const struct rcar_sysc_ch *sysc_ch)
|
|
{
|
|
return rcar_sysc_power(sysc_ch, true);
|
|
}
|
|
|
|
bool rcar_sysc_power_is_off(const struct rcar_sysc_ch *sysc_ch)
|
|
{
|
|
unsigned int st;
|
|
|
|
st = ioread32(rcar_sysc_base + sysc_ch->chan_offs + PWRSR_OFFS);
|
|
if (st & BIT(sysc_ch->chan_bit))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void __iomem *rcar_sysc_init(phys_addr_t base)
|
|
{
|
|
rcar_sysc_base = ioremap_nocache(base, PAGE_SIZE);
|
|
if (!rcar_sysc_base)
|
|
panic("unable to ioremap R-Car SYSC hardware block\n");
|
|
|
|
return rcar_sysc_base;
|
|
}
|