code:
/*
 * SA11x0 Assembler Sleep/WakeUp Management Routines
 *
 * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License.
 *
 * History:
 *
 * 2001-02-06: Cliff Brake         Initial code
 *
 * 2001-08-29:	Nicolas Pitre	Simplified.
 *
 * 2002-05-27:	Nicolas Pitre	Revisited, more cleanup and simplification.
 *				Storage is on the stack now.
 */

#include <linux/linkage.h>
#include <asm/assembler.h>
#include <mach/hardware.h>

		.text
/*
 * sa1100_finish_suspend()
 *
 * Causes sa11x0 to enter sleep state
 *
 * Must be aligned to a cacheline.
 */
	.balign	32
ENTRY(sa1100_finish_suspend)
	@ disable clock switching
	mcr	p15, 0, r1, c15, c2, 2

	ldr	r6, =MDREFR
	ldr	r4, [r6]
	orr     r4, r4, #MDREFR_K1DB2
	ldr	r5, =PPCR

	@ Pre-load __loop_udelay into the I-cache
	mov	r0, #1
	bl	__loop_udelay
	mov	r0, r0

	@ The following must all exist in a single cache line to
	@ avoid accessing memory until this sequence is complete,
	@ otherwise we occasionally hang.

	@ Adjust memory timing before lowering CPU clock
	str     r4, [r6]

	@ delay 90us and set CPU PLL to lowest speed
	@ fixes resume problem on high speed SA1110
	mov	r0, #90
	bl	__loop_udelay
	mov	r1, #0
	str	r1, [r5]
	mov	r0, #90
	bl	__loop_udelay

	/*
	 * SA1110 SDRAM controller workaround.  register values:
	 *
	 * r0  = &MSC0
	 * r1  = &MSC1
	 * r2  = &MSC2
	 * r3  = MSC0 value
	 * r4  = MSC1 value
	 * r5  = MSC2 value
	 * r6  = &MDREFR
	 * r7  = first MDREFR value
	 * r8  = second MDREFR value
	 * r9  = &MDCNFG
	 * r10 = MDCNFG value
	 * r11 = third MDREFR value
	 * r12 = &PMCR
	 * r13 = PMCR value (1)
	 */

	ldr	r0, =MSC0
	ldr	r1, =MSC1
	ldr	r2, =MSC2

	ldr	r3, [r0]
	bic	r3, r3, #FMsk(MSC_RT)
	bic	r3, r3, #FMsk(MSC_RT)<<16

	ldr	r4, [r1]
	bic	r4, r4, #FMsk(MSC_RT)
	bic	r4, r4, #FMsk(MSC_RT)<<16

	ldr	r5, [r2]
	bic	r5, r5, #FMsk(MSC_RT)
	bic	r5, r5, #FMsk(MSC_RT)<<16

	ldr	r7, [r6]
	bic	r7, r7, #0x0000FF00
	bic	r7, r7, #0x000000F0
	orr	r8, r7, #MDREFR_SLFRSH

	ldr	r9, =MDCNFG
	ldr	r10, [r9]
	bic	r10, r10, #(MDCNFG_DE0+MDCNFG_DE1)
	bic	r10, r10, #(MDCNFG_DE2+MDCNFG_DE3)

	bic	r11, r8, #MDREFR_SLFRSH
	bic	r11, r11, #MDREFR_E1PIN

	ldr	r12, =PMCR

	mov	r13, #PMCR_SF

	b	sa1110_sdram_controller_fix

	.align 5
sa1110_sdram_controller_fix:

	@ Step 1 clear RT field of all MSCx registers
	str 	r3, [r0]
	str	r4, [r1]
	str	r5, [r2]

	@ Step 2 clear DRI field in MDREFR
	str	r7, [r6]

	@ Step 3 set SLFRSH bit in MDREFR
	str	r8, [r6]

	@ Step 4 clear DE bis in MDCNFG
	str	r10, [r9]

	@ Step 5 clear DRAM refresh control register
	str	r11, [r6]

	@ Wow, now the hardware suspend request pins can be used, that makes them functional for
	@ about 7 ns out of the	entire time that the CPU is running!

	@ Step 6 set force sleep bit in PMCR

	str	r13, [r12]

20:	b	20b			@ loop waiting for sleep


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 *  linux/arch/arm/mach-sa1100/ssp.c
 *
 *  Copyright (C) 2003 Russell King.
 *
 *  Generic SSP driver.  This provides the generic core for simple
 *  IO-based SSP applications.
 */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/io.h>

#include <mach/hardware.h>
#include <mach/irqs.h>
#include <asm/hardware/ssp.h>

#define TIMEOUT 100000

static irqreturn_t ssp_interrupt(int irq, void *dev_id)
{
	unsigned int status = Ser4SSSR;

	if (status & SSSR_ROR)
		printk(KERN_WARNING "SSP: receiver overrun\n");

	Ser4SSSR = SSSR_ROR;

	return status ? IRQ_HANDLED : IRQ_NONE;
}

/**
 * ssp_write_word - write a word to the SSP port
 * @data: 16-bit, MSB justified data to write.
 *
 * Wait for a free entry in the SSP transmit FIFO, and write a data
 * word to the SSP port.  Wait for the SSP port to start sending
 * the data.
 *
 * The caller is expected to perform the necessary locking.
 *
 * Returns:
 *   %-ETIMEDOUT	timeout occurred
 *   0			success
 */
int ssp_write_word(u16 data)
{
	int timeout = TIMEOUT;

	while (!(Ser4SSSR & SSSR_TNF)) {
	        if (!--timeout)
	        	return -ETIMEDOUT;
		cpu_relax();
	}

	Ser4SSDR = data;

	timeout = TIMEOUT;
	while (!(Ser4SSSR & SSSR_BSY)) {
	        if (!--timeout)
	        	return -ETIMEDOUT;
		cpu_relax();
	}

	return 0;
}

/**
 * ssp_read_word - read a word from the SSP port
 *
 * Wait for a data word in the SSP receive FIFO, and return the
 * received data.  Data is LSB justified.
 *
 * Note: Currently, if data is not expected to be received, this
 * function will wait for ever.
 *
 * The caller is expected to perform the necessary locking.
 *
 * Returns:
 *   %-ETIMEDOUT	timeout occurred
 *   16-bit data	success
 */
int ssp_read_word(u16 *data)
{
	int timeout = TIMEOUT;

	while (!(Ser4SSSR & SSSR_RNE)) {
	        if (!--timeout)
	        	return -ETIMEDOUT;
		cpu_relax();
	}

	*data = (u16)Ser4SSDR;

	return 0;
}

/**
 * ssp_flush - flush the transmit and receive FIFOs
 *
 * Wait for the SSP to idle, and ensure that the receive FIFO
 * is empty.
 *
 * The caller is expected to perform the necessary locking.
 *
 * Returns:
 *   %-ETIMEDOUT	timeout occurred
 *   0			success
 */
int ssp_flush(void)
{
	int timeout = TIMEOUT * 2;

	do {
		while (Ser4SSSR & SSSR_RNE) {
		        if (!--timeout)
		        	return -ETIMEDOUT;
			(void) Ser4SSDR;
		}
	        if (!--timeout)
	        	return -ETIMEDOUT;
	} while (Ser4SSSR & SSSR_BSY);

	return 0;
}

/**
 * ssp_enable - enable the SSP port
 *
 * Turn on the SSP port.
 */
void ssp_enable(void)
{
	Ser4SSCR0 |= SSCR0_SSE;
}

/**
 * ssp_disable - shut down the SSP port
 *
 * Turn off the SSP port, optionally powering it down.
 */
void ssp_disable(void)
{
	Ser4SSCR0 &= ~SSCR0_SSE;
}

/**
 * ssp_save_state - save the SSP configuration
 * @ssp: pointer to structure to save SSP configuration
 *
 * Save the configured SSP state for suspend.
 */
void ssp_save_state(struct ssp_state *ssp)
{
	ssp->cr0 = Ser4SSCR0;
	ssp->cr1 = Ser4SSCR1;

	Ser4SSCR0 &= ~SSCR0_SSE;
}

/**
 * ssp_restore_state - restore a previously saved SSP configuration
 * @ssp: pointer to configuration saved by ssp_save_state
 *
 * Restore the SSP configuration saved previously by ssp_save_state.
 */
void ssp_restore_state(struct ssp_state *ssp)
{
	Ser4SSSR = SSSR_ROR;

	Ser4SSCR0 = ssp->cr0 & ~SSCR0_SSE;
	Ser4SSCR1 = ssp->cr1;
	Ser4SSCR0 = ssp->cr0;
}

/**
 * ssp_init - setup the SSP port
 *
 * initialise and claim resources for the SSP port.
 *
 * Returns:
 *   %-ENODEV	if the SSP port is unavailable
 *   %-EBUSY	if the resources are already in use
 *   %0		on success
 */
int ssp_init(void)
{
	int ret;

	if (!(PPAR & PPAR_SPR) && (Ser4MCCR0 & MCCR0_MCE))
		return -ENODEV;

	if (!request_mem_region(__PREG(Ser4SSCR0), 0x18, "SSP")) {
		return -EBUSY;
	}

	Ser4SSSR = SSSR_ROR;

	ret = request_irq(IRQ_Ser4SSP, ssp_interrupt, 0, "SSP", NULL);
	if (ret)
		goto out_region;

	return 0;

 out_region:
	release_mem_region(__PREG(Ser4SSCR0), 0x18);
	return ret;
}

/**
 * ssp_exit - undo the effects of ssp_init
 *
 * release and free resources for the SSP port.
 */
void ssp_exit(void)
{
	Ser4SSCR0 &= ~SSCR0_SSE;

	free_irq(IRQ_Ser4SSP, NULL);
	release_mem_region(__PREG(Ser4SSCR0), 0x18);
}

MODULE_AUTHOR("Russell King");
MODULE_DESCRIPTION("SA11x0 SSP PIO driver");
MODULE_LICENSE("GPL");

EXPORT_SYMBOL(ssp_write_word);
EXPORT_SYMBOL(ssp_read_word);
EXPORT_SYMBOL(ssp_flush);
EXPORT_SYMBOL(ssp_enable);
EXPORT_SYMBOL(ssp_disable);
EXPORT_SYMBOL(ssp_save_state);
EXPORT_SYMBOL(ssp_restore_state);
EXPORT_SYMBOL(ssp_init);
EXPORT_SYMBOL(ssp_exit);

repo_name: angery/linux


code:
# SPDX-License-Identifier: GPL-2.0
menuconfig ARCH_RENESAS
	bool "Renesas ARM SoCs"
	depends on ARCH_MULTI_V7
	select ARM_GIC
	select NO_IOPORT_MAP
	select ZONE_DMA if ARM_LPAE

path: arch/arm/mach-shmobile/Kconfig


code:
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the linux kernel.
#

# Common objects
obj-y				:= timer.o

# CPU objects
obj-$(CONFIG_ARCH_SH73A0)	+= setup-sh73a0.o
obj-$(CONFIG_ARCH_R8A73A4)	+= setup-r8a73a4.o
obj-$(CONFIG_ARCH_R8A7740)	+= setup-r8a7740.o
obj-$(CONFIG_ARCH_R8A7778)	+= setup-r8a7778.o
obj-$(CONFIG_ARCH_R8A7779)	+= setup-r8a7779.o
obj-$(CONFIG_ARCH_EMEV2)	+= setup-emev2.o
obj-$(CONFIG_ARCH_R7S72100)	+= setup-r7s72100.o
obj-$(CONFIG_ARCH_R7S9210)	+= setup-r7s9210.o

# CPU reset vector handling objects
cpu-y				:= platsmp.o headsmp.o

# Shared SoC family objects
obj-$(CONFIG_ARCH_RCAR_GEN2)	+= setup-rcar-gen2.o platsmp-apmu.o $(cpu-y)
CFLAGS_setup-rcar-gen2.o	+= -march=armv7-a
obj-$(CONFIG_ARCH_R8A7790)	+= regulator-quirk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7791)	+= regulator-quirk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7793)	+= regulator-quirk-rcar-gen2.o

# SMP objects
smp-y				:= $(cpu-y)
smp-$(CONFIG_ARCH_RCAR_GEN2)	+= headsmp-apmu.o
smp-$(CONFIG_ARCH_SH73A0)	+= smp-sh73a0.o headsmp-scu.o platsmp-scu.o
smp-$(CONFIG_ARCH_R8A7779)	+= smp-r8a7779.o headsmp-scu.o platsmp-scu.o
smp-$(CONFIG_ARCH_EMEV2)	+= smp-emev2.o headsmp-scu.o platsmp-scu.o

# PM objects
obj-$(CONFIG_SUSPEND)		+= suspend.o
obj-$(CONFIG_ARCH_RCAR_GEN2)	+= pm-rcar-gen2.o

# Framework support
obj-$(CONFIG_SMP)		+= $(smp-y)

path: arch/arm/mach-shmobile/Makefile


code:
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ARCH_MACH_COMMON_H
#define __ARCH_MACH_COMMON_H

extern void shmobile_init_delay(void);
extern void shmobile_boot_vector(void);
extern unsigned long shmobile_boot_fn;
extern unsigned long shmobile_boot_size;
extern void shmobile_boot_vector_gen2(void);
extern unsigned long shmobile_boot_fn_gen2;
extern unsigned long shmobile_boot_cpu_gen2;
extern unsigned long shmobile_boot_size_gen2;
extern void shmobile_smp_boot(void);
extern void shmobile_smp_sleep(void);
extern void shmobile_smp_hook(unsigned int cpu, unsigned long fn,
			      unsigned long arg);
extern bool shmobile_smp_cpu_can_disable(unsigned int cpu);
extern void shmobile_boot_apmu(void);
extern void shmobile_boot_scu(void);
extern void shmobile_smp_scu_prepare_cpus(phys_addr_t scu_base_phys,
					  unsigned int max_cpus);
extern void shmobile_smp_scu_cpu_die(unsigned int cpu);
extern int shmobile_smp_scu_cpu_kill(unsigned int cpu);
extern struct platform_suspend_ops shmobile_suspend_ops;

#ifdef CONFIG_SUSPEND
int shmobile_suspend_init(void);
void shmobile_smp_apmu_suspend_init(void);
#else
static inline int shmobile_suspend_init(void) { return 0; }
static inline void shmobile_smp_apmu_suspend_init(void) { }
#endif

static inline void __init shmobile_init_late(void)
{
	shmobile_suspend_init();
}

#endif /* __ARCH_MACH_COMMON_H */


code:
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_EMEV2_H__
#define __ASM_EMEV2_H__

extern const struct smp_operations emev2_smp_ops;

#endif /* __ASM_EMEV2_H__ */


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * SMP support for APMU based systems with Cortex A7/A15
 *
 * Copyright (C) 2014  Renesas Electronics Corporation
 */

#include <linux/linkage.h>
#include <asm/assembler.h>

ENTRY(shmobile_boot_apmu)
	bl	secure_cntvoff_init
	b	secondary_startup
ENDPROC(shmobile_boot_apmu)


code:
/* SPDX-License-Identifier: GPL-2.0+
 *
 * Shared SCU setup for mach-shmobile
 *
 * Copyright (C) 2012 Bastian Hecht
 */

#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/memory.h>

/*
 * Boot code for secondary CPUs.
 *
 * First we turn on L1 cache coherency for our CPU. Then we jump to
 * secondary_startup that invalidates the cache and hands over control
 * to the common ARM startup code.
 */
ENTRY(shmobile_boot_scu)
					@ r0 = SCU base address
	mrc     p15, 0, r1, c0, c0, 5	@ read MPIDR
	and	r1, r1, #3		@ mask out cpu ID
	lsl	r1, r1, #3		@ we will shift by cpu_id * 8 bits
	ldr	r2, [r0, #8]		@ SCU Power Status Register
	mov	r3, #3
	lsl	r3, r3, r1
	bic	r2, r2, r3		@ Clear bits of our CPU (Run Mode)
	str	r2, [r0, #8]		@ write back

	b	secondary_startup
ENDPROC(shmobile_boot_scu)


code:
/* SPDX-License-Identifier: GPL-2.0
 *
 * SMP support for R-Mobile / SH-Mobile
 *
 * Copyright (C) 2010  Magnus Damm
 * Copyright (C) 2010  Takashi Yoshii
 *
 * Based on vexpress, Copyright (c) 2003 ARM Limited, All Rights Reserved
 */
#include <linux/init.h>
#include <linux/linkage.h>
#include <linux/threads.h>
#include <asm/assembler.h>
#include <asm/memory.h>

#define SCTLR_MMU	0x01
#define BOOTROM_ADDRESS	0xE6340000
#define RWTCSRA_ADDRESS 0xE6020004
#define RWTCSRA_WOVF	0x10

/*
 * Reset vector for secondary CPUs.
 * This will be mapped at address 0 by SBAR register.
 * We need _long_ jump to the physical address.
 */
	.arm
	.align  12
ENTRY(shmobile_boot_vector)
	ldr     r1, 1f
	bx	r1

ENDPROC(shmobile_boot_vector)

	.align	2
	.globl	shmobile_boot_fn
shmobile_boot_fn:
1:	.space	4
	.globl	shmobile_boot_size
shmobile_boot_size:
	.long	. - shmobile_boot_vector

#ifdef CONFIG_ARCH_RCAR_GEN2
/*
 * Reset vector for R-Car Gen2 and RZ/G1 secondary CPUs.
 * This will be mapped at address 0 by SBAR register.
 */
ENTRY(shmobile_boot_vector_gen2)
	mrc	p15, 0, r0, c0, c0, 5		@ r0 = MPIDR
	ldr	r1, shmobile_boot_cpu_gen2
	cmp	r0, r1
	bne	shmobile_smp_continue_gen2

	mrc	p15, 0, r1, c1, c0, 0		@ r1 = SCTLR
	and	r0, r1, #SCTLR_MMU
	cmp	r0, #SCTLR_MMU
	beq	shmobile_smp_continue_gen2

	ldr	r0, rwtcsra
	mov	r1, #0
	ldrb	r1, [r0]
	and	r0, r1, #RWTCSRA_WOVF
	cmp	r0, #RWTCSRA_WOVF
	bne	shmobile_smp_continue_gen2

	ldr	r0, bootrom
	bx	r0

shmobile_smp_continue_gen2:
	ldr     r1, shmobile_boot_fn_gen2
	bx	r1

ENDPROC(shmobile_boot_vector_gen2)

	.align	4
rwtcsra:
	.word	RWTCSRA_ADDRESS
bootrom:
	.word	BOOTROM_ADDRESS
	.globl	shmobile_boot_cpu_gen2
shmobile_boot_cpu_gen2:
	.word	0x00000000

	.align	2
	.globl	shmobile_boot_fn_gen2
shmobile_boot_fn_gen2:
	.space	4
	.globl	shmobile_boot_size_gen2
shmobile_boot_size_gen2:
	.long	. - shmobile_boot_vector_gen2
#endif /* CONFIG_ARCH_RCAR_GEN2 */

/*
 * Per-CPU SMP boot function/argument selection code based on MPIDR
 */

ENTRY(shmobile_smp_boot)
	mrc	p15, 0, r1, c0, c0, 5		@ r1 = MPIDR
	and	r0, r1, #0xffffff		@ MPIDR_HWID_BITMASK
						@ r0 = cpu_logical_map() value
	mov	r1, #0				@ r1 = CPU index
	adr	r2, 1f
	ldmia	r2, {r5, r6, r7}
	add	r5, r5, r2			@ array of per-cpu mpidr values
	add	r6, r6, r2			@ array of per-cpu functions
	add	r7, r7, r2			@ array of per-cpu arguments

shmobile_smp_boot_find_mpidr:
	ldr	r8, [r5, r1, lsl #2]
	cmp	r8, r0
	bne	shmobile_smp_boot_next

	ldr	r9, [r6, r1, lsl #2]
	cmp	r9, #0
	bne	shmobile_smp_boot_found

shmobile_smp_boot_next:
	add	r1, r1, #1
	cmp	r1, #NR_CPUS
	blo	shmobile_smp_boot_find_mpidr

	b	shmobile_smp_sleep

shmobile_smp_boot_found:
	ldr	r0, [r7, r1, lsl #2]
	ret	r9
ENDPROC(shmobile_smp_boot)

ENTRY(shmobile_smp_sleep)
	wfi
	b	shmobile_smp_boot
ENDPROC(shmobile_smp_sleep)

	.align	2
1:	.long	shmobile_smp_mpidr - .
	.long	shmobile_smp_fn - 1b
	.long	shmobile_smp_arg - 1b

	.bss
	.globl	shmobile_smp_mpidr
shmobile_smp_mpidr:
	.space	NR_CPUS * 4
	.globl	shmobile_smp_fn
shmobile_smp_fn:
	.space	NR_CPUS * 4
	.globl	shmobile_smp_arg
shmobile_smp_arg:
	.space	NR_CPUS * 4


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * SMP support for SoCs with APMU
 *
 * Copyright (C) 2014  Renesas Electronics Corporation
 * Copyright (C) 2013  Magnus Damm
 */
#include <linux/cpu_pm.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/of_address.h>
#include <linux/smp.h>
#include <linux/suspend.h>
#include <linux/threads.h>
#include <asm/cacheflush.h>
#include <asm/cp15.h>
#include <asm/proc-fns.h>
#include <asm/smp_plat.h>
#include <asm/suspend.h>
#include "common.h"
#include "rcar-gen2.h"

static struct {
	void __iomem *iomem;
	int bit;
} apmu_cpus[NR_CPUS];

#define WUPCR_OFFS	 0x10		/* Wake Up Control Register */
#define PSTR_OFFS	 0x40		/* Power Status Register */
#define CPUNCR_OFFS(n)	(0x100 + (0x10 * (n)))
					/* CPUn Power Status Control Register */
#define DBGRCR_OFFS	0x180		/* Debug Resource Reset Control Reg. */

/* Power Status Register */
#define CPUNST(r, n)	(((r) >> (n * 4)) & 3)	/* CPUn Status Bit */
#define CPUST_RUN	0		/* Run Mode */
#define CPUST_STANDBY	3		/* CoreStandby Mode */

/* Debug Resource Reset Control Register */
#define DBGCPUREN	BIT(24)		/* CPU Other Reset Request Enable */
#define DBGCPUNREN(n)	BIT((n) + 20)	/* CPUn Reset Request Enable */
#define DBGCPUPREN	BIT(19)		/* CPU Peripheral Reset Req. Enable */

static int __maybe_unused apmu_power_on(void __iomem *p, int bit)
{
	/* request power on */
	writel_relaxed(BIT(bit), p + WUPCR_OFFS);

	/* wait for APMU to finish */
	while (readl_relaxed(p + WUPCR_OFFS) != 0)
		;

	return 0;
}

static int __maybe_unused apmu_power_off(void __iomem *p, int bit)
{
	/* request Core Standby for next WFI */
	writel_relaxed(3, p + CPUNCR_OFFS(bit));
	return 0;
}

static int __maybe_unused apmu_power_off_poll(void __iomem *p, int bit)
{
	int k;

	for (k = 0; k < 1000; k++) {
		if (CPUNST(readl_relaxed(p + PSTR_OFFS), bit) == CPUST_STANDBY)
			return 1;

		mdelay(1);
	}

	return 0;
}

static int __maybe_unused apmu_wrap(int cpu, int (*fn)(void __iomem *p, int cpu))
{
	void __iomem *p = apmu_cpus[cpu].iomem;

	return p ? fn(p, apmu_cpus[cpu].bit) : -EINVAL;
}

#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_SUSPEND)
/* nicked from arch/arm/mach-exynos/hotplug.c */
static inline void cpu_enter_lowpower_a15(void)
{
	unsigned int v;

	asm volatile(
	"       mrc     p15, 0, %0, c1, c0, 0\n"
	"       bic     %0, %0, %1\n"
	"       mcr     p15, 0, %0, c1, c0, 0\n"
		: "=&r" (v)
		: "Ir" (CR_C)
		: "cc");

	flush_cache_louis();

	asm volatile(
	/*
	 * Turn off coherency
	 */
	"       mrc     p15, 0, %0, c1, c0, 1\n"
	"       bic     %0, %0, %1\n"
	"       mcr     p15, 0, %0, c1, c0, 1\n"
		: "=&r" (v)
		: "Ir" (0x40)
		: "cc");

	isb();
	dsb();
}

static void shmobile_smp_apmu_cpu_shutdown(unsigned int cpu)
{

	/* Select next sleep mode using the APMU */
	apmu_wrap(cpu, apmu_power_off);

	/* Do ARM specific CPU shutdown */
	cpu_enter_lowpower_a15();
}
#endif

#if defined(CONFIG_HOTPLUG_CPU)
static void shmobile_smp_apmu_cpu_die(unsigned int cpu)
{
	/* For this particular CPU deregister boot vector */
	shmobile_smp_hook(cpu, 0, 0);

	/* Shutdown CPU core */
	shmobile_smp_apmu_cpu_shutdown(cpu);

	/* jump to shared mach-shmobile sleep / reset code */
	shmobile_smp_sleep();
}

static int shmobile_smp_apmu_cpu_kill(unsigned int cpu)
{
	return apmu_wrap(cpu, apmu_power_off_poll);
}
#endif

#if defined(CONFIG_SUSPEND)
static int shmobile_smp_apmu_do_suspend(unsigned long cpu)
{
	shmobile_smp_hook(cpu, __pa_symbol(cpu_resume), 0);
	shmobile_smp_apmu_cpu_shutdown(cpu);
	cpu_do_idle(); /* WFI selects Core Standby */
	return 1;
}

static inline void cpu_leave_lowpower(void)
{
	unsigned int v;

	asm volatile("mrc    p15, 0, %0, c1, c0, 0\n"
		     "       orr     %0, %0, %1\n"
		     "       mcr     p15, 0, %0, c1, c0, 0\n"
		     "       mrc     p15, 0, %0, c1, c0, 1\n"
		     "       orr     %0, %0, %2\n"
		     "       mcr     p15, 0, %0, c1, c0, 1\n"
		     : "=&r" (v)
		     : "Ir" (CR_C), "Ir" (0x40)
		     : "cc");
}

static int shmobile_smp_apmu_enter_suspend(suspend_state_t state)
{
	cpu_suspend(smp_processor_id(), shmobile_smp_apmu_do_suspend);
	cpu_leave_lowpower();
	return 0;
}

void __init shmobile_smp_apmu_suspend_init(void)
{
	shmobile_suspend_ops.enter = shmobile_smp_apmu_enter_suspend;
}
#endif

#ifdef CONFIG_SMP
static void apmu_init_cpu(struct resource *res, int cpu, int bit)
{
	u32 x;

	if ((cpu >= ARRAY_SIZE(apmu_cpus)) || apmu_cpus[cpu].iomem)
		return;

	apmu_cpus[cpu].iomem = ioremap(res->start, resource_size(res));
	apmu_cpus[cpu].bit = bit;

	pr_debug("apmu ioremap %d %d %pr\n", cpu, bit, res);

	/* Setup for debug mode */
	x = readl(apmu_cpus[cpu].iomem + DBGRCR_OFFS);
	x |= DBGCPUREN | DBGCPUNREN(bit) | DBGCPUPREN;
	writel(x, apmu_cpus[cpu].iomem + DBGRCR_OFFS);
}

static const struct of_device_id apmu_ids[] = {
	{ .compatible = "renesas,apmu" },
	{ /*sentinel*/ }
};

static void apmu_parse_dt(void (*fn)(struct resource *res, int cpu, int bit))
{
	struct device_node *np_apmu, *np_cpu;
	struct resource res;
	int bit, index;
	u32 id;

	for_each_matching_node(np_apmu, apmu_ids) {
		/* only enable the cluster that includes the boot CPU */
		bool is_allowed = false;

		for (bit = 0; bit < CONFIG_NR_CPUS; bit++) {
			np_cpu = of_parse_phandle(np_apmu, "cpus", bit);
			if (np_cpu) {
				if (!of_property_read_u32(np_cpu, "reg", &id)) {
					if (id == cpu_logical_map(0)) {
						is_allowed = true;
						of_node_put(np_cpu);
						break;
					}

				}
				of_node_put(np_cpu);
			}
		}
		if (!is_allowed)
			continue;

		for (bit = 0; bit < CONFIG_NR_CPUS; bit++) {
			np_cpu = of_parse_phandle(np_apmu, "cpus", bit);
			if (np_cpu) {
				if (!of_property_read_u32(np_cpu, "reg", &id)) {
					index = get_logical_index(id);
					if ((index >= 0) &&
					    !of_address_to_resource(np_apmu,
								    0, &res))
						fn(&res, index, bit);
				}
				of_node_put(np_cpu);
			}
		}
	}
}

static void __init shmobile_smp_apmu_setup_boot(void)
{
	/* install boot code shared by all CPUs */
	shmobile_boot_fn = __pa_symbol(shmobile_smp_boot);
	shmobile_boot_fn_gen2 = shmobile_boot_fn;
}

static int shmobile_smp_apmu_boot_secondary(unsigned int cpu,
					    struct task_struct *idle)
{
	/* For this particular CPU register boot vector */
	shmobile_smp_hook(cpu, __pa_symbol(shmobile_boot_apmu), 0);

	return apmu_wrap(cpu, apmu_power_on);
}

static void __init shmobile_smp_apmu_prepare_cpus_dt(unsigned int max_cpus)
{
	shmobile_smp_apmu_setup_boot();
	apmu_parse_dt(apmu_init_cpu);
	rcar_gen2_pm_init();
}

static struct smp_operations apmu_smp_ops __initdata = {
	.smp_prepare_cpus	= shmobile_smp_apmu_prepare_cpus_dt,
	.smp_boot_secondary	= shmobile_smp_apmu_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
	.cpu_can_disable	= shmobile_smp_cpu_can_disable,
	.cpu_die		= shmobile_smp_apmu_cpu_die,
	.cpu_kill		= shmobile_smp_apmu_cpu_kill,
#endif
};

CPU_METHOD_OF_DECLARE(shmobile_smp_apmu, "renesas,apmu", &apmu_smp_ops);
#endif /* CONFIG_SMP */


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * SMP support for SoCs with SCU covered by mach-shmobile
 *
 * Copyright (C) 2013  Magnus Damm
 */
#include <linux/cpu.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/smp.h>
#include <asm/cacheflush.h>
#include <asm/smp_plat.h>
#include <asm/smp_scu.h>
#include "common.h"

static phys_addr_t shmobile_scu_base_phys;
static void __iomem *shmobile_scu_base;

static int shmobile_scu_cpu_prepare(unsigned int cpu)
{
	/* For this particular CPU register SCU SMP boot vector */
	shmobile_smp_hook(cpu, __pa_symbol(shmobile_boot_scu),
			  shmobile_scu_base_phys);
	return 0;
}

void __init shmobile_smp_scu_prepare_cpus(phys_addr_t scu_base_phys,
					  unsigned int max_cpus)
{
	/* install boot code shared by all CPUs */
	shmobile_boot_fn = __pa_symbol(shmobile_smp_boot);

	/* enable SCU and cache coherency on booting CPU */
	shmobile_scu_base_phys = scu_base_phys;
	shmobile_scu_base = ioremap(scu_base_phys, PAGE_SIZE);
	scu_enable(shmobile_scu_base);
	scu_power_mode(shmobile_scu_base, SCU_PM_NORMAL);

	/* Use CPU notifier for reset vector control */
	cpuhp_setup_state_nocalls(CPUHP_ARM_SHMOBILE_SCU_PREPARE,
				  "arm/shmobile-scu:prepare",
				  shmobile_scu_cpu_prepare, NULL);
}

#ifdef CONFIG_HOTPLUG_CPU
void shmobile_smp_scu_cpu_die(unsigned int cpu)
{
	/* For this particular CPU deregister boot vector */
	shmobile_smp_hook(cpu, 0, 0);

	dsb();
	flush_cache_all();

	/* disable cache coherency */
	scu_power_mode(shmobile_scu_base, SCU_PM_POWEROFF);

	/* jump to shared mach-shmobile sleep / reset code */
	shmobile_smp_sleep();
}

static int shmobile_smp_scu_psr_core_disabled(int cpu)
{
	unsigned long mask = SCU_PM_POWEROFF << (cpu * 8);

	if ((readl(shmobile_scu_base + 8) & mask) == mask)
		return 1;

	return 0;
}

int shmobile_smp_scu_cpu_kill(unsigned int cpu)
{
	int k;

	/* this function is running on another CPU than the offline target,
	 * here we need wait for shutdown code in platform_cpu_die() to
	 * finish before asking SoC-specific code to power off the CPU core.
	 */
	for (k = 0; k < 1000; k++) {
		if (shmobile_smp_scu_psr_core_disabled(cpu))
			return 1;

		mdelay(1);
	}

	return 0;
}
#endif


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * SMP support for R-Mobile / SH-Mobile
 *
 * Copyright (C) 2010  Magnus Damm
 * Copyright (C) 2011  Paul Mundt
 *
 * Based on vexpress, Copyright (C) 2002 ARM Ltd, All Rights Reserved
 */
#include <linux/init.h>
#include <asm/cacheflush.h>
#include <asm/smp_plat.h>
#include "common.h"

extern unsigned long shmobile_smp_fn[];
extern unsigned long shmobile_smp_arg[];
extern unsigned long shmobile_smp_mpidr[];

void shmobile_smp_hook(unsigned int cpu, unsigned long fn, unsigned long arg)
{
	shmobile_smp_fn[cpu] = 0;
	flush_cache_all();

	shmobile_smp_mpidr[cpu] = cpu_logical_map(cpu);
	shmobile_smp_fn[cpu] = fn;
	shmobile_smp_arg[cpu] = arg;
	flush_cache_all();
}

#ifdef CONFIG_HOTPLUG_CPU
bool shmobile_smp_cpu_can_disable(unsigned int cpu)
{
	return true; /* Hotplug of any CPU is supported */
}
#endif


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * R-Car Generation 2 Power management support
 *
 * Copyright (C) 2013 - 2015  Renesas Electronics Corporation
 * Copyright (C) 2011  Renesas Solutions Corp.
 * Copyright (C) 2011  Magnus Damm
 */

#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/smp.h>
#include <asm/io.h>
#include <asm/cputype.h>
#include "common.h"
#include "rcar-gen2.h"

/* RST */
#define RST		0xe6160000

#define CA15BAR		0x0020		/* CA15 Boot Address Register */
#define CA7BAR		0x0030		/* CA7 Boot Address Register */
#define CA15RESCNT	0x0040		/* CA15 Reset Control Register */
#define CA7RESCNT	0x0044		/* CA7 Reset Control Register */

/* SYS Boot Address Register */
#define SBAR_BAREN	BIT(4)		/* SBAR is valid */

/* Reset Control Registers */
#define CA15RESCNT_CODE	0xa5a50000
#define CA15RESCNT_CPUS	0xf		/* CPU0-3 */
#define CA7RESCNT_CODE	0x5a5a0000
#define CA7RESCNT_CPUS	0xf		/* CPU0-3 */

/* On-chip RAM */
#define ICRAM1		0xe63c0000	/* Inter Connect RAM1 (4 KiB) */

static inline u32 phys_to_sbar(phys_addr_t addr)
{
	return (addr >> 8) & 0xfffffc00;
}

void __init rcar_gen2_pm_init(void)
{
	void __iomem *p;
	u32 bar;
	static int once;
	struct device_node *np;
	bool has_a7 = false;
	bool has_a15 = false;
	struct resource res;
	int error;

	if (once++)
		return;

	for_each_of_cpu_node(np) {
		if (of_device_is_compatible(np, "arm,cortex-a15"))
			has_a15 = true;
		else if (of_device_is_compatible(np, "arm,cortex-a7"))
			has_a7 = true;
	}

	np = of_find_compatible_node(NULL, NULL, "renesas,smp-sram");
	if (!np) {
		/* No smp-sram in DT, fall back to hardcoded address */
		res = (struct resource)DEFINE_RES_MEM(ICRAM1,
						      shmobile_boot_size);
		goto map;
	}

	error = of_address_to_resource(np, 0, &res);
	of_node_put(np);
	if (error) {
		pr_err("Failed to get smp-sram address: %d\n", error);
		return;
	}

map:
	/* RAM for jump stub, because BAR requires 256KB aligned address */
	if (res.start & (256 * 1024 - 1) ||
	    resource_size(&res) < shmobile_boot_size) {
		pr_err("Invalid smp-sram region\n");
		return;
	}

	p = ioremap(res.start, resource_size(&res));
	if (!p)
		return;
	/*
	 * install the reset vector, use the largest version if we have enough
	 * memory available
	 */
	if (resource_size(&res) >= shmobile_boot_size_gen2) {
		shmobile_boot_cpu_gen2 = read_cpuid_mpidr();
		memcpy_toio(p, shmobile_boot_vector_gen2,
			    shmobile_boot_size_gen2);
	} else {
		memcpy_toio(p, shmobile_boot_vector, shmobile_boot_size);
	}
	iounmap(p);

	/* setup reset vectors */
	p = ioremap(RST, 0x63);
	bar = phys_to_sbar(res.start);
	if (has_a15) {
		writel_relaxed(bar, p + CA15BAR);
		writel_relaxed(bar | SBAR_BAREN, p + CA15BAR);

		/* de-assert reset for CA15 CPUs */
		writel_relaxed((readl_relaxed(p + CA15RESCNT) &
				~CA15RESCNT_CPUS) | CA15RESCNT_CODE,
			       p + CA15RESCNT);
	}
	if (has_a7) {
		writel_relaxed(bar, p + CA7BAR);
		writel_relaxed(bar | SBAR_BAREN, p + CA7BAR);

		/* de-assert reset for CA7 CPUs */
		writel_relaxed((readl_relaxed(p + CA7RESCNT) &
				~CA7RESCNT_CPUS) | CA7RESCNT_CODE,
			       p + CA7RESCNT);
	}
	iounmap(p);

	shmobile_smp_apmu_suspend_init();
}


code:
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_R8A7779_H__
#define __ASM_R8A7779_H__

extern const struct smp_operations r8a7779_smp_ops;

#endif /* __ASM_R8A7779_H__ */


code:
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_RCAR_GEN2_H__
#define __ASM_RCAR_GEN2_H__

void rcar_gen2_pm_init(void);

#endif /* __ASM_RCAR_GEN2_H__ */


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * R-Car Generation 2 da9063(L)/da9210 regulator quirk
 *
 * Certain Gen2 development boards have an da9063 and one or more da9210
 * regulators. All of these regulators have their interrupt request lines
 * tied to the same interrupt pin (IRQ2) on the SoC.
 *
 * After cold boot or da9063-induced restart, both the da9063 and da9210 seem
 * to assert their interrupt request lines.  Hence as soon as one driver
 * requests this irq, it gets stuck in an interrupt storm, as it only manages
 * to deassert its own interrupt request line, and the other driver hasn't
 * installed an interrupt handler yet.
 *
 * To handle this, install a quirk that masks the interrupts in both the
 * da9063 and da9210.  This quirk has to run after the i2c master driver has
 * been initialized, but before the i2c slave drivers are initialized.
 *
 * Copyright (C) 2015 Glider bvba
 */

#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/list.h>
#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/mfd/da9063/registers.h>

#define IRQC_BASE		0xe61c0000
#define IRQC_MONITOR		0x104	/* IRQn Signal Level Monitor Register */

#define REGULATOR_IRQ_MASK	BIT(2)	/* IRQ2, active low */

/* start of DA9210 System Control and Event Registers */
#define DA9210_REG_MASK_A		0x54

struct regulator_quirk {
	struct list_head		list;
	const struct of_device_id	*id;
	struct device_node		*np;
	struct of_phandle_args		irq_args;
	struct i2c_msg			i2c_msg;
	bool				shared;	/* IRQ line is shared */
};

static LIST_HEAD(quirk_list);
static void __iomem *irqc;

/* first byte sets the memory pointer, following are consecutive reg values */
static u8 da9063_irq_clr[] = { DA9063_REG_IRQ_MASK_A, 0xff, 0xff, 0xff, 0xff };
static u8 da9210_irq_clr[] = { DA9210_REG_MASK_A, 0xff, 0xff };

static struct i2c_msg da9063_msg = {
	.len = ARRAY_SIZE(da9063_irq_clr),
	.buf = da9063_irq_clr,
};

static struct i2c_msg da9210_msg = {
	.len = ARRAY_SIZE(da9210_irq_clr),
	.buf = da9210_irq_clr,
};

static const struct of_device_id rcar_gen2_quirk_match[] = {
	{ .compatible = "dlg,da9063", .data = &da9063_msg },
	{ .compatible = "dlg,da9063l", .data = &da9063_msg },
	{ .compatible = "dlg,da9210", .data = &da9210_msg },
	{ /* sentinel */ }
};

static int regulator_quirk_notify(struct notifier_block *nb,
				  unsigned long action, void *data)
{
	struct regulator_quirk *pos, *tmp;
	struct device *dev = data;
	struct i2c_client *client;
	static bool done;
	int ret;
	u32 mon;

	if (done)
		return 0;

	mon = ioread32(irqc + IRQC_MONITOR);
	dev_dbg(dev, "%s: %ld, IRQC_MONITOR = 0x%x\n", __func__, action, mon);
	if (mon & REGULATOR_IRQ_MASK)
		goto remove;

	if (action != BUS_NOTIFY_ADD_DEVICE || dev->type == &i2c_adapter_type)
		return 0;

	client = to_i2c_client(dev);
	dev_dbg(dev, "Detected %s\n", client->name);

	/*
	 * Send message to all PMICs that share an IRQ line to deassert it.
	 *
	 * WARNING: This works only if all the PMICs are on the same I2C bus.
	 */
	list_for_each_entry(pos, &quirk_list, list) {
		if (!pos->shared)
			continue;

		if (pos->np->parent != client->dev.parent->of_node)
			continue;

		dev_info(&client->dev, "clearing %s@0x%02x interrupts\n",
			 pos->id->compatible, pos->i2c_msg.addr);

		ret = i2c_transfer(client->adapter, &pos->i2c_msg, 1);
		if (ret != 1)
			dev_err(&client->dev, "i2c error %d\n", ret);
	}

	mon = ioread32(irqc + IRQC_MONITOR);
	if (mon & REGULATOR_IRQ_MASK)
		goto remove;

	return 0;

remove:
	dev_info(dev, "IRQ2 is not asserted, removing quirk\n");

	list_for_each_entry_safe(pos, tmp, &quirk_list, list) {
		list_del(&pos->list);
		of_node_put(pos->np);
		kfree(pos);
	}

	done = true;
	iounmap(irqc);
	return 0;
}

static struct notifier_block regulator_quirk_nb = {
	.notifier_call = regulator_quirk_notify
};

static int __init rcar_gen2_regulator_quirk(void)
{
	struct regulator_quirk *quirk, *pos, *tmp;
	struct of_phandle_args *argsa, *argsb;
	const struct of_device_id *id;
	struct device_node *np;
	u32 mon, addr;
	int ret;

	if (!of_machine_is_compatible("renesas,koelsch") &&
	    !of_machine_is_compatible("renesas,lager") &&
	    !of_machine_is_compatible("renesas,porter") &&
	    !of_machine_is_compatible("renesas,stout") &&
	    !of_machine_is_compatible("renesas,gose"))
		return -ENODEV;

	for_each_matching_node_and_match(np, rcar_gen2_quirk_match, &id) {
		if (!of_device_is_available(np)) {
			of_node_put(np);
			break;
		}

		ret = of_property_read_u32(np, "reg", &addr);
		if (ret)	/* Skip invalid entry and continue */
			continue;

		quirk = kzalloc(sizeof(*quirk), GFP_KERNEL);
		if (!quirk) {
			ret = -ENOMEM;
			of_node_put(np);
			goto err_mem;
		}

		argsa = &quirk->irq_args;
		memcpy(&quirk->i2c_msg, id->data, sizeof(quirk->i2c_msg));

		quirk->id = id;
		quirk->np = of_node_get(np);
		quirk->i2c_msg.addr = addr;

		ret = of_irq_parse_one(np, 0, argsa);
		if (ret) {	/* Skip invalid entry and continue */
			of_node_put(np);
			kfree(quirk);
			continue;
		}

		list_for_each_entry(pos, &quirk_list, list) {
			argsb = &pos->irq_args;

			if (argsa->args_count != argsb->args_count)
				continue;

			ret = memcmp(argsa->args, argsb->args,
				     argsa->args_count *
				     sizeof(argsa->args[0]));
			if (!ret) {
				pos->shared = true;
				quirk->shared = true;
			}
		}

		list_add_tail(&quirk->list, &quirk_list);
	}

	irqc = ioremap(IRQC_BASE, PAGE_SIZE);
	if (!irqc) {
		ret = -ENOMEM;
		goto err_mem;
	}

	mon = ioread32(irqc + IRQC_MONITOR);
	if (mon & REGULATOR_IRQ_MASK) {
		pr_debug("%s: IRQ2 is not asserted, not installing quirk\n",
			 __func__);
		ret = 0;
		goto err_free;
	}

	pr_info("IRQ2 is asserted, installing regulator quirk\n");

	bus_register_notifier(&i2c_bus_type, &regulator_quirk_nb);
	return 0;

err_free:
	iounmap(irqc);
err_mem:
	list_for_each_entry_safe(pos, tmp, &quirk_list, list) {
		list_del(&pos->list);
		of_node_put(pos->np);
		kfree(pos);
	}

	return ret;
}

arch_initcall(rcar_gen2_regulator_quirk);


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * Emma Mobile EV2 processor support
 *
 * Copyright (C) 2012  Magnus Damm
 */
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>

#include "common.h"
#include "emev2.h"

static const char *const emev2_boards_compat_dt[] __initconst = {
	"renesas,emev2",
	NULL
};

DT_MACHINE_START(EMEV2_DT, "Generic Emma Mobile EV2 (Flattened Device Tree)")
	.smp		= smp_ops(emev2_smp_ops),
	.init_early	= shmobile_init_delay,
	.init_late	= shmobile_init_late,
	.dt_compat	= emev2_boards_compat_dt,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * r7s72100 processor support
 *
 * Copyright (C) 2013  Renesas Solutions Corp.
 * Copyright (C) 2013  Magnus Damm
 */

#include <linux/kernel.h>

#include <asm/mach/arch.h>

#include "common.h"

static const char *const r7s72100_boards_compat_dt[] __initconst = {
	"renesas,r7s72100",
	NULL
};

DT_MACHINE_START(R7S72100_DT, "Generic R7S72100 (Flattened Device Tree)")
	.l2c_aux_val    = 0,
	.l2c_aux_mask   = ~0,
	.init_early	= shmobile_init_delay,
	.init_late	= shmobile_init_late,
	.dt_compat	= r7s72100_boards_compat_dt,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * r7s9210 processor support
 *
 * Copyright (C) 2018  Renesas Electronics Corporation
 * Copyright (C) 2018  Chris Brandt
 *
 */

#include <linux/kernel.h>

#include <asm/mach/arch.h>

#include "common.h"

static const char *const r7s9210_boards_compat_dt[] __initconst = {
	"renesas,r7s9210",
	NULL
};

DT_MACHINE_START(R7S72100_DT, "Generic R7S9210 (Flattened Device Tree)")
	.l2c_aux_val    = 0,
	.l2c_aux_mask   = ~0,
	.init_early	= shmobile_init_delay,
	.init_late	= shmobile_init_late,
	.dt_compat	= r7s9210_boards_compat_dt,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * r8a73a4 processor support
 *
 * Copyright (C) 2013  Renesas Solutions Corp.
 * Copyright (C) 2013  Magnus Damm
 */

#include <linux/init.h>

#include <asm/mach/arch.h>

#include "common.h"

static const char *const r8a73a4_boards_compat_dt[] __initconst = {
	"renesas,r8a73a4",
	NULL
};

DT_MACHINE_START(R8A73A4_DT, "Generic R8A73A4 (Flattened Device Tree)")
	.init_late	= shmobile_init_late,
	.dt_compat	= r8a73a4_boards_compat_dt,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * R8A7740 processor support
 *
 * Copyright (C) 2011  Renesas Solutions Corp.
 * Copyright (C) 2011  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
 */
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/irqchip.h>
#include <linux/irqchip/arm-gic.h>

#include <asm/mach/map.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>

#include "common.h"

/*
 * r8a7740 chip has lasting errata on MERAM buffer.
 * this is work-around for it.
 * see
 *	"Media RAM (MERAM)" on r8a7740 documentation
 */
#define MEBUFCNTR	0xFE950098
static void __init r8a7740_meram_workaround(void)
{
	void __iomem *reg;

	reg = ioremap(MEBUFCNTR, 4);
	if (reg) {
		iowrite32(0x01600164, reg);
		iounmap(reg);
	}
}

static void __init r8a7740_init_irq_of(void)
{
	void __iomem *intc_prio_base = ioremap(0xe6900010, 0x10);
	void __iomem *intc_msk_base = ioremap(0xe6900040, 0x10);
	void __iomem *pfc_inta_ctrl = ioremap(0xe605807c, 0x4);

	irqchip_init();

	/* route signals to GIC */
	iowrite32(0x0, pfc_inta_ctrl);

	/*
	 * To mask the shared interrupt to SPI 149 we must ensure to set
	 * PRIO *and* MASK. Else we run into IRQ floods when registering
	 * the intc_irqpin devices
	 */
	iowrite32(0x0, intc_prio_base + 0x0);
	iowrite32(0x0, intc_prio_base + 0x4);
	iowrite32(0x0, intc_prio_base + 0x8);
	iowrite32(0x0, intc_prio_base + 0xc);
	iowrite8(0xff, intc_msk_base + 0x0);
	iowrite8(0xff, intc_msk_base + 0x4);
	iowrite8(0xff, intc_msk_base + 0x8);
	iowrite8(0xff, intc_msk_base + 0xc);

	iounmap(intc_prio_base);
	iounmap(intc_msk_base);
	iounmap(pfc_inta_ctrl);
}

static void __init r8a7740_generic_init(void)
{
	r8a7740_meram_workaround();
}

static const char *const r8a7740_boards_compat_dt[] __initconst = {
	"renesas,r8a7740",
	NULL
};

DT_MACHINE_START(R8A7740_DT, "Generic R8A7740 (Flattened Device Tree)")
	.l2c_aux_val	= 0,
	.l2c_aux_mask	= ~0,
	.init_early	= shmobile_init_delay,
	.init_irq	= r8a7740_init_irq_of,
	.init_machine	= r8a7740_generic_init,
	.init_late	= shmobile_init_late,
	.dt_compat	= r8a7740_boards_compat_dt,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * r8a7778 processor support
 *
 * Copyright (C) 2013  Renesas Solutions Corp.
 * Copyright (C) 2013  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
 * Copyright (C) 2013  Cogent Embedded, Inc.
 */

#include <linux/io.h>
#include <linux/irqchip.h>

#include <asm/mach/arch.h>

#include "common.h"

#define HPBREG_BASE	0xfe700000

#define INT2SMSKCR0	0x82288 /* 0xfe782288 */
#define INT2SMSKCR1	0x8228c /* 0xfe78228c */

#define INT2NTSR0	0x00018 /* 0xfe700018 */
#define INT2NTSR1	0x0002c /* 0xfe70002c */

static void __init r8a7778_init_irq_dt(void)
{
	void __iomem *base = ioremap(HPBREG_BASE, 0x00100000);

	BUG_ON(!base);

	irqchip_init();

	/* route all interrupts to ARM */
	writel(0x73ffffff, base + INT2NTSR0);
	writel(0xffffffff, base + INT2NTSR1);

	/* unmask all known interrupts in INTCS2 */
	writel(0x08330773, base + INT2SMSKCR0);
	writel(0x00311110, base + INT2SMSKCR1);

	iounmap(base);
}

static const char *const r8a7778_compat_dt[] __initconst = {
	"renesas,r8a7778",
	NULL
};

DT_MACHINE_START(R8A7778_DT, "Generic R8A7778 (Flattened Device Tree)")
	.init_early	= shmobile_init_delay,
	.init_irq	= r8a7778_init_irq_dt,
	.init_late	= shmobile_init_late,
	.dt_compat	= r8a7778_compat_dt,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * r8a7779 processor support
 *
 * Copyright (C) 2011, 2013  Renesas Solutions Corp.
 * Copyright (C) 2011  Magnus Damm
 * Copyright (C) 2013  Cogent Embedded, Inc.
 */
#include <linux/init.h>
#include <linux/irqchip.h>

#include <asm/mach/arch.h>
#include <asm/mach/map.h>

#include "common.h"
#include "r8a7779.h"

#define HPBREG_BASE	0xfe700000

/* IRQ */
#define INT2SMSKCR0	0x822a0	/* Interrupt Submask Clear Register 0 */
#define INT2SMSKCR1	0x822a4	/* Interrupt Submask Clear Register 1 */
#define INT2SMSKCR2	0x822a8	/* Interrupt Submask Clear Register 2 */
#define INT2SMSKCR3	0x822ac	/* Interrupt Submask Clear Register 3 */
#define INT2SMSKCR4	0x822b0	/* Interrupt Submask Clear Register 4 */

#define INT2NTSR0	0x00060	/* Interrupt Notification Select Register 0 */
#define INT2NTSR1	0x00064	/* Interrupt Notification Select Register 1 */

static void __init r8a7779_init_irq_dt(void)
{
	void __iomem *base = ioremap(HPBREG_BASE, 0x00100000);

	irqchip_init();

	/* route all interrupts to ARM */
	writel(0xffffffff, base + INT2NTSR0);
	writel(0x3fffffff, base + INT2NTSR1);

	/* unmask all known interrupts in INTCS2 */
	writel(0xfffffff0, base + INT2SMSKCR0);
	writel(0xfff7ffff, base + INT2SMSKCR1);
	writel(0xfffbffdf, base + INT2SMSKCR2);
	writel(0xbffffffc, base + INT2SMSKCR3);
	writel(0x003fee3f, base + INT2SMSKCR4);

	iounmap(base);
}

static const char *const r8a7779_compat_dt[] __initconst = {
	"renesas,r8a7779",
	NULL
};

DT_MACHINE_START(R8A7779_DT, "Generic R8A7779 (Flattened Device Tree)")
	.smp		= smp_ops(r8a7779_smp_ops),
	.init_irq	= r8a7779_init_irq_dt,
	.init_late	= shmobile_init_late,
	.dt_compat	= r8a7779_compat_dt,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * R-Car Generation 2 support
 *
 * Copyright (C) 2013  Renesas Solutions Corp.
 * Copyright (C) 2013  Magnus Damm
 * Copyright (C) 2014  Ulrich Hecht
 */

#include <linux/clocksource.h>
#include <linux/device.h>
#include <linux/dma-map-ops.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/memblock.h>
#include <linux/of.h>
#include <linux/of_clk.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
#include <linux/psci.h>
#include <asm/mach/arch.h>
#include <asm/secure_cntvoff.h>
#include "common.h"
#include "rcar-gen2.h"

static const struct of_device_id cpg_matches[] __initconst = {
	{ .compatible = "renesas,r8a7742-cpg-mssr", .data = "extal" },
	{ .compatible = "renesas,r8a7743-cpg-mssr", .data = "extal" },
	{ .compatible = "renesas,r8a7744-cpg-mssr", .data = "extal" },
	{ .compatible = "renesas,r8a7790-cpg-mssr", .data = "extal" },
	{ .compatible = "renesas,r8a7791-cpg-mssr", .data = "extal" },
	{ .compatible = "renesas,r8a7793-cpg-mssr", .data = "extal" },
	{ /* sentinel */ }
};

static unsigned int __init get_extal_freq(void)
{
	const struct of_device_id *match;
	struct device_node *cpg, *extal;
	u32 freq = 20000000;
	int idx = 0;

	cpg = of_find_matching_node_and_match(NULL, cpg_matches, &match);
	if (!cpg)
		return freq;

	if (match->data)
		idx = of_property_match_string(cpg, "clock-names", match->data);
	extal = of_parse_phandle(cpg, "clocks", idx);
	of_node_put(cpg);
	if (!extal)
		return freq;

	of_property_read_u32(extal, "clock-frequency", &freq);
	of_node_put(extal);
	return freq;
}

#define CNTCR 0
#define CNTFID0 0x20

static void __init rcar_gen2_timer_init(void)
{
	bool need_update = true;
	void __iomem *base;
	u32 freq;

	/*
	 * If PSCI is available then most likely we are running on PSCI-enabled
	 * U-Boot which, we assume, has already taken care of resetting CNTVOFF
	 * and updating counter module before switching to non-secure mode
	 * and we don't need to.
	 */
#ifdef CONFIG_ARM_PSCI_FW
	if (psci_ops.cpu_on)
		need_update = false;
#endif

	if (need_update == false)
		goto skip_update;

	secure_cntvoff_init();

	if (of_machine_is_compatible("renesas,r8a7745") ||
	    of_machine_is_compatible("renesas,r8a77470") ||
	    of_machine_is_compatible("renesas,r8a7792") ||
	    of_machine_is_compatible("renesas,r8a7794")) {
		freq = 260000000 / 8;	/* ZS / 8 */
	} else {
		/* At Linux boot time the r8a7790 arch timer comes up
		 * with the counter disabled. Moreover, it may also report
		 * a potentially incorrect fixed 13 MHz frequency. To be
		 * correct these registers need to be updated to use the
		 * frequency EXTAL / 2.
		 */
		freq = get_extal_freq() / 2;
	}

	/* Remap "armgcnt address map" space */
	base = ioremap(0xe6080000, PAGE_SIZE);

	/*
	 * Update the timer if it is either not running, or is not at the
	 * right frequency. The timer is only configurable in secure mode
	 * so this avoids an abort if the loader started the timer and
	 * entered the kernel in non-secure mode.
	 */

	if ((ioread32(base + CNTCR) & 1) == 0 ||
	    ioread32(base + CNTFID0) != freq) {
		/* Update registers with correct frequency */
		iowrite32(freq, base + CNTFID0);
		asm volatile("mcr p15, 0, %0, c14, c0, 0" : : "r" (freq));

		/* make sure arch timer is started by setting bit 0 of CNTCR */
		iowrite32(1, base + CNTCR);
	}

	iounmap(base);

skip_update:
	of_clk_init(NULL);
	timer_probe();
}

struct memory_reserve_config {
	u64 reserved;
	u64 base, size;
};

static int __init rcar_gen2_scan_mem(unsigned long node, const char *uname,
				     int depth, void *data)
{
	const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
	const __be32 *reg, *endp;
	int l;
	struct memory_reserve_config *mrc = data;
	u64 lpae_start = 1ULL << 32;

	/* We are scanning "memory" nodes only */
	if (type == NULL || strcmp(type, "memory"))
		return 0;

	reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
	if (reg == NULL)
		reg = of_get_flat_dt_prop(node, "reg", &l);
	if (reg == NULL)
		return 0;

	endp = reg + (l / sizeof(__be32));
	while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
		u64 base, size;

		base = dt_mem_next_cell(dt_root_addr_cells, &reg);
		size = dt_mem_next_cell(dt_root_size_cells, &reg);

		if (base >= lpae_start)
			continue;

		if ((base + size) >= lpae_start)
			size = lpae_start - base;

		if (size < mrc->reserved)
			continue;

		if (base < mrc->base)
			continue;

		/* keep the area at top near the 32-bit legacy limit */
		mrc->base = base + size - mrc->reserved;
		mrc->size = mrc->reserved;
	}

	return 0;
}

static void __init rcar_gen2_reserve(void)
{
	struct memory_reserve_config mrc;

	/* reserve 256 MiB at the top of the physical legacy 32-bit space */
	memset(&mrc, 0, sizeof(mrc));
	mrc.reserved = SZ_256M;

	of_scan_flat_dt(rcar_gen2_scan_mem, &mrc);
#ifdef CONFIG_DMA_CMA
	if (mrc.size && memblock_is_region_memory(mrc.base, mrc.size)) {
		static struct cma *rcar_gen2_dma_contiguous;

		dma_contiguous_reserve_area(mrc.size, mrc.base, 0,
					    &rcar_gen2_dma_contiguous, true);
	}
#endif
}

static const char * const rcar_gen2_boards_compat_dt[] __initconst = {
	"renesas,r8a7790",
	"renesas,r8a7791",
	"renesas,r8a7792",
	"renesas,r8a7793",
	"renesas,r8a7794",
	NULL
};

DT_MACHINE_START(RCAR_GEN2_DT, "Generic R-Car Gen2 (Flattened Device Tree)")
	.init_late	= shmobile_init_late,
	.init_time	= rcar_gen2_timer_init,
	.reserve	= rcar_gen2_reserve,
	.dt_compat	= rcar_gen2_boards_compat_dt,
MACHINE_END

static const char * const rz_g1_boards_compat_dt[] __initconst = {
	"renesas,r8a7742",
	"renesas,r8a7743",
	"renesas,r8a7744",
	"renesas,r8a7745",
	"renesas,r8a77470",
	NULL
};

DT_MACHINE_START(RZ_G1_DT, "Generic RZ/G1 (Flattened Device Tree)")
	.init_late	= shmobile_init_late,
	.init_time	= rcar_gen2_timer_init,
	.reserve	= rcar_gen2_reserve,
	.dt_compat	= rz_g1_boards_compat_dt,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * sh73a0 processor support
 *
 * Copyright (C) 2010  Takashi Yoshii
 * Copyright (C) 2010  Magnus Damm
 * Copyright (C) 2008  Yoshihiro Shimoda
 */
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/io.h>

#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/map.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>

#include "common.h"
#include "sh73a0.h"

static void __init sh73a0_generic_init(void)
{
#ifdef CONFIG_CACHE_L2X0
	/* Shared attribute override enable, 64K*8way */
	l2x0_init(ioremap(0xf0100000, PAGE_SIZE), 0x00400000, 0xc20f0fff);
#endif
}

static const char *const sh73a0_boards_compat_dt[] __initconst = {
	"renesas,sh73a0",
	NULL
};

DT_MACHINE_START(SH73A0_DT, "Generic SH73A0 (Flattened Device Tree)")
	.smp		= smp_ops(sh73a0_smp_ops),
	.init_machine	= sh73a0_generic_init,
	.init_late	= shmobile_init_late,
	.dt_compat	= sh73a0_boards_compat_dt,
MACHINE_END


code:
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_SH73A0_H__
#define __ASM_SH73A0_H__

extern const struct smp_operations sh73a0_smp_ops;

#endif /* __ASM_SH73A0_H__ */


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * SMP support for Emma Mobile EV2
 *
 * Copyright (C) 2012  Renesas Solutions Corp.
 * Copyright (C) 2012  Magnus Damm
 */
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <asm/smp_plat.h>
#include <asm/smp_scu.h>

#include "common.h"
#include "emev2.h"

#define EMEV2_SCU_BASE 0x1e000000
#define EMEV2_SMU_BASE 0xe0110000
#define SMU_GENERAL_REG0 0x7c0

static int emev2_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
	arch_send_wakeup_ipi_mask(cpumask_of(cpu_logical_map(cpu)));
	return 0;
}

static void __init emev2_smp_prepare_cpus(unsigned int max_cpus)
{
	void __iomem *smu;

	/* Tell ROM loader about our vector (in headsmp.S) */
	smu = ioremap(EMEV2_SMU_BASE, PAGE_SIZE);
	if (smu) {
		iowrite32(__pa(shmobile_boot_vector), smu + SMU_GENERAL_REG0);
		iounmap(smu);
	}

	/* setup EMEV2 specific SCU bits */
	shmobile_smp_scu_prepare_cpus(EMEV2_SCU_BASE, max_cpus);
}

const struct smp_operations emev2_smp_ops __initconst = {
	.smp_prepare_cpus	= emev2_smp_prepare_cpus,
	.smp_boot_secondary	= emev2_boot_secondary,
};


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * SMP support for R-Mobile / SH-Mobile - r8a7779 portion
 *
 * Copyright (C) 2011  Renesas Solutions Corp.
 * Copyright (C) 2011  Magnus Damm
 */
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/soc/renesas/rcar-sysc.h>

#include <asm/cacheflush.h>
#include <asm/smp_plat.h>
#include <asm/smp_scu.h>

#include "common.h"
#include "r8a7779.h"

#define HPBREG_BASE		0xfe700000
#define AVECR			0x0040	/* ARM Reset Vector Address Register */

#define R8A7779_SCU_BASE	0xf0000000

static int r8a7779_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
	int ret = -EIO;

	cpu = cpu_logical_map(cpu);
	if (cpu)
		ret = rcar_sysc_power_up_cpu(cpu);

	return ret;
}

static void __init r8a7779_smp_prepare_cpus(unsigned int max_cpus)
{
	void __iomem *base = ioremap(HPBREG_BASE, 0x1000);

	/* Map the reset vector (in headsmp-scu.S, headsmp.S) */
	writel(__pa(shmobile_boot_vector), base + AVECR);

	/* setup r8a7779 specific SCU bits */
	shmobile_smp_scu_prepare_cpus(R8A7779_SCU_BASE, max_cpus);

	iounmap(base);
}

#ifdef CONFIG_HOTPLUG_CPU
static int r8a7779_platform_cpu_kill(unsigned int cpu)
{
	int ret = -EIO;

	cpu = cpu_logical_map(cpu);
	if (cpu)
		ret = rcar_sysc_power_down_cpu(cpu);

	return ret ? ret : 1;
}

static int r8a7779_cpu_kill(unsigned int cpu)
{
	if (shmobile_smp_scu_cpu_kill(cpu))
		return r8a7779_platform_cpu_kill(cpu);

	return 0;
}
#endif /* CONFIG_HOTPLUG_CPU */

const struct smp_operations r8a7779_smp_ops  __initconst = {
	.smp_prepare_cpus	= r8a7779_smp_prepare_cpus,
	.smp_boot_secondary	= r8a7779_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
	.cpu_die		= shmobile_smp_scu_cpu_die,
	.cpu_kill		= r8a7779_cpu_kill,
#endif
};


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * SMP support for R-Mobile / SH-Mobile - sh73a0 portion
 *
 * Copyright (C) 2010  Magnus Damm
 * Copyright (C) 2010  Takashi Yoshii
 */
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/io.h>
#include <linux/delay.h>

#include <asm/smp_plat.h>

#include "common.h"
#include "sh73a0.h"

#define CPG_BASE2	0xe6151000
#define WUPCR		0x10	/* System-CPU Wake Up Control Register */
#define SRESCR		0x18	/* System-CPU Software Reset Control Register */
#define PSTR		0x40	/* System-CPU Power Status Register */

#define SYSC_BASE	0xe6180000
#define SBAR		0x20	/* SYS Boot Address Register */

#define AP_BASE		0xe6f10000
#define APARMBAREA	0x20	/* Address Translation Area Register */

#define SH73A0_SCU_BASE 0xf0000000

static int sh73a0_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
	unsigned int lcpu = cpu_logical_map(cpu);
	void __iomem *cpg2 = ioremap(CPG_BASE2, PAGE_SIZE);

	if (((readl(cpg2 + PSTR) >> (4 * lcpu)) & 3) == 3)
		writel(1 << lcpu, cpg2 + WUPCR);	/* wake up */
	else
		writel(1 << lcpu, cpg2 + SRESCR);	/* reset */
	iounmap(cpg2);
	return 0;
}

static void __init sh73a0_smp_prepare_cpus(unsigned int max_cpus)
{
	void __iomem *ap = ioremap(AP_BASE, PAGE_SIZE);
	void __iomem *sysc = ioremap(SYSC_BASE, PAGE_SIZE);

	/* Map the reset vector (in headsmp.S) */
	writel(0, ap + APARMBAREA);      /* 4k */
	writel(__pa(shmobile_boot_vector), sysc + SBAR);
	iounmap(sysc);
	iounmap(ap);

	/* setup sh73a0 specific SCU bits */
	shmobile_smp_scu_prepare_cpus(SH73A0_SCU_BASE, max_cpus);
}

const struct smp_operations sh73a0_smp_ops __initconst = {
	.smp_prepare_cpus	= sh73a0_smp_prepare_cpus,
	.smp_boot_secondary	= sh73a0_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
	.cpu_can_disable	= shmobile_smp_cpu_can_disable,
	.cpu_die		= shmobile_smp_scu_cpu_die,
	.cpu_kill		= shmobile_smp_scu_cpu_kill,
#endif
};


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * Suspend-to-RAM support code for SH-Mobile ARM
 *
 *  Copyright (C) 2011 Magnus Damm
 */

#include <linux/pm.h>
#include <linux/suspend.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/cpu.h>

#include <asm/io.h>
#include <asm/system_misc.h>

#include "common.h"

static int shmobile_suspend_default_enter(suspend_state_t suspend_state)
{
	cpu_do_idle();
	return 0;
}

static int shmobile_suspend_begin(suspend_state_t state)
{
	cpu_idle_poll_ctrl(true);
	return 0;
}

static void shmobile_suspend_end(void)
{
	cpu_idle_poll_ctrl(false);
}

struct platform_suspend_ops shmobile_suspend_ops = {
	.begin		= shmobile_suspend_begin,
	.end		= shmobile_suspend_end,
	.enter		= shmobile_suspend_default_enter,
	.valid		= suspend_valid_only_mem,
};

int __init shmobile_suspend_init(void)
{
	suspend_set_ops(&shmobile_suspend_ops);
	return 0;
}


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * SH-Mobile Timer
 *
 * Copyright (C) 2010  Magnus Damm
 * Copyright (C) 2002 - 2009  Paul Mundt
 */
#include <linux/platform_device.h>
#include <linux/clocksource.h>
#include <linux/delay.h>
#include <linux/of_address.h>

#include "common.h"

void __init shmobile_init_delay(void)
{
	struct device_node *np;
	u32 max_freq = 0;

	for_each_of_cpu_node(np) {
		u32 freq;

		if (!of_property_read_u32(np, "clock-frequency", &freq))
			max_freq = max(max_freq, freq);
	}

	if (!max_freq)
		return;

	/*
	 * Calculate a worst-case loops-per-jiffy value
	 * based on maximum cpu core hz setting and the
	 * __delay() implementation in arch/arm/lib/delay.S.
	 *
	 * This will result in a longer delay than expected
	 * when the cpu core runs on lower frequencies.
	 */

	if (!preset_lpj)
		preset_lpj = max_freq / HZ;
}


code:
# SPDX-License-Identifier: GPL-2.0-only
menuconfig ARCH_INTEL_SOCFPGA
	bool "Altera SOCFPGA family"
	depends on ARCH_MULTI_V7
	select ARCH_HAS_RESET_CONTROLLER
	select ARM_AMBA
	select ARM_GIC
	select CACHE_L2X0
	select DW_APB_TIMER_OF
	select GPIO_PL061 if GPIOLIB
	select HAVE_ARM_SCU
	select HAVE_ARM_TWD if SMP
	select MFD_SYSCON
	select ARM_ERRATA_754322
	select ARM_ERRATA_764369 if SMP
	select ARM_ERRATA_775420
	select PL310_ERRATA_588369
	select PL310_ERRATA_727915
	select PL310_ERRATA_753970 if PL310
	select PL310_ERRATA_769419
	select RESET_CONTROLLER

if ARCH_INTEL_SOCFPGA
config SOCFPGA_SUSPEND
	bool "Suspend to RAM on SOCFPGA"
	help
	  Select this if you want to enable Suspend-to-RAM on SOCFPGA
	  platforms.
endif

path: arch/arm/mach-socfpga/Kconfig


code:
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the linux kernel.
#

obj-y					:= socfpga.o
obj-$(CONFIG_SMP)	+= headsmp.o platsmp.o
obj-$(CONFIG_SOCFPGA_SUSPEND)	+= pm.o self-refresh.o
obj-$(CONFIG_EDAC_ALTERA_L2C)	+= l2_cache.o
obj-$(CONFIG_EDAC_ALTERA_OCRAM)	+= ocram.o

path: arch/arm/mach-socfpga/Makefile


code:
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright 2012 Pavel Machek <pavel@denx.de>
 * Copyright (C) 2012-2015 Altera Corporation
 */

#ifndef __MACH_CORE_H
#define __MACH_CORE_H

#define SOCFPGA_RSTMGR_CTRL	0x04
#define SOCFPGA_RSTMGR_MODMPURST	0x10
#define SOCFPGA_RSTMGR_MODPERRST	0x14
#define SOCFPGA_RSTMGR_BRGMODRST	0x1c

#define SOCFPGA_A10_RSTMGR_CTRL		0xC
#define SOCFPGA_A10_RSTMGR_MODMPURST	0x20

/* System Manager bits */
#define RSTMGR_CTRL_SWCOLDRSTREQ	0x1	/* Cold Reset */
#define RSTMGR_CTRL_SWWARMRSTREQ	0x2	/* Warm Reset */

#define RSTMGR_MPUMODRST_CPU1		0x2     /* CPU1 Reset */

void socfpga_init_l2_ecc(void);
void socfpga_init_ocram_ecc(void);
void socfpga_init_arria10_l2_ecc(void);
void socfpga_init_arria10_ocram_ecc(void);

extern void __iomem *sys_manager_base_addr;
extern void __iomem *rst_manager_base_addr;
extern void __iomem *sdr_ctl_base_addr;

u32 socfpga_sdram_self_refresh(u32 sdr_base);
extern unsigned int socfpga_sdram_self_refresh_sz;

extern char secondary_trampoline[], secondary_trampoline_end[];

extern unsigned long socfpga_cpu1start_addr;

#define SOCFPGA_SCU_VIRT_BASE   0xfee00000

#endif


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 *  Copyright (c) 2003 ARM Limited
 *  Copyright (c) u-boot contributors
 *  Copyright (c) 2012 Pavel Machek <pavel@denx.de>
 */
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/memory.h>
#include <asm/assembler.h>

	.arch	armv7-a
	.arm

ENTRY(secondary_trampoline)
	/* CPU1 will always fetch from 0x0 when it is brought out of reset.
	 * Thus, we can just subtract the PAGE_OFFSET to get the physical
	 * address of &cpu1start_addr. This would not work for platforms
	 * where the physical memory does not start at 0x0.
	*/
ARM_BE8(setend	be)
	adr	r0, 1f
	ldmia	r0, {r1, r2}
	sub	r2, r2, #PAGE_OFFSET
	ldr	r3, [r2]
	ldr	r4, [r3]
ARM_BE8(rev	r4, r4)
	bx	r4

	.align
1:	.long	.
	.long	socfpga_cpu1start_addr
ENTRY(secondary_trampoline_end)


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright Altera Corporation (C) 2016. All rights reserved.
 */
#include <linux/io.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>

#include "core.h"

/* A10 System Manager L2 ECC Control register */
#define A10_MPU_CTRL_L2_ECC_OFST          0x0
#define A10_MPU_CTRL_L2_ECC_EN            BIT(0)

/* A10 System Manager Global IRQ Mask register */
#define A10_SYSMGR_ECC_INTMASK_CLR_OFST   0x98
#define A10_SYSMGR_ECC_INTMASK_CLR_L2     BIT(0)

/* A10 System Manager L2 ECC IRQ Clear register */
#define A10_SYSMGR_MPU_CLEAR_L2_ECC_OFST  0xA8
#define A10_SYSMGR_MPU_CLEAR_L2_ECC       (BIT(31) | BIT(15))

void socfpga_init_l2_ecc(void)
{
	struct device_node *np;
	void __iomem *mapped_l2_edac_addr;

	np = of_find_compatible_node(NULL, NULL, "altr,socfpga-l2-ecc");
	if (!np) {
		pr_err("Unable to find socfpga-l2-ecc in dtb\n");
		return;
	}

	mapped_l2_edac_addr = of_iomap(np, 0);
	of_node_put(np);
	if (!mapped_l2_edac_addr) {
		pr_err("Unable to find L2 ECC mapping in dtb\n");
		return;
	}

	/* Enable ECC */
	writel(0x01, mapped_l2_edac_addr);
	iounmap(mapped_l2_edac_addr);
}

void socfpga_init_arria10_l2_ecc(void)
{
	struct device_node *np;
	void __iomem *mapped_l2_edac_addr;

	/* Find the L2 EDAC device tree node */
	np = of_find_compatible_node(NULL, NULL, "altr,socfpga-a10-l2-ecc");
	if (!np) {
		pr_err("Unable to find socfpga-a10-l2-ecc in dtb\n");
		return;
	}

	mapped_l2_edac_addr = of_iomap(np, 0);
	of_node_put(np);
	if (!mapped_l2_edac_addr) {
		pr_err("Unable to find L2 ECC mapping in dtb\n");
		return;
	}

	if (!sys_manager_base_addr) {
		pr_err("System Manager not mapped for L2 ECC\n");
		goto exit;
	}
	/* Clear any pending IRQs */
	writel(A10_SYSMGR_MPU_CLEAR_L2_ECC, (sys_manager_base_addr +
	       A10_SYSMGR_MPU_CLEAR_L2_ECC_OFST));
	/* Enable ECC */
	writel(A10_SYSMGR_ECC_INTMASK_CLR_L2, sys_manager_base_addr +
	       A10_SYSMGR_ECC_INTMASK_CLR_OFST);
	writel(A10_MPU_CTRL_L2_ECC_EN, mapped_l2_edac_addr +
	       A10_MPU_CTRL_L2_ECC_OFST);
exit:
	iounmap(mapped_l2_edac_addr);
}


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright Altera Corporation (C) 2016. All rights reserved.
 */
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/genalloc.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>

#include "core.h"

#define ALTR_OCRAM_CLEAR_ECC          0x00000018
#define ALTR_OCRAM_ECC_EN             0x00000019

void socfpga_init_ocram_ecc(void)
{
	struct device_node *np;
	void __iomem *mapped_ocr_edac_addr;

	/* Find the OCRAM EDAC device tree node */
	np = of_find_compatible_node(NULL, NULL, "altr,socfpga-ocram-ecc");
	if (!np) {
		pr_err("Unable to find socfpga-ocram-ecc\n");
		return;
	}

	mapped_ocr_edac_addr = of_iomap(np, 0);
	of_node_put(np);
	if (!mapped_ocr_edac_addr) {
		pr_err("Unable to map OCRAM ecc regs.\n");
		return;
	}

	/* Clear any pending OCRAM ECC interrupts, then enable ECC */
	writel(ALTR_OCRAM_CLEAR_ECC, mapped_ocr_edac_addr);
	writel(ALTR_OCRAM_ECC_EN, mapped_ocr_edac_addr);

	iounmap(mapped_ocr_edac_addr);
}

/* Arria10 OCRAM Section */
#define ALTR_A10_ECC_CTRL_OFST          0x08
#define ALTR_A10_OCRAM_ECC_EN_CTL       (BIT(1) | BIT(0))
#define ALTR_A10_ECC_INITA              BIT(16)

#define ALTR_A10_ECC_INITSTAT_OFST      0x0C
#define ALTR_A10_ECC_INITCOMPLETEA      BIT(0)
#define ALTR_A10_ECC_INITCOMPLETEB      BIT(8)

#define ALTR_A10_ECC_ERRINTEN_OFST      0x10
#define ALTR_A10_ECC_SERRINTEN          BIT(0)

#define ALTR_A10_ECC_INTSTAT_OFST       0x20
#define ALTR_A10_ECC_SERRPENA           BIT(0)
#define ALTR_A10_ECC_DERRPENA           BIT(8)
#define ALTR_A10_ECC_ERRPENA_MASK       (ALTR_A10_ECC_SERRPENA | \
					 ALTR_A10_ECC_DERRPENA)
/* ECC Manager Defines */
#define A10_SYSMGR_ECC_INTMASK_SET_OFST   0x94
#define A10_SYSMGR_ECC_INTMASK_CLR_OFST   0x98
#define A10_SYSMGR_ECC_INTMASK_OCRAM      BIT(1)

#define ALTR_A10_ECC_INIT_WATCHDOG_10US   10000

static inline void ecc_set_bits(u32 bit_mask, void __iomem *ioaddr)
{
	u32 value = readl(ioaddr);

	value |= bit_mask;
	writel(value, ioaddr);
}

static inline void ecc_clear_bits(u32 bit_mask, void __iomem *ioaddr)
{
	u32 value = readl(ioaddr);

	value &= ~bit_mask;
	writel(value, ioaddr);
}

static inline int ecc_test_bits(u32 bit_mask, void __iomem *ioaddr)
{
	u32 value = readl(ioaddr);

	return (value & bit_mask) ? 1 : 0;
}

/*
 * This function uses the memory initialization block in the Arria10 ECC
 * controller to initialize/clear the entire memory data and ECC data.
 */
static int altr_init_memory_port(void __iomem *ioaddr)
{
	int limit = ALTR_A10_ECC_INIT_WATCHDOG_10US;

	ecc_set_bits(ALTR_A10_ECC_INITA, (ioaddr + ALTR_A10_ECC_CTRL_OFST));
	while (limit--) {
		if (ecc_test_bits(ALTR_A10_ECC_INITCOMPLETEA,
				  (ioaddr + ALTR_A10_ECC_INITSTAT_OFST)))
			break;
		udelay(1);
	}
	if (limit < 0)
		return -EBUSY;

	/* Clear any pending ECC interrupts */
	writel(ALTR_A10_ECC_ERRPENA_MASK,
	       (ioaddr + ALTR_A10_ECC_INTSTAT_OFST));

	return 0;
}

void socfpga_init_arria10_ocram_ecc(void)
{
	struct device_node *np;
	int ret = 0;
	void __iomem *ecc_block_base;

	if (!sys_manager_base_addr) {
		pr_err("SOCFPGA: sys-mgr is not initialized\n");
		return;
	}

	/* Find the OCRAM EDAC device tree node */
	np = of_find_compatible_node(NULL, NULL, "altr,socfpga-a10-ocram-ecc");
	if (!np) {
		pr_err("Unable to find socfpga-a10-ocram-ecc\n");
		return;
	}

	/* Map the ECC Block */
	ecc_block_base = of_iomap(np, 0);
	of_node_put(np);
	if (!ecc_block_base) {
		pr_err("Unable to map OCRAM ECC block\n");
		return;
	}

	/* Disable ECC */
	writel(ALTR_A10_OCRAM_ECC_EN_CTL,
	       sys_manager_base_addr + A10_SYSMGR_ECC_INTMASK_SET_OFST);
	ecc_clear_bits(ALTR_A10_ECC_SERRINTEN,
		       (ecc_block_base + ALTR_A10_ECC_ERRINTEN_OFST));
	ecc_clear_bits(ALTR_A10_OCRAM_ECC_EN_CTL,
		       (ecc_block_base + ALTR_A10_ECC_CTRL_OFST));

	/* Ensure all writes complete */
	wmb();

	/* Use HW initialization block to initialize memory for ECC */
	ret = altr_init_memory_port(ecc_block_base);
	if (ret) {
		pr_err("ECC: cannot init OCRAM PORTA memory\n");
		goto exit;
	}

	/* Enable ECC */
	ecc_set_bits(ALTR_A10_OCRAM_ECC_EN_CTL,
		     (ecc_block_base + ALTR_A10_ECC_CTRL_OFST));
	ecc_set_bits(ALTR_A10_ECC_SERRINTEN,
		     (ecc_block_base + ALTR_A10_ECC_ERRINTEN_OFST));
	writel(ALTR_A10_OCRAM_ECC_EN_CTL,
	       sys_manager_base_addr + A10_SYSMGR_ECC_INTMASK_CLR_OFST);

	/* Ensure all writes complete */
	wmb();
exit:
	iounmap(ecc_block_base);
}


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright 2010-2011 Calxeda, Inc.
 * Copyright 2012 Pavel Machek <pavel@denx.de>
 * Based on platsmp.c, Copyright (C) 2002 ARM Ltd.
 * Copyright (C) 2012 Altera Corporation
 */
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>

#include <asm/cacheflush.h>
#include <asm/smp_scu.h>
#include <asm/smp_plat.h>

#include "core.h"

static int socfpga_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
	int trampoline_size = secondary_trampoline_end - secondary_trampoline;

	if (socfpga_cpu1start_addr) {
		/* This will put CPU #1 into reset. */
		writel(RSTMGR_MPUMODRST_CPU1,
		       rst_manager_base_addr + SOCFPGA_RSTMGR_MODMPURST);

		memcpy(phys_to_virt(0), secondary_trampoline, trampoline_size);

		writel(__pa_symbol(secondary_startup),
		       sys_manager_base_addr + (socfpga_cpu1start_addr & 0x000000ff));

		flush_cache_all();
		smp_wmb();
		outer_clean_range(0, trampoline_size);

		/* This will release CPU #1 out of reset. */
		writel(0, rst_manager_base_addr + SOCFPGA_RSTMGR_MODMPURST);
	}

	return 0;
}

static int socfpga_a10_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
	int trampoline_size = secondary_trampoline_end - secondary_trampoline;

	if (socfpga_cpu1start_addr) {
		writel(RSTMGR_MPUMODRST_CPU1, rst_manager_base_addr +
		       SOCFPGA_A10_RSTMGR_MODMPURST);
		memcpy(phys_to_virt(0), secondary_trampoline, trampoline_size);

		writel(__pa_symbol(secondary_startup),
		       sys_manager_base_addr + (socfpga_cpu1start_addr & 0x00000fff));

		flush_cache_all();
		smp_wmb();
		outer_clean_range(0, trampoline_size);

		/* This will release CPU #1 out of reset. */
		writel(0, rst_manager_base_addr + SOCFPGA_A10_RSTMGR_MODMPURST);
	}

	return 0;
}

static void __init socfpga_smp_prepare_cpus(unsigned int max_cpus)
{
	struct device_node *np;
	void __iomem *socfpga_scu_base_addr;

	np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
	if (!np) {
		pr_err("%s: missing scu\n", __func__);
		return;
	}

	socfpga_scu_base_addr = of_iomap(np, 0);
	if (!socfpga_scu_base_addr)
		return;
	scu_enable(socfpga_scu_base_addr);
}

#ifdef CONFIG_HOTPLUG_CPU
/*
 * platform-specific code to shutdown a CPU
 *
 * Called with IRQs disabled
 */
static void socfpga_cpu_die(unsigned int cpu)
{
	/* Do WFI. If we wake up early, go back into WFI */
	while (1)
		cpu_do_idle();
}

/*
 * We need a dummy function so that platform_can_cpu_hotplug() knows
 * we support CPU hotplug. However, the function does not need to do
 * anything, because CPUs going offline just do WFI. We could reset
 * the CPUs but it would increase power consumption.
 */
static int socfpga_cpu_kill(unsigned int cpu)
{
	return 1;
}
#endif

static const struct smp_operations socfpga_smp_ops __initconst = {
	.smp_prepare_cpus	= socfpga_smp_prepare_cpus,
	.smp_boot_secondary	= socfpga_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
	.cpu_die		= socfpga_cpu_die,
	.cpu_kill		= socfpga_cpu_kill,
#endif
};

static const struct smp_operations socfpga_a10_smp_ops __initconst = {
	.smp_prepare_cpus	= socfpga_smp_prepare_cpus,
	.smp_boot_secondary	= socfpga_a10_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
	.cpu_die		= socfpga_cpu_die,
	.cpu_kill		= socfpga_cpu_kill,
#endif
};

CPU_METHOD_OF_DECLARE(socfpga_smp, "altr,socfpga-smp", &socfpga_smp_ops);
CPU_METHOD_OF_DECLARE(socfpga_a10_smp, "altr,socfpga-a10-smp", &socfpga_a10_smp_ops);


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 *  arch/arm/mach-socfpga/pm.c
 *
 * Copyright (C) 2014-2015 Altera Corporation. All rights reserved.
 *
 * with code from pm-imx6.c
 * Copyright 2011-2014 Freescale Semiconductor, Inc.
 * Copyright 2011 Linaro Ltd.
 */

#include <linux/bitops.h>
#include <linux/genalloc.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/of_platform.h>
#include <linux/suspend.h>
#include <asm/suspend.h>
#include <asm/fncpy.h>
#include "core.h"

/* Pointer to function copied to ocram */
static u32 (*socfpga_sdram_self_refresh_in_ocram)(u32 sdr_base);

static int socfpga_setup_ocram_self_refresh(void)
{
	struct platform_device *pdev;
	phys_addr_t ocram_pbase;
	struct device_node *np;
	struct gen_pool *ocram_pool;
	unsigned long ocram_base;
	void __iomem *suspend_ocram_base;
	int ret = 0;

	np = of_find_compatible_node(NULL, NULL, "mmio-sram");
	if (!np) {
		pr_err("%s: Unable to find mmio-sram in dtb\n", __func__);
		return -ENODEV;
	}

	pdev = of_find_device_by_node(np);
	if (!pdev) {
		pr_warn("%s: failed to find ocram device!\n", __func__);
		ret = -ENODEV;
		goto put_node;
	}

	ocram_pool = gen_pool_get(&pdev->dev, NULL);
	if (!ocram_pool) {
		pr_warn("%s: ocram pool unavailable!\n", __func__);
		ret = -ENODEV;
		goto put_device;
	}

	ocram_base = gen_pool_alloc(ocram_pool, socfpga_sdram_self_refresh_sz);
	if (!ocram_base) {
		pr_warn("%s: unable to alloc ocram!\n", __func__);
		ret = -ENOMEM;
		goto put_device;
	}

	ocram_pbase = gen_pool_virt_to_phys(ocram_pool, ocram_base);

	suspend_ocram_base = __arm_ioremap_exec(ocram_pbase,
						socfpga_sdram_self_refresh_sz,
						false);
	if (!suspend_ocram_base) {
		pr_warn("%s: __arm_ioremap_exec failed!\n", __func__);
		ret = -ENOMEM;
		goto put_device;
	}

	/* Copy the code that puts DDR in self refresh to ocram */
	socfpga_sdram_self_refresh_in_ocram =
		(void *)fncpy(suspend_ocram_base,
			      &socfpga_sdram_self_refresh,
			      socfpga_sdram_self_refresh_sz);

	WARN(!socfpga_sdram_self_refresh_in_ocram,
	     "could not copy function to ocram");
	if (!socfpga_sdram_self_refresh_in_ocram)
		ret = -EFAULT;

put_device:
	put_device(&pdev->dev);
put_node:
	of_node_put(np);

	return ret;
}

static int socfpga_pm_suspend(unsigned long arg)
{
	u32 ret;

	if (!sdr_ctl_base_addr)
		return -EFAULT;

	ret = socfpga_sdram_self_refresh_in_ocram((u32)sdr_ctl_base_addr);

	pr_debug("%s self-refresh loops request=%d exit=%d\n", __func__,
		 ret & 0xffff, (ret >> 16) & 0xffff);

	return 0;
}

static int socfpga_pm_enter(suspend_state_t state)
{
	switch (state) {
	case PM_SUSPEND_MEM:
		outer_disable();
		cpu_suspend(0, socfpga_pm_suspend);
		outer_resume();
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

static const struct platform_suspend_ops socfpga_pm_ops = {
	.valid	= suspend_valid_only_mem,
	.enter	= socfpga_pm_enter,
};

static int __init socfpga_pm_init(void)
{
	int ret;

	ret = socfpga_setup_ocram_self_refresh();
	if (ret)
		return ret;

	suspend_set_ops(&socfpga_pm_ops);
	pr_info("SoCFPGA initialized for DDR self-refresh during suspend.\n");

	return 0;
}
arch_initcall(socfpga_pm_init);


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (C) 2014-2015 Altera Corporation. All rights reserved.
 */
#include <linux/linkage.h>
#include <asm/assembler.h>

#define MAX_LOOP_COUNT		1000

/* Register offset */
#define SDR_CTRLGRP_LOWPWREQ_ADDR       0x54
#define SDR_CTRLGRP_LOWPWRACK_ADDR      0x58

/* Bitfield positions */
#define SELFRSHREQ_POS                  3
#define SELFRSHREQ_MASK                 0x8

#define SELFRFSHACK_POS                 1
#define SELFRFSHACK_MASK                0x2

	/*
	 * This code assumes that when the bootloader configured
	 * the sdram controller for the DDR on the board it
	 * configured the following fields depending on the DDR
	 * vendor/configuration:
	 *
	 * sdr.ctrlcfg.lowpwreq.selfrfshmask
	 * sdr.ctrlcfg.lowpwrtiming.clkdisablecycles
	 * sdr.ctrlcfg.dramtiming4.selfrfshexit
	 */

	.arch   armv7-a
	.text
	.align 3

	/*
	 * socfpga_sdram_self_refresh
	 *
	 *  r0 : sdr_ctl_base_addr
	 *  r1 : temp storage of return value
	 *  r2 : temp storage of register values
	 *  r3 : loop counter
	 *
	 *  return value: lower 16 bits: loop count going into self refresh
	 *                upper 16 bits: loop count exiting self refresh
	 */
ENTRY(socfpga_sdram_self_refresh)
	/* Enable dynamic clock gating in the Power Control Register. */
	mrc	p15, 0, r2, c15, c0, 0
	orr	r2, r2, #1
	mcr	p15, 0, r2, c15, c0, 0

	/* Enable self refresh: set sdr.ctrlgrp.lowpwreq.selfrshreq = 1 */
	ldr	r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR]
	orr	r2, r2, #SELFRSHREQ_MASK
	str	r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR]

	/* Poll until sdr.ctrlgrp.lowpwrack.selfrfshack == 1 or hit max loops */
	mov	r3, #0
while_ack_0:
	ldr	r2, [r0, #SDR_CTRLGRP_LOWPWRACK_ADDR]
	and	r2, r2, #SELFRFSHACK_MASK
	cmp	r2, #SELFRFSHACK_MASK
	beq	ack_1

	add	r3, #1
	cmp	r3, #MAX_LOOP_COUNT
	bne	while_ack_0

ack_1:
	mov	r1, r3

	/*
	 * Execute an ISB instruction to ensure that all of the
	 * CP15 register changes have been committed.
	 */
	isb

	/*
	 * Execute a barrier instruction to ensure that all cache,
	 * TLB and branch predictor maintenance operations issued
	 * by any CPU in the cluster have completed.
	 */
	dsb
	dmb

	wfi

	/* Disable self-refresh: set sdr.ctrlgrp.lowpwreq.selfrshreq = 0 */
	ldr	r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR]
	bic	r2, r2, #SELFRSHREQ_MASK
	str	r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR]

	/* Poll until sdr.ctrlgrp.lowpwrack.selfrfshack == 0 or hit max loops */
	mov	r3, #0
while_ack_1:
	ldr	r2, [r0, #SDR_CTRLGRP_LOWPWRACK_ADDR]
	and	r2, r2, #SELFRFSHACK_MASK
	cmp	r2, #SELFRFSHACK_MASK
	bne	ack_0

	add	r3, #1
	cmp	r3, #MAX_LOOP_COUNT
	bne	while_ack_1

ack_0:
	/*
	 * Prepare return value:
	 * Shift loop count for exiting self refresh into upper 16 bits.
	 * Leave loop count for requesting self refresh in lower 16 bits.
	 */
	mov	r3, r3, lsl #16
	add	r1, r1, r3

	/* Disable dynamic clock gating in the Power Control Register. */
	mrc	p15, 0, r2, c15, c0, 0
	bic	r2, r2, #1
	mcr	p15, 0, r2, c15, c0, 0

	mov     r0, r1                  @ return value
	bx	lr			@ return

ENDPROC(socfpga_sdram_self_refresh)
ENTRY(socfpga_sdram_self_refresh_sz)
	.word	. - socfpga_sdram_self_refresh


code:
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *  Copyright (C) 2012-2015 Altera Corporation
 */
#include <linux/irqchip.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/reboot.h>
#include <linux/reset/socfpga.h>

#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/cacheflush.h>

#include "core.h"

void __iomem *sys_manager_base_addr;
void __iomem *rst_manager_base_addr;
void __iomem *sdr_ctl_base_addr;
unsigned long socfpga_cpu1start_addr;

static void __init socfpga_sysmgr_init(void)
{
	struct device_node *np;

	np = of_find_compatible_node(NULL, NULL, "altr,sys-mgr");

	if (of_property_read_u32(np, "cpu1-start-addr",
			(u32 *) &socfpga_cpu1start_addr))
		pr_err("SMP: Need cpu1-start-addr in device tree.\n");

	/* Ensure that socfpga_cpu1start_addr is visible to other CPUs */
	smp_wmb();
	sync_cache_w(&socfpga_cpu1start_addr);

	sys_manager_base_addr = of_iomap(np, 0);

	np = of_find_compatible_node(NULL, NULL, "altr,rst-mgr");
	rst_manager_base_addr = of_iomap(np, 0);

	np = of_find_compatible_node(NULL, NULL, "altr,sdr-ctl");
	sdr_ctl_base_addr = of_iomap(np, 0);
}

static void __init socfpga_init_irq(void)
{
	irqchip_init();
	socfpga_sysmgr_init();
	if (IS_ENABLED(CONFIG_EDAC_ALTERA_L2C))
		socfpga_init_l2_ecc();

	if (IS_ENABLED(CONFIG_EDAC_ALTERA_OCRAM))
		socfpga_init_ocram_ecc();
	socfpga_reset_init();
}

static void __init socfpga_arria10_init_irq(void)
{
	irqchip_init();
	socfpga_sysmgr_init();
	if (IS_ENABLED(CONFIG_EDAC_ALTERA_L2C))
		socfpga_init_arria10_l2_ecc();
	if (IS_ENABLED(CONFIG_EDAC_ALTERA_OCRAM))
		socfpga_init_arria10_ocram_ecc();
	socfpga_reset_init();
}

static void socfpga_cyclone5_restart(enum reboot_mode mode, const char *cmd)
{
	u32 temp;

	temp = readl(rst_manager_base_addr + SOCFPGA_RSTMGR_CTRL);

	if (mode == REBOOT_WARM)
		temp |= RSTMGR_CTRL_SWWARMRSTREQ;
	else
		temp |= RSTMGR_CTRL_SWCOLDRSTREQ;
	writel(temp, rst_manager_base_addr + SOCFPGA_RSTMGR_CTRL);
}

static void socfpga_arria10_restart(enum reboot_mode mode, const char *cmd)
{
	u32 temp;

	temp = readl(rst_manager_base_addr + SOCFPGA_A10_RSTMGR_CTRL);

	if (mode == REBOOT_WARM)
		temp |= RSTMGR_CTRL_SWWARMRSTREQ;
	else
		temp |= RSTMGR_CTRL_SWCOLDRSTREQ;
	writel(temp, rst_manager_base_addr + SOCFPGA_A10_RSTMGR_CTRL);
}

static const char *altera_dt_match[] = {
	"altr,socfpga",
	NULL
};

DT_MACHINE_START(SOCFPGA, "Altera SOCFPGA")
	.l2c_aux_val	= 0,
	.l2c_aux_mask	= ~0,
	.init_irq	= socfpga_init_irq,
	.restart	= socfpga_cyclone5_restart,
	.dt_compat	= altera_dt_match,
MACHINE_END

static const char *altera_a10_dt_match[] = {
	"altr,socfpga-arria10",
	NULL
};

DT_MACHINE_START(SOCFPGA_A10, "Altera SOCFPGA Arria10")
	.l2c_aux_val	= 0,
	.l2c_aux_mask	= ~0,
	.init_irq	= socfpga_arria10_init_irq,
	.restart	= socfpga_arria10_restart,
	.dt_compat	= altera_a10_dt_match,
MACHINE_END


code:
# SPDX-License-Identifier: GPL-2.0-only
#
# SPEAr Platform configuration file
#

menuconfig PLAT_SPEAR
	bool "ST SPEAr Family"
	depends on ARCH_MULTI_V7 || (ARCH_MULTI_V5 && CPU_LITTLE_ENDIAN)
	select ARM_AMBA
	select CLKSRC_MMIO
	select GPIOLIB

if PLAT_SPEAR

config ARCH_SPEAR13XX
	bool "ST SPEAr13xx"
	depends on ARCH_MULTI_V7
	select ARM_GIC
	select GPIO_SPEAR_SPICS
	select HAVE_ARM_SCU if SMP
	select HAVE_ARM_TWD if SMP
	select PINCTRL
	select MFD_SYSCON
	help
	  Supports for ARM's SPEAR13XX family

if ARCH_SPEAR13XX

config MACH_SPEAR1310
	bool "SPEAr1310 Machine support with Device Tree"
	select PINCTRL_SPEAR1310
	select PHY_ST_SPEAR1310_MIPHY
	help
	  Supports ST SPEAr1310 machine configured via the device-tree

config MACH_SPEAR1340
	bool "SPEAr1340 Machine support with Device Tree"
	select PINCTRL_SPEAR1340
	select PHY_ST_SPEAR1340_MIPHY
	help
	  Supports ST SPEAr1340 machine configured via the device-tree

endif #ARCH_SPEAR13XX

config ARCH_SPEAR3XX
	bool "ST SPEAr3xx"
	depends on ARCH_MULTI_V5
	depends on !ARCH_SPEAR13XX
	select ARM_VIC
	select PINCTRL
	help
	  Supports for ARM's SPEAR3XX family

if ARCH_SPEAR3XX

config MACH_SPEAR300
	bool "SPEAr300 Machine support with Device Tree"
	select PINCTRL_SPEAR300
	help
	  Supports ST SPEAr300 machine configured via the device-tree

config MACH_SPEAR310
	bool "SPEAr310 Machine support with Device Tree"
	select PINCTRL_SPEAR310
	help
	  Supports ST SPEAr310 machine configured via the device-tree

config MACH_SPEAR320
	bool "SPEAr320 Machine support with Device Tree"
	select PINCTRL_SPEAR320
	help
	  Supports ST SPEAr320 machine configured via the device-tree

endif

config ARCH_SPEAR6XX
	bool "ST SPEAr6XX"
	depends on ARCH_MULTI_V5
	depends on !ARCH_SPEAR13XX
	select ARM_VIC
	help
	  Supports for ARM's SPEAR6XX family

config MACH_SPEAR600
	def_bool y
	depends on ARCH_SPEAR6XX
	help
	  Supports ST SPEAr600 boards configured via the device-tree

config ARCH_SPEAR_AUTO
	bool
	depends on !ARCH_SPEAR13XX && !ARCH_SPEAR6XX
	select ARCH_SPEAR3XX

endif

path: arch/arm/mach-spear/Kconfig


code:
# SPDX-License-Identifier: GPL-2.0
#
# SPEAr Platform specific Makefile
#

# Common support
obj-y	:= restart.o time.o

smp-$(CONFIG_SMP)		+= headsmp.o platsmp.o
smp-$(CONFIG_HOTPLUG_CPU)	+= hotplug.o

obj-$(CONFIG_ARCH_SPEAR13XX)	+= spear13xx.o $(smp-y)
obj-$(CONFIG_MACH_SPEAR1310)	+= spear1310.o
obj-$(CONFIG_MACH_SPEAR1340)	+= spear1340.o

obj-$(CONFIG_ARCH_SPEAR3XX)	+= spear3xx.o
obj-$(CONFIG_ARCH_SPEAR3XX)	+= pl080.o
obj-$(CONFIG_MACH_SPEAR300)	+= spear300.o
obj-$(CONFIG_MACH_SPEAR310)	+= spear310.o
obj-$(CONFIG_MACH_SPEAR320)	+= spear320.o

obj-$(CONFIG_ARCH_SPEAR6XX)	+= spear6xx.o
obj-$(CONFIG_ARCH_SPEAR6XX)	+= pl080.o

CFLAGS_hotplug.o		+= -march=armv7-a

path: arch/arm/mach-spear/Makefile


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * spear machine family generic header file
 *
 * Copyright (C) 2009-2012 ST Microelectronics
 * Rajeev Kumar <rajeev-dlh.kumar@st.com>
 * Viresh Kumar <vireshk@kernel.org>
 */

#ifndef __MACH_GENERIC_H
#define __MACH_GENERIC_H

#include <linux/dmaengine.h>
#include <linux/amba/pl08x.h>
#include <linux/init.h>
#include <linux/reboot.h>

#include <asm/mach/time.h>

extern volatile int spear_pen_release;

extern void spear13xx_timer_init(void);
extern void spear3xx_timer_init(void);
extern struct pl022_ssp_controller pl022_plat_data;
extern struct pl08x_platform_data pl080_plat_data;

void __init spear_setup_of_timer(void);
void __init spear3xx_map_io(void);
void __init spear3xx_dt_init_irq(void);
void __init spear13xx_map_io(void);
void __init spear13xx_l2x0_init(void);

void spear_restart(enum reboot_mode, const char *);

void spear13xx_secondary_startup(void);
void spear13xx_cpu_die(unsigned int cpu);

extern const struct smp_operations spear13xx_smp_ops;

#endif /* __MACH_GENERIC_H */


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * arch/arm/mach-spear13XX/headsmp.S
 *
 * Picked from realview
 * Copyright (c) 2012 ST Microelectronics Limited
 * Shiraz Hashim <shiraz.linux.kernel@gmail.com>
 */

#include <linux/linkage.h>
#include <linux/init.h>

	__INIT

/*
 * spear13xx specific entry point for secondary CPUs. This provides
 * a "holding pen" into which all secondary cores are held until we're
 * ready for them to initialise.
 */
ENTRY(spear13xx_secondary_startup)
	mrc	p15, 0, r0, c0, c0, 5
	and	r0, r0, #15
	adr	r4, 1f
	ldmia	r4, {r5, r6}
	sub	r4, r4, r5
	add	r6, r6, r4
pen:	ldr	r7, [r6]
	cmp	r7, r0
	bne	pen

	/* re-enable coherency */
	mrc	p15, 0, r0, c1, c0, 1
	orr	r0, r0, #(1 << 6) | (1 << 0)
	mcr	p15, 0, r0, c1, c0, 1
	/*
	 * we've been released from the holding pen: secondary_stack
	 * should now contain the SVC stack for this core
	 */
	b	secondary_startup

	.align
1:	.long	.
	.long	spear_pen_release
ENDPROC(spear13xx_secondary_startup)


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * linux/arch/arm/mach-spear13xx/hotplug.c
 *
 * Copyright (C) 2012 ST Microelectronics Ltd.
 * Deepak Sikri <deepak.sikri@st.com>
 *
 * based upon linux/arch/arm/mach-realview/hotplug.c
 */
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/smp.h>
#include <asm/cp15.h>
#include <asm/smp_plat.h>

#include "generic.h"

static inline void cpu_enter_lowpower(void)
{
	unsigned int v;

	asm volatile(
	"	mcr	p15, 0, %1, c7, c5, 0\n"
	"	dsb\n"
	/*
	 * Turn off coherency
	 */
	"	mrc	p15, 0, %0, c1, c0, 1\n"
	"	bic	%0, %0, #0x20\n"
	"	mcr	p15, 0, %0, c1, c0, 1\n"
	"	mrc	p15, 0, %0, c1, c0, 0\n"
	"	bic	%0, %0, %2\n"
	"	mcr	p15, 0, %0, c1, c0, 0\n"
	: "=&r" (v)
	: "r" (0), "Ir" (CR_C)
	: "cc", "memory");
}

static inline void cpu_leave_lowpower(void)
{
	unsigned int v;

	asm volatile("mrc	p15, 0, %0, c1, c0, 0\n"
	"	orr	%0, %0, %1\n"
	"	mcr	p15, 0, %0, c1, c0, 0\n"
	"	mrc	p15, 0, %0, c1, c0, 1\n"
	"	orr	%0, %0, #0x20\n"
	"	mcr	p15, 0, %0, c1, c0, 1\n"
	: "=&r" (v)
	: "Ir" (CR_C)
	: "cc");
}

static inline void spear13xx_do_lowpower(unsigned int cpu, int *spurious)
{
	for (;;) {
		wfi();

		if (spear_pen_release == cpu) {
			/*
			 * OK, proper wakeup, we're done
			 */
			break;
		}

		/*
		 * Getting here, means that we have come out of WFI without
		 * having been woken up - this shouldn't happen
		 *
		 * Just note it happening - when we're woken, we can report
		 * its occurrence.
		 */
		(*spurious)++;
	}
}

/*
 * platform-specific code to shutdown a CPU
 *
 * Called with IRQs disabled
 */
void spear13xx_cpu_die(unsigned int cpu)
{
	int spurious = 0;

	/*
	 * we're ready for shutdown now, so do it
	 */
	cpu_enter_lowpower();
	spear13xx_do_lowpower(cpu, &spurious);

	/*
	 * bring this CPU back into the world of cache
	 * coherency, and then restore interrupts
	 */
	cpu_leave_lowpower();

	if (spurious)
		pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
}


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Miscellaneous registers definitions for SPEAr3xx machine family
 *
 * Copyright (C) 2009 ST Microelectronics
 * Viresh Kumar <vireshk@kernel.org>
 */

#ifndef __MACH_MISC_REGS_H
#define __MACH_MISC_REGS_H

#include "spear.h"

#define MISC_BASE		(VA_SPEAR_ICM3_MISC_REG_BASE)
#define DMA_CHN_CFG		(MISC_BASE + 0x0A0)

#endif /* __MACH_MISC_REGS_H */


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * arch/arm/plat-spear/pl080.c
 *
 * DMAC pl080 definitions for SPEAr platform
 *
 * Copyright (C) 2012 ST Microelectronics
 * Viresh Kumar <vireshk@kernel.org>
 */

#include <linux/amba/pl08x.h>
#include <linux/amba/bus.h>
#include <linux/bug.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/spinlock_types.h>
#include "spear.h"
#include "misc_regs.h"

static spinlock_t lock = __SPIN_LOCK_UNLOCKED(x);

struct {
	unsigned char busy;
	unsigned char val;
} signals[16] = {{0, 0}, };

int pl080_get_signal(const struct pl08x_channel_data *cd)
{
	unsigned int signal = cd->min_signal, val;
	unsigned long flags;

	spin_lock_irqsave(&lock, flags);

	/* Return if signal is already acquired by somebody else */
	if (signals[signal].busy &&
			(signals[signal].val != cd->muxval)) {
		spin_unlock_irqrestore(&lock, flags);
		return -EBUSY;
	}

	/* If acquiring for the first time, configure it */
	if (!signals[signal].busy) {
		val = readl(DMA_CHN_CFG);

		/*
		 * Each request line has two bits in DMA_CHN_CFG register. To
		 * goto the bits of current request line, do left shift of
		 * value by 2 * signal number.
		 */
		val &= ~(0x3 << (signal * 2));
		val |= cd->muxval << (signal * 2);
		writel(val, DMA_CHN_CFG);
	}

	signals[signal].busy++;
	signals[signal].val = cd->muxval;
	spin_unlock_irqrestore(&lock, flags);

	return signal;
}

void pl080_put_signal(const struct pl08x_channel_data *cd, int signal)
{
	unsigned long flags;

	spin_lock_irqsave(&lock, flags);

	/* if signal is not used */
	if (!signals[signal].busy)
		BUG();

	signals[signal].busy--;

	spin_unlock_irqrestore(&lock, flags);
}


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * arch/arm/plat-spear/include/plat/pl080.h
 *
 * DMAC pl080 definitions for SPEAr platform
 *
 * Copyright (C) 2012 ST Microelectronics
 * Viresh Kumar <vireshk@kernel.org>
 */

#ifndef __PLAT_PL080_H
#define __PLAT_PL080_H

struct pl08x_channel_data;
int pl080_get_signal(const struct pl08x_channel_data *cd);
void pl080_put_signal(const struct pl08x_channel_data *cd, int signal);

#endif /* __PLAT_PL080_H */


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * arch/arm/mach-spear13xx/platsmp.c
 *
 * based upon linux/arch/arm/mach-realview/platsmp.c
 *
 * Copyright (C) 2012 ST Microelectronics Ltd.
 * Shiraz Hashim <shiraz.linux.kernel@gmail.com>
 */

#include <linux/delay.h>
#include <linux/jiffies.h>
#include <linux/io.h>
#include <linux/smp.h>
#include <asm/cacheflush.h>
#include <asm/smp_scu.h>
#include "spear.h"
#include "generic.h"

/* XXX spear_pen_release is cargo culted code - DO NOT COPY XXX */
volatile int spear_pen_release = -1;

/*
 * XXX CARGO CULTED CODE - DO NOT COPY XXX
 *
 * Write spear_pen_release in a way that is guaranteed to be visible to
 * all observers, irrespective of whether they're taking part in coherency
 * or not.  This is necessary for the hotplug code to work reliably.
 */
static void spear_write_pen_release(int val)
{
	spear_pen_release = val;
	smp_wmb();
	sync_cache_w(&spear_pen_release);
}

static DEFINE_SPINLOCK(boot_lock);

static void __iomem *scu_base = IOMEM(VA_SCU_BASE);

static void spear13xx_secondary_init(unsigned int cpu)
{
	/*
	 * let the primary processor know we're out of the
	 * pen, then head off into the C entry point
	 */
	spear_write_pen_release(-1);

	/*
	 * Synchronise with the boot thread.
	 */
	spin_lock(&boot_lock);
	spin_unlock(&boot_lock);
}

static int spear13xx_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
	unsigned long timeout;

	/*
	 * set synchronisation state between this boot processor
	 * and the secondary one
	 */
	spin_lock(&boot_lock);

	/*
	 * The secondary processor is waiting to be released from
	 * the holding pen - release it, then wait for it to flag
	 * that it has been released by resetting spear_pen_release.
	 *
	 * Note that "spear_pen_release" is the hardware CPU ID, whereas
	 * "cpu" is Linux's internal ID.
	 */
	spear_write_pen_release(cpu);

	timeout = jiffies + (1 * HZ);
	while (time_before(jiffies, timeout)) {
		smp_rmb();
		if (spear_pen_release == -1)
			break;

		udelay(10);
	}

	/*
	 * now the secondary core is starting up let it run its
	 * calibrations, then wait for it to finish
	 */
	spin_unlock(&boot_lock);

	return spear_pen_release != -1 ? -ENOSYS : 0;
}

/*
 * Initialise the CPU possible map early - this describes the CPUs
 * which may be present or become present in the system.
 */
static void __init spear13xx_smp_init_cpus(void)
{
	unsigned int i, ncores = scu_get_core_count(scu_base);

	if (ncores > nr_cpu_ids) {
		pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
			ncores, nr_cpu_ids);
		ncores = nr_cpu_ids;
	}

	for (i = 0; i < ncores; i++)
		set_cpu_possible(i, true);
}

static void __init spear13xx_smp_prepare_cpus(unsigned int max_cpus)
{

	scu_enable(scu_base);

	/*
	 * Write the address of secondary startup into the system-wide location
	 * (presently it is in SRAM). The BootMonitor waits until it receives a
	 * soft interrupt, and then the secondary CPU branches to this address.
	 */
	__raw_writel(__pa_symbol(spear13xx_secondary_startup), SYS_LOCATION);
}

const struct smp_operations spear13xx_smp_ops __initconst = {
       .smp_init_cpus		= spear13xx_smp_init_cpus,
       .smp_prepare_cpus	= spear13xx_smp_prepare_cpus,
       .smp_secondary_init	= spear13xx_secondary_init,
       .smp_boot_secondary	= spear13xx_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
       .cpu_die			= spear13xx_cpu_die,
#endif
};


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * arch/arm/plat-spear/restart.c
 *
 * SPEAr platform specific restart functions
 *
 * Copyright (C) 2009 ST Microelectronics
 * Viresh Kumar <vireshk@kernel.org>
 */
#include <linux/io.h>
#include <linux/amba/sp810.h>
#include <linux/reboot.h>
#include <asm/system_misc.h>
#include "spear.h"
#include "generic.h"

#define SPEAR13XX_SYS_SW_RES			(VA_MISC_BASE + 0x204)
void spear_restart(enum reboot_mode mode, const char *cmd)
{
	if (mode == REBOOT_SOFT) {
		/* software reset, Jump into ROM at address 0 */
		soft_restart(0);
	} else {
		/* hardware reset, Use on-chip reset capability */
#ifdef CONFIG_ARCH_SPEAR13XX
		writel_relaxed(0x01, SPEAR13XX_SYS_SW_RES);
#endif
#if defined(CONFIG_ARCH_SPEAR3XX) || defined(CONFIG_ARCH_SPEAR6XX)
		sysctl_soft_reset((void __iomem *)VA_SPEAR_SYS_CTRL_BASE);
#endif
	}
}


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * SPEAr3xx/6xx Machine family specific definition
 *
 * Copyright (C) 2009,2012 ST Microelectronics
 * Rajeev Kumar<rajeev-dlh.kumar@st.com>
 * Viresh Kumar <vireshk@kernel.org>
 */

#ifndef __MACH_SPEAR_H
#define __MACH_SPEAR_H

#include <asm/memory.h>

#if defined(CONFIG_ARCH_SPEAR3XX) || defined (CONFIG_ARCH_SPEAR6XX)

/* ICM1 - Low speed connection */
#define SPEAR_ICM1_2_BASE		UL(0xD0000000)
#define VA_SPEAR_ICM1_2_BASE		IOMEM(0xFD000000)
#define SPEAR_ICM1_UART_BASE		UL(0xD0000000)
#define VA_SPEAR_ICM1_UART_BASE		(VA_SPEAR_ICM1_2_BASE - SPEAR_ICM1_2_BASE + SPEAR_ICM1_UART_BASE)
#define SPEAR3XX_ICM1_SSP_BASE		UL(0xD0100000)

/* ML-1, 2 - Multi Layer CPU Subsystem */
#define SPEAR_ICM3_ML1_2_BASE		UL(0xF0000000)
#define VA_SPEAR6XX_ML_CPU_BASE		IOMEM(0xF0000000)

/* ICM3 - Basic Subsystem */
#define SPEAR_ICM3_SMI_CTRL_BASE	UL(0xFC000000)
#define VA_SPEAR_ICM3_SMI_CTRL_BASE	IOMEM(0xFC000000)
#define SPEAR_ICM3_DMA_BASE		UL(0xFC400000)
#define SPEAR_ICM3_SYS_CTRL_BASE	UL(0xFCA00000)
#define VA_SPEAR_ICM3_SYS_CTRL_BASE	(VA_SPEAR_ICM3_SMI_CTRL_BASE - SPEAR_ICM3_SMI_CTRL_BASE + SPEAR_ICM3_SYS_CTRL_BASE)
#define SPEAR_ICM3_MISC_REG_BASE	UL(0xFCA80000)
#define VA_SPEAR_ICM3_MISC_REG_BASE	(VA_SPEAR_ICM3_SMI_CTRL_BASE - SPEAR_ICM3_SMI_CTRL_BASE + SPEAR_ICM3_MISC_REG_BASE)

/* Debug uart for linux, will be used for debug and uncompress messages */
#define SPEAR_DBG_UART_BASE		SPEAR_ICM1_UART_BASE

/* Sysctl base for spear platform */
#define SPEAR_SYS_CTRL_BASE		SPEAR_ICM3_SYS_CTRL_BASE
#define VA_SPEAR_SYS_CTRL_BASE		VA_SPEAR_ICM3_SYS_CTRL_BASE
#endif /* SPEAR3xx || SPEAR6XX */

/* SPEAr320 Macros */
#define SPEAR320_SOC_CONFIG_BASE	UL(0xB3000000)
#define VA_SPEAR320_SOC_CONFIG_BASE	IOMEM(0xFE000000)

#ifdef CONFIG_ARCH_SPEAR13XX

#define PERIP_GRP2_BASE				UL(0xB3000000)
#define VA_PERIP_GRP2_BASE			IOMEM(0xF9000000)
#define MCIF_SDHCI_BASE				UL(0xB3000000)
#define SYSRAM0_BASE				UL(0xB3800000)
#define VA_SYSRAM0_BASE				IOMEM(0xF9800000)
#define SYS_LOCATION				(VA_SYSRAM0_BASE + 0x600)

#define PERIP_GRP1_BASE				UL(0xE0000000)
#define VA_PERIP_GRP1_BASE			IOMEM(0xFD000000)
#define UART_BASE				UL(0xE0000000)
#define VA_UART_BASE				IOMEM(0xFD000000)
#define SSP_BASE				UL(0xE0100000)
#define MISC_BASE				UL(0xE0700000)
#define VA_MISC_BASE				IOMEM(0xFD700000)

#define A9SM_AND_MPMC_BASE			UL(0xEC000000)
#define VA_A9SM_AND_MPMC_BASE			IOMEM(0xFC000000)

#define SPEAR1310_RAS_BASE			UL(0xD8400000)
#define VA_SPEAR1310_RAS_BASE			IOMEM(UL(0xFA400000))

/* A9SM peripheral offsets */
#define A9SM_PERIP_BASE				UL(0xEC800000)
#define VA_A9SM_PERIP_BASE			IOMEM(0xFC800000)
#define VA_SCU_BASE				(VA_A9SM_PERIP_BASE + 0x00)

#define L2CC_BASE				UL(0xED000000)
#define VA_L2CC_BASE				IOMEM(UL(0xFB000000))

/* others */
#define MCIF_CF_BASE				UL(0xB2800000)

/* Debug uart for linux, will be used for debug and uncompress messages */
#define SPEAR_DBG_UART_BASE			UART_BASE

#endif /* SPEAR13XX */

#endif /* __MACH_SPEAR_H */


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * arch/arm/mach-spear13xx/spear1310.c
 *
 * SPEAr1310 machine source file
 *
 * Copyright (C) 2012 ST Microelectronics
 * Viresh Kumar <vireshk@kernel.org>
 */

#define pr_fmt(fmt) "SPEAr1310: " fmt

#include <linux/amba/pl022.h>
#include <linux/pata_arasan_cf_data.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include "generic.h"
#include "spear.h"

/* Base addresses */
#define SPEAR1310_RAS_GRP1_BASE			UL(0xD8000000)
#define VA_SPEAR1310_RAS_GRP1_BASE		UL(0xFA000000)

static void __init spear1310_dt_init(void)
{
	platform_device_register_simple("spear-cpufreq", -1, NULL, 0);
}

static const char * const spear1310_dt_board_compat[] = {
	"st,spear1310",
	"st,spear1310-evb",
	NULL,
};

/*
 * Following will create 16MB static virtual/physical mappings
 * PHYSICAL		VIRTUAL
 * 0xD8000000		0xFA000000
 */
static struct map_desc spear1310_io_desc[] __initdata = {
	{
		.virtual	= VA_SPEAR1310_RAS_GRP1_BASE,
		.pfn		= __phys_to_pfn(SPEAR1310_RAS_GRP1_BASE),
		.length		= SZ_16M,
		.type		= MT_DEVICE
	},
};

static void __init spear1310_map_io(void)
{
	iotable_init(spear1310_io_desc, ARRAY_SIZE(spear1310_io_desc));
	spear13xx_map_io();
}

DT_MACHINE_START(SPEAR1310_DT, "ST SPEAr1310 SoC with Flattened Device Tree")
	.smp		=	smp_ops(spear13xx_smp_ops),
	.map_io		=	spear1310_map_io,
	.init_time	=	spear13xx_timer_init,
	.init_machine	=	spear1310_dt_init,
	.restart	=	spear_restart,
	.dt_compat	=	spear1310_dt_board_compat,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * arch/arm/mach-spear13xx/spear1340.c
 *
 * SPEAr1340 machine source file
 *
 * Copyright (C) 2012 ST Microelectronics
 * Viresh Kumar <vireshk@kernel.org>
 */

#define pr_fmt(fmt) "SPEAr1340: " fmt

#include <linux/of_platform.h>
#include <asm/mach/arch.h>
#include "generic.h"

static void __init spear1340_dt_init(void)
{
	platform_device_register_simple("spear-cpufreq", -1, NULL, 0);
}

static const char * const spear1340_dt_board_compat[] = {
	"st,spear1340",
	"st,spear1340-evb",
	NULL,
};

DT_MACHINE_START(SPEAR1340_DT, "ST SPEAr1340 SoC with Flattened Device Tree")
	.smp		=	smp_ops(spear13xx_smp_ops),
	.map_io		=	spear13xx_map_io,
	.init_time	=	spear13xx_timer_init,
	.init_machine	=	spear1340_dt_init,
	.restart	=	spear_restart,
	.dt_compat	=	spear1340_dt_board_compat,
MACHINE_END