162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2016 Freescale Semiconductor, Inc.
462306a36Sopenharmony_ci * Copyright 2017-2018 NXP
562306a36Sopenharmony_ci *   Author: Dong Aisheng <aisheng.dong@nxp.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/io.h>
962306a36Sopenharmony_ci#include <linux/of.h>
1062306a36Sopenharmony_ci#include <linux/of_address.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "common.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define SMC_PMCTRL		0x10
1562306a36Sopenharmony_ci#define BP_PMCTRL_PSTOPO        16
1662306a36Sopenharmony_ci#define PSTOPO_PSTOP3		0x3
1762306a36Sopenharmony_ci#define PSTOPO_PSTOP2		0x2
1862306a36Sopenharmony_ci#define PSTOPO_PSTOP1		0x1
1962306a36Sopenharmony_ci#define BP_PMCTRL_RUNM		8
2062306a36Sopenharmony_ci#define RUNM_RUN		0
2162306a36Sopenharmony_ci#define BP_PMCTRL_STOPM		0
2262306a36Sopenharmony_ci#define STOPM_STOP		0
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define BM_PMCTRL_PSTOPO	(3 << BP_PMCTRL_PSTOPO)
2562306a36Sopenharmony_ci#define BM_PMCTRL_RUNM		(3 << BP_PMCTRL_RUNM)
2662306a36Sopenharmony_ci#define BM_PMCTRL_STOPM		(7 << BP_PMCTRL_STOPM)
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic void __iomem *smc1_base;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ciint imx7ulp_set_lpm(enum ulp_cpu_pwr_mode mode)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	u32 val = readl_relaxed(smc1_base + SMC_PMCTRL);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	/* clear all */
3562306a36Sopenharmony_ci	val &= ~(BM_PMCTRL_RUNM | BM_PMCTRL_STOPM | BM_PMCTRL_PSTOPO);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	switch (mode) {
3862306a36Sopenharmony_ci	case ULP_PM_RUN:
3962306a36Sopenharmony_ci		/* system/bus clock enabled */
4062306a36Sopenharmony_ci		val |= PSTOPO_PSTOP3 << BP_PMCTRL_PSTOPO;
4162306a36Sopenharmony_ci		break;
4262306a36Sopenharmony_ci	case ULP_PM_WAIT:
4362306a36Sopenharmony_ci		/* system clock disabled, bus clock enabled */
4462306a36Sopenharmony_ci		val |= PSTOPO_PSTOP2 << BP_PMCTRL_PSTOPO;
4562306a36Sopenharmony_ci		break;
4662306a36Sopenharmony_ci	case ULP_PM_STOP:
4762306a36Sopenharmony_ci		/* system/bus clock disabled */
4862306a36Sopenharmony_ci		val |= PSTOPO_PSTOP1 << BP_PMCTRL_PSTOPO;
4962306a36Sopenharmony_ci		break;
5062306a36Sopenharmony_ci	default:
5162306a36Sopenharmony_ci		return -EINVAL;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	writel_relaxed(val, smc1_base + SMC_PMCTRL);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	return 0;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_civoid __init imx7ulp_pm_init(void)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	struct device_node *np;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-smc1");
6462306a36Sopenharmony_ci	smc1_base = of_iomap(np, 0);
6562306a36Sopenharmony_ci	of_node_put(np);
6662306a36Sopenharmony_ci	WARN_ON(!smc1_base);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	imx7ulp_set_lpm(ULP_PM_RUN);
6962306a36Sopenharmony_ci}
70