18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * (C) Copyright 2009, Texas Instruments, Inc. https://www.ti.com/
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci/* replicated define because linux/bitops.h cannot be included in assembly */
78c2ecf20Sopenharmony_ci#define BIT(nr)			(1 << (nr))
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/linkage.h>
108c2ecf20Sopenharmony_ci#include <asm/assembler.h>
118c2ecf20Sopenharmony_ci#include "psc.h"
128c2ecf20Sopenharmony_ci#include "ddr2.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "clock.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci/* Arbitrary, hardware currently does not update PHYRDY correctly */
178c2ecf20Sopenharmony_ci#define PHYRDY_CYCLES		0x1000
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/* Assume 25 MHz speed for the cycle conversions since PLLs are bypassed */
208c2ecf20Sopenharmony_ci#define PLL_BYPASS_CYCLES	(PLL_BYPASS_TIME * 25)
218c2ecf20Sopenharmony_ci#define PLL_RESET_CYCLES	(PLL_RESET_TIME	* 25)
228c2ecf20Sopenharmony_ci#define PLL_LOCK_CYCLES		(PLL_LOCK_TIME * 25)
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define DEEPSLEEP_SLEEPENABLE_BIT	BIT(31)
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	.text
278c2ecf20Sopenharmony_ci	.arch	armv5te
288c2ecf20Sopenharmony_ci/*
298c2ecf20Sopenharmony_ci * Move DaVinci into deep sleep state
308c2ecf20Sopenharmony_ci *
318c2ecf20Sopenharmony_ci * Note: This code is copied to internal SRAM by PM code. When the DaVinci
328c2ecf20Sopenharmony_ci *	 wakes up it continues execution at the point it went to sleep.
338c2ecf20Sopenharmony_ci * Register Usage:
348c2ecf20Sopenharmony_ci * 	r0: contains virtual base for DDR2 controller
358c2ecf20Sopenharmony_ci * 	r1: contains virtual base for DDR2 Power and Sleep controller (PSC)
368c2ecf20Sopenharmony_ci * 	r2: contains PSC number for DDR2
378c2ecf20Sopenharmony_ci * 	r3: contains virtual base DDR2 PLL controller
388c2ecf20Sopenharmony_ci * 	r4: contains virtual address of the DEEPSLEEP register
398c2ecf20Sopenharmony_ci */
408c2ecf20Sopenharmony_ciENTRY(davinci_cpu_suspend)
418c2ecf20Sopenharmony_ci	stmfd	sp!, {r0-r12, lr}		@ save registers on stack
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	ldr 	ip, CACHE_FLUSH
448c2ecf20Sopenharmony_ci	blx	ip
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	ldmia	r0, {r0-r4}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	/*
498c2ecf20Sopenharmony_ci	 * Switch DDR to self-refresh mode.
508c2ecf20Sopenharmony_ci	 */
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	/* calculate SDRCR address */
538c2ecf20Sopenharmony_ci	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
548c2ecf20Sopenharmony_ci	bic	ip, ip, #DDR2_SRPD_BIT
558c2ecf20Sopenharmony_ci	orr	ip, ip, #DDR2_LPMODEN_BIT
568c2ecf20Sopenharmony_ci	str	ip, [r0, #DDR2_SDRCR_OFFSET]
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
598c2ecf20Sopenharmony_ci	orr	ip, ip, #DDR2_MCLKSTOPEN_BIT
608c2ecf20Sopenharmony_ci	str	ip, [r0, #DDR2_SDRCR_OFFSET]
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci       mov	ip, #PHYRDY_CYCLES
638c2ecf20Sopenharmony_ci1:     subs	ip, ip, #0x1
648c2ecf20Sopenharmony_ci       bne	1b
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci       /* Disable DDR2 LPSC */
678c2ecf20Sopenharmony_ci	mov	r7, r0
688c2ecf20Sopenharmony_ci	mov	r0, #0x2
698c2ecf20Sopenharmony_ci	bl davinci_ddr_psc_config
708c2ecf20Sopenharmony_ci	mov	r0, r7
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	/* Disable clock to DDR PHY */
738c2ecf20Sopenharmony_ci	ldr	ip, [r3, #PLLDIV1]
748c2ecf20Sopenharmony_ci	bic	ip, ip, #PLLDIV_EN
758c2ecf20Sopenharmony_ci	str	ip, [r3, #PLLDIV1]
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	/* Put the DDR PLL in bypass and power down */
788c2ecf20Sopenharmony_ci	ldr	ip, [r3, #PLLCTL]
798c2ecf20Sopenharmony_ci	bic	ip, ip, #PLLCTL_PLLENSRC
808c2ecf20Sopenharmony_ci	bic	ip, ip, #PLLCTL_PLLEN
818c2ecf20Sopenharmony_ci	str	ip, [r3, #PLLCTL]
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	/* Wait for PLL to switch to bypass */
848c2ecf20Sopenharmony_ci       mov	ip, #PLL_BYPASS_CYCLES
858c2ecf20Sopenharmony_ci2:     subs	ip, ip, #0x1
868c2ecf20Sopenharmony_ci       bne	2b
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci       /* Power down the PLL */
898c2ecf20Sopenharmony_ci	ldr	ip, [r3, #PLLCTL]
908c2ecf20Sopenharmony_ci	orr	ip, ip, #PLLCTL_PLLPWRDN
918c2ecf20Sopenharmony_ci	str	ip, [r3, #PLLCTL]
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	/* Go to deep sleep */
948c2ecf20Sopenharmony_ci	ldr	ip, [r4]
958c2ecf20Sopenharmony_ci	orr	ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT
968c2ecf20Sopenharmony_ci	/* System goes to sleep beyond after this instruction */
978c2ecf20Sopenharmony_ci	str	ip, [r4]
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	/* Wake up from sleep */
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	/* Clear sleep enable */
1028c2ecf20Sopenharmony_ci	ldr	ip, [r4]
1038c2ecf20Sopenharmony_ci	bic	ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT
1048c2ecf20Sopenharmony_ci	str	ip, [r4]
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	/* initialize the DDR PLL controller */
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	/* Put PLL in reset */
1098c2ecf20Sopenharmony_ci	ldr	ip, [r3, #PLLCTL]
1108c2ecf20Sopenharmony_ci	bic	ip, ip, #PLLCTL_PLLRST
1118c2ecf20Sopenharmony_ci	str	ip, [r3, #PLLCTL]
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	/* Clear PLL power down */
1148c2ecf20Sopenharmony_ci	ldr	ip, [r3, #PLLCTL]
1158c2ecf20Sopenharmony_ci	bic	ip, ip, #PLLCTL_PLLPWRDN
1168c2ecf20Sopenharmony_ci	str	ip, [r3, #PLLCTL]
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci       mov	ip, #PLL_RESET_CYCLES
1198c2ecf20Sopenharmony_ci3:     subs	ip, ip, #0x1
1208c2ecf20Sopenharmony_ci       bne	3b
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci       /* Bring PLL out of reset */
1238c2ecf20Sopenharmony_ci	ldr	ip, [r3, #PLLCTL]
1248c2ecf20Sopenharmony_ci	orr	ip, ip, #PLLCTL_PLLRST
1258c2ecf20Sopenharmony_ci	str	ip, [r3, #PLLCTL]
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	/* Wait for PLL to lock (assume prediv = 1, 25MHz OSCIN) */
1288c2ecf20Sopenharmony_ci       mov	ip, #PLL_LOCK_CYCLES
1298c2ecf20Sopenharmony_ci4:     subs	ip, ip, #0x1
1308c2ecf20Sopenharmony_ci       bne	4b
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci       /* Remove PLL from bypass mode */
1338c2ecf20Sopenharmony_ci	ldr	ip, [r3, #PLLCTL]
1348c2ecf20Sopenharmony_ci	bic	ip, ip, #PLLCTL_PLLENSRC
1358c2ecf20Sopenharmony_ci	orr	ip, ip, #PLLCTL_PLLEN
1368c2ecf20Sopenharmony_ci	str	ip, [r3, #PLLCTL]
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	/* Start 2x clock to DDR2 */
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	ldr	ip, [r3, #PLLDIV1]
1418c2ecf20Sopenharmony_ci	orr	ip, ip, #PLLDIV_EN
1428c2ecf20Sopenharmony_ci	str	ip, [r3, #PLLDIV1]
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	/* Enable VCLK */
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci       /* Enable DDR2 LPSC */
1478c2ecf20Sopenharmony_ci	mov	r7, r0
1488c2ecf20Sopenharmony_ci	mov	r0, #0x3
1498c2ecf20Sopenharmony_ci	bl davinci_ddr_psc_config
1508c2ecf20Sopenharmony_ci	mov	r0, r7
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	/* clear  MCLKSTOPEN */
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
1558c2ecf20Sopenharmony_ci	bic	ip, ip, #DDR2_MCLKSTOPEN_BIT
1568c2ecf20Sopenharmony_ci	str	ip, [r0, #DDR2_SDRCR_OFFSET]
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
1598c2ecf20Sopenharmony_ci	bic	ip, ip, #DDR2_LPMODEN_BIT
1608c2ecf20Sopenharmony_ci	str	ip, [r0, #DDR2_SDRCR_OFFSET]
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	/* Restore registers and return */
1638c2ecf20Sopenharmony_ci	ldmfd   sp!, {r0-r12, pc}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ciENDPROC(davinci_cpu_suspend)
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci/*
1688c2ecf20Sopenharmony_ci * Disables or Enables DDR2 LPSC
1698c2ecf20Sopenharmony_ci * Register Usage:
1708c2ecf20Sopenharmony_ci * 	r0: Enable or Disable LPSC r0 = 0x3 => Enable, r0 = 0x2 => Disable LPSC
1718c2ecf20Sopenharmony_ci * 	r1: contains virtual base for DDR2 Power and Sleep controller (PSC)
1728c2ecf20Sopenharmony_ci * 	r2: contains PSC number for DDR2
1738c2ecf20Sopenharmony_ci */
1748c2ecf20Sopenharmony_ciENTRY(davinci_ddr_psc_config)
1758c2ecf20Sopenharmony_ci	/* Set next state in mdctl for DDR2 */
1768c2ecf20Sopenharmony_ci	mov	r6, #MDCTL
1778c2ecf20Sopenharmony_ci	add	r6, r6, r2, lsl #2
1788c2ecf20Sopenharmony_ci	ldr	ip, [r1, r6]
1798c2ecf20Sopenharmony_ci	bic	ip, ip, #MDSTAT_STATE_MASK
1808c2ecf20Sopenharmony_ci	orr	ip, ip, r0
1818c2ecf20Sopenharmony_ci	str	ip, [r1, r6]
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	/* Enable the Power Domain Transition Command */
1848c2ecf20Sopenharmony_ci	ldr	ip, [r1, #PTCMD]
1858c2ecf20Sopenharmony_ci	orr	ip, ip, #0x1
1868c2ecf20Sopenharmony_ci	str	ip, [r1, #PTCMD]
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	/* Check for Transition Complete (PTSTAT) */
1898c2ecf20Sopenharmony_ciptstat_done:
1908c2ecf20Sopenharmony_ci	ldr	ip, [r1, #PTSTAT]
1918c2ecf20Sopenharmony_ci	and	ip, ip, #0x1
1928c2ecf20Sopenharmony_ci	cmp 	ip, #0x0
1938c2ecf20Sopenharmony_ci	bne	ptstat_done
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	/* Check for DDR2 clock disable completion; */
1968c2ecf20Sopenharmony_ci	mov	r6, #MDSTAT
1978c2ecf20Sopenharmony_ci	add	r6, r6, r2, lsl #2
1988c2ecf20Sopenharmony_ciddr2clk_stop_done:
1998c2ecf20Sopenharmony_ci	ldr	ip, [r1, r6]
2008c2ecf20Sopenharmony_ci	and	ip, ip, #MDSTAT_STATE_MASK
2018c2ecf20Sopenharmony_ci	cmp	ip, r0
2028c2ecf20Sopenharmony_ci	bne	ddr2clk_stop_done
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	ret	lr
2058c2ecf20Sopenharmony_ciENDPROC(davinci_ddr_psc_config)
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ciCACHE_FLUSH:
2088c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_V6
2098c2ecf20Sopenharmony_ci	.word	v6_flush_kern_cache_all
2108c2ecf20Sopenharmony_ci#else
2118c2ecf20Sopenharmony_ci	.word   arm926_flush_kern_cache_all
2128c2ecf20Sopenharmony_ci#endif
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ciENTRY(davinci_cpu_suspend_sz)
2158c2ecf20Sopenharmony_ci	.word	. - davinci_cpu_suspend
2168c2ecf20Sopenharmony_ciENDPROC(davinci_cpu_suspend_sz)
217