162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Static Memory Controller 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/module.h> 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/init.h> 962306a36Sopenharmony_ci#include <linux/io.h> 1062306a36Sopenharmony_ci#include <linux/syscore_ops.h> 1162306a36Sopenharmony_ci#include <linux/soc/pxa/cpu.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "smemc.h" 1462306a36Sopenharmony_ci#include <linux/soc/pxa/smemc.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#ifdef CONFIG_PM 1762306a36Sopenharmony_cistatic unsigned long msc[2]; 1862306a36Sopenharmony_cistatic unsigned long sxcnfg, memclkcfg; 1962306a36Sopenharmony_cistatic unsigned long csadrcfg[4]; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic int pxa3xx_smemc_suspend(void) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci msc[0] = __raw_readl(MSC0); 2462306a36Sopenharmony_ci msc[1] = __raw_readl(MSC1); 2562306a36Sopenharmony_ci sxcnfg = __raw_readl(SXCNFG); 2662306a36Sopenharmony_ci memclkcfg = __raw_readl(MEMCLKCFG); 2762306a36Sopenharmony_ci csadrcfg[0] = __raw_readl(CSADRCFG0); 2862306a36Sopenharmony_ci csadrcfg[1] = __raw_readl(CSADRCFG1); 2962306a36Sopenharmony_ci csadrcfg[2] = __raw_readl(CSADRCFG2); 3062306a36Sopenharmony_ci csadrcfg[3] = __raw_readl(CSADRCFG3); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci return 0; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic void pxa3xx_smemc_resume(void) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci __raw_writel(msc[0], MSC0); 3862306a36Sopenharmony_ci __raw_writel(msc[1], MSC1); 3962306a36Sopenharmony_ci __raw_writel(sxcnfg, SXCNFG); 4062306a36Sopenharmony_ci __raw_writel(memclkcfg, MEMCLKCFG); 4162306a36Sopenharmony_ci __raw_writel(csadrcfg[0], CSADRCFG0); 4262306a36Sopenharmony_ci __raw_writel(csadrcfg[1], CSADRCFG1); 4362306a36Sopenharmony_ci __raw_writel(csadrcfg[2], CSADRCFG2); 4462306a36Sopenharmony_ci __raw_writel(csadrcfg[3], CSADRCFG3); 4562306a36Sopenharmony_ci /* CSMSADRCFG wakes up in its default state (0), so we need to set it */ 4662306a36Sopenharmony_ci __raw_writel(0x2, CSMSADRCFG); 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic struct syscore_ops smemc_syscore_ops = { 5062306a36Sopenharmony_ci .suspend = pxa3xx_smemc_suspend, 5162306a36Sopenharmony_ci .resume = pxa3xx_smemc_resume, 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic int __init smemc_init(void) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci if (cpu_is_pxa3xx()) { 5762306a36Sopenharmony_ci /* 5862306a36Sopenharmony_ci * The only documentation we have on the 5962306a36Sopenharmony_ci * Chip Select Configuration Register (CSMSADRCFG) is that 6062306a36Sopenharmony_ci * it must be programmed to 0x2. 6162306a36Sopenharmony_ci * Moreover, in the bit definitions, the second bit 6262306a36Sopenharmony_ci * (CSMSADRCFG[1]) is called "SETALWAYS". 6362306a36Sopenharmony_ci * Other bits are reserved in this register. 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_ci __raw_writel(0x2, CSMSADRCFG); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci register_syscore_ops(&smemc_syscore_ops); 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci return 0; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_cisubsys_initcall(smemc_init); 7362306a36Sopenharmony_ci#endif 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic const unsigned int df_clkdiv[4] = { 1, 2, 4, 1 }; 7662306a36Sopenharmony_ciunsigned int pxa3xx_smemc_get_memclkdiv(void) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci unsigned long memclkcfg = __raw_readl(MEMCLKCFG); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci return df_clkdiv[(memclkcfg >> 16) & 0x3]; 8162306a36Sopenharmony_ci} 82