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