162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * (C) Copyright 2009, Texas Instruments, Inc. https://www.ti.com/
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci/* replicated define because linux/bitops.h cannot be included in assembly */
762306a36Sopenharmony_ci#define BIT(nr)			(1 << (nr))
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/linkage.h>
1062306a36Sopenharmony_ci#include <asm/assembler.h>
1162306a36Sopenharmony_ci#include "psc.h"
1262306a36Sopenharmony_ci#include "ddr2.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "clock.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci/* Arbitrary, hardware currently does not update PHYRDY correctly */
1762306a36Sopenharmony_ci#define PHYRDY_CYCLES		0x1000
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/* Assume 25 MHz speed for the cycle conversions since PLLs are bypassed */
2062306a36Sopenharmony_ci#define PLL_BYPASS_CYCLES	(PLL_BYPASS_TIME * 25)
2162306a36Sopenharmony_ci#define PLL_RESET_CYCLES	(PLL_RESET_TIME	* 25)
2262306a36Sopenharmony_ci#define PLL_LOCK_CYCLES		(PLL_LOCK_TIME * 25)
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define DEEPSLEEP_SLEEPENABLE_BIT	BIT(31)
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	.text
2762306a36Sopenharmony_ci	.arch	armv5te
2862306a36Sopenharmony_ci/*
2962306a36Sopenharmony_ci * Move DaVinci into deep sleep state
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci * Note: This code is copied to internal SRAM by PM code. When the DaVinci
3262306a36Sopenharmony_ci *	 wakes up it continues execution at the point it went to sleep.
3362306a36Sopenharmony_ci * Register Usage:
3462306a36Sopenharmony_ci * 	r0: contains virtual base for DDR2 controller
3562306a36Sopenharmony_ci * 	r1: contains virtual base for DDR2 Power and Sleep controller (PSC)
3662306a36Sopenharmony_ci * 	r2: contains PSC number for DDR2
3762306a36Sopenharmony_ci * 	r3: contains virtual base DDR2 PLL controller
3862306a36Sopenharmony_ci * 	r4: contains virtual address of the DEEPSLEEP register
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_ciENTRY(davinci_cpu_suspend)
4162306a36Sopenharmony_ci	stmfd	sp!, {r0-r12, lr}		@ save registers on stack
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	ldr 	ip, CACHE_FLUSH
4462306a36Sopenharmony_ci	blx	ip
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	ldmia	r0, {r0-r4}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	/*
4962306a36Sopenharmony_ci	 * Switch DDR to self-refresh mode.
5062306a36Sopenharmony_ci	 */
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	/* calculate SDRCR address */
5362306a36Sopenharmony_ci	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
5462306a36Sopenharmony_ci	bic	ip, ip, #DDR2_SRPD_BIT
5562306a36Sopenharmony_ci	orr	ip, ip, #DDR2_LPMODEN_BIT
5662306a36Sopenharmony_ci	str	ip, [r0, #DDR2_SDRCR_OFFSET]
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
5962306a36Sopenharmony_ci	orr	ip, ip, #DDR2_MCLKSTOPEN_BIT
6062306a36Sopenharmony_ci	str	ip, [r0, #DDR2_SDRCR_OFFSET]
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci       mov	ip, #PHYRDY_CYCLES
6362306a36Sopenharmony_ci1:     subs	ip, ip, #0x1
6462306a36Sopenharmony_ci       bne	1b
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci       /* Disable DDR2 LPSC */
6762306a36Sopenharmony_ci	mov	r7, r0
6862306a36Sopenharmony_ci	mov	r0, #0x2
6962306a36Sopenharmony_ci	bl davinci_ddr_psc_config
7062306a36Sopenharmony_ci	mov	r0, r7
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	/* Disable clock to DDR PHY */
7362306a36Sopenharmony_ci	ldr	ip, [r3, #PLLDIV1]
7462306a36Sopenharmony_ci	bic	ip, ip, #PLLDIV_EN
7562306a36Sopenharmony_ci	str	ip, [r3, #PLLDIV1]
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	/* Put the DDR PLL in bypass and power down */
7862306a36Sopenharmony_ci	ldr	ip, [r3, #PLLCTL]
7962306a36Sopenharmony_ci	bic	ip, ip, #PLLCTL_PLLENSRC
8062306a36Sopenharmony_ci	bic	ip, ip, #PLLCTL_PLLEN
8162306a36Sopenharmony_ci	str	ip, [r3, #PLLCTL]
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	/* Wait for PLL to switch to bypass */
8462306a36Sopenharmony_ci       mov	ip, #PLL_BYPASS_CYCLES
8562306a36Sopenharmony_ci2:     subs	ip, ip, #0x1
8662306a36Sopenharmony_ci       bne	2b
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci       /* Power down the PLL */
8962306a36Sopenharmony_ci	ldr	ip, [r3, #PLLCTL]
9062306a36Sopenharmony_ci	orr	ip, ip, #PLLCTL_PLLPWRDN
9162306a36Sopenharmony_ci	str	ip, [r3, #PLLCTL]
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	/* Go to deep sleep */
9462306a36Sopenharmony_ci	ldr	ip, [r4]
9562306a36Sopenharmony_ci	orr	ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT
9662306a36Sopenharmony_ci	/* System goes to sleep beyond after this instruction */
9762306a36Sopenharmony_ci	str	ip, [r4]
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	/* Wake up from sleep */
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	/* Clear sleep enable */
10262306a36Sopenharmony_ci	ldr	ip, [r4]
10362306a36Sopenharmony_ci	bic	ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT
10462306a36Sopenharmony_ci	str	ip, [r4]
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	/* initialize the DDR PLL controller */
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/* Put PLL in reset */
10962306a36Sopenharmony_ci	ldr	ip, [r3, #PLLCTL]
11062306a36Sopenharmony_ci	bic	ip, ip, #PLLCTL_PLLRST
11162306a36Sopenharmony_ci	str	ip, [r3, #PLLCTL]
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	/* Clear PLL power down */
11462306a36Sopenharmony_ci	ldr	ip, [r3, #PLLCTL]
11562306a36Sopenharmony_ci	bic	ip, ip, #PLLCTL_PLLPWRDN
11662306a36Sopenharmony_ci	str	ip, [r3, #PLLCTL]
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci       mov	ip, #PLL_RESET_CYCLES
11962306a36Sopenharmony_ci3:     subs	ip, ip, #0x1
12062306a36Sopenharmony_ci       bne	3b
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci       /* Bring PLL out of reset */
12362306a36Sopenharmony_ci	ldr	ip, [r3, #PLLCTL]
12462306a36Sopenharmony_ci	orr	ip, ip, #PLLCTL_PLLRST
12562306a36Sopenharmony_ci	str	ip, [r3, #PLLCTL]
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	/* Wait for PLL to lock (assume prediv = 1, 25MHz OSCIN) */
12862306a36Sopenharmony_ci       mov	ip, #PLL_LOCK_CYCLES
12962306a36Sopenharmony_ci4:     subs	ip, ip, #0x1
13062306a36Sopenharmony_ci       bne	4b
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci       /* Remove PLL from bypass mode */
13362306a36Sopenharmony_ci	ldr	ip, [r3, #PLLCTL]
13462306a36Sopenharmony_ci	bic	ip, ip, #PLLCTL_PLLENSRC
13562306a36Sopenharmony_ci	orr	ip, ip, #PLLCTL_PLLEN
13662306a36Sopenharmony_ci	str	ip, [r3, #PLLCTL]
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	/* Start 2x clock to DDR2 */
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	ldr	ip, [r3, #PLLDIV1]
14162306a36Sopenharmony_ci	orr	ip, ip, #PLLDIV_EN
14262306a36Sopenharmony_ci	str	ip, [r3, #PLLDIV1]
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	/* Enable VCLK */
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci       /* Enable DDR2 LPSC */
14762306a36Sopenharmony_ci	mov	r7, r0
14862306a36Sopenharmony_ci	mov	r0, #0x3
14962306a36Sopenharmony_ci	bl davinci_ddr_psc_config
15062306a36Sopenharmony_ci	mov	r0, r7
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	/* clear  MCLKSTOPEN */
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
15562306a36Sopenharmony_ci	bic	ip, ip, #DDR2_MCLKSTOPEN_BIT
15662306a36Sopenharmony_ci	str	ip, [r0, #DDR2_SDRCR_OFFSET]
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
15962306a36Sopenharmony_ci	bic	ip, ip, #DDR2_LPMODEN_BIT
16062306a36Sopenharmony_ci	str	ip, [r0, #DDR2_SDRCR_OFFSET]
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	/* Restore registers and return */
16362306a36Sopenharmony_ci	ldmfd   sp!, {r0-r12, pc}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ciENDPROC(davinci_cpu_suspend)
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci/*
16862306a36Sopenharmony_ci * Disables or Enables DDR2 LPSC
16962306a36Sopenharmony_ci * Register Usage:
17062306a36Sopenharmony_ci * 	r0: Enable or Disable LPSC r0 = 0x3 => Enable, r0 = 0x2 => Disable LPSC
17162306a36Sopenharmony_ci * 	r1: contains virtual base for DDR2 Power and Sleep controller (PSC)
17262306a36Sopenharmony_ci * 	r2: contains PSC number for DDR2
17362306a36Sopenharmony_ci */
17462306a36Sopenharmony_ciENTRY(davinci_ddr_psc_config)
17562306a36Sopenharmony_ci	/* Set next state in mdctl for DDR2 */
17662306a36Sopenharmony_ci	mov	r6, #MDCTL
17762306a36Sopenharmony_ci	add	r6, r6, r2, lsl #2
17862306a36Sopenharmony_ci	ldr	ip, [r1, r6]
17962306a36Sopenharmony_ci	bic	ip, ip, #MDSTAT_STATE_MASK
18062306a36Sopenharmony_ci	orr	ip, ip, r0
18162306a36Sopenharmony_ci	str	ip, [r1, r6]
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/* Enable the Power Domain Transition Command */
18462306a36Sopenharmony_ci	ldr	ip, [r1, #PTCMD]
18562306a36Sopenharmony_ci	orr	ip, ip, #0x1
18662306a36Sopenharmony_ci	str	ip, [r1, #PTCMD]
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	/* Check for Transition Complete (PTSTAT) */
18962306a36Sopenharmony_ciptstat_done:
19062306a36Sopenharmony_ci	ldr	ip, [r1, #PTSTAT]
19162306a36Sopenharmony_ci	and	ip, ip, #0x1
19262306a36Sopenharmony_ci	cmp 	ip, #0x0
19362306a36Sopenharmony_ci	bne	ptstat_done
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	/* Check for DDR2 clock disable completion; */
19662306a36Sopenharmony_ci	mov	r6, #MDSTAT
19762306a36Sopenharmony_ci	add	r6, r6, r2, lsl #2
19862306a36Sopenharmony_ciddr2clk_stop_done:
19962306a36Sopenharmony_ci	ldr	ip, [r1, r6]
20062306a36Sopenharmony_ci	and	ip, ip, #MDSTAT_STATE_MASK
20162306a36Sopenharmony_ci	cmp	ip, r0
20262306a36Sopenharmony_ci	bne	ddr2clk_stop_done
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	ret	lr
20562306a36Sopenharmony_ciENDPROC(davinci_ddr_psc_config)
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ciCACHE_FLUSH:
20862306a36Sopenharmony_ci#ifdef CONFIG_CPU_V6
20962306a36Sopenharmony_ci	.word	v6_flush_kern_cache_all
21062306a36Sopenharmony_ci#else
21162306a36Sopenharmony_ci	.word   arm926_flush_kern_cache_all
21262306a36Sopenharmony_ci#endif
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ciENTRY(davinci_cpu_suspend_sz)
21562306a36Sopenharmony_ci	.word	. - davinci_cpu_suspend
21662306a36Sopenharmony_ciENDPROC(davinci_cpu_suspend_sz)
217