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