/*
 * PowerPC 4xx Clock and Power Management
 *
 * Copyright (C) 2010, Applied Micro Circuits Corporation
 * Victor Gallardo (vgallardo@apm.com)
 *
 * Based on arch/powerpc/platforms/44x/idle.c:
 * Jerone Young <jyoung5@us.ibm.com>
 * Copyright 2008 IBM Corp.
 *
 * Based on arch/powerpc/sysdev/fsl_pmc.c:
 * Anton Vorontsov <avorontsov@ru.mvista.com>
 * Copyright 2009  MontaVista Software, Inc.
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

#include <linux/kernel.h>
#include <linux/of_platform.h>
#include <linux/sysfs.h>
#include <linux/cpu.h>
#include <linux/suspend.h>
#include <asm/dcr.h>
#include <asm/dcr-native.h>
#include <asm/machdep.h>

#define CPM_ER	0
#define CPM_FR	1
#define CPM_SR	2

#define CPM_IDLE_WAIT	0
#define CPM_IDLE_DOZE	1

struct cpm {
	dcr_host_t	dcr_host;
	unsigned int	dcr_offset[3];
	unsigned int	powersave_off;
	unsigned int	unused;
	unsigned int	idle_doze;
	unsigned int	standby;
	unsigned int	suspend;
};

static struct cpm cpm;

struct cpm_idle_mode {
	unsigned int enabled;
	const char  *name;
};

static struct cpm_idle_mode idle_mode[] = {
	[CPM_IDLE_WAIT] = { 1, "wait" }, /* default */
	[CPM_IDLE_DOZE] = { 0, "doze" },
};

static unsigned int cpm_set(unsigned int cpm_reg, unsigned int mask)
{
	unsigned int value;

	/* CPM controller supports 3 different types of sleep interface
	 * known as class 1, 2 and 3. For class 1 units, they are
	 * unconditionally put to sleep when the corresponding CPM bit is
	 * set. For class 2 and 3 units this is not case; if they can be
	 * put to to sleep, they will. Here we do not verify, we just
	 * set them and expect them to eventually go off when they can.
	 */
	value = dcr_read(cpm.dcr_host, cpm.dcr_offset[cpm_reg]);
	dcr_write(cpm.dcr_host, cpm.dcr_offset[cpm_reg], value | mask);

	/* return old state, to restore later if needed */
	return value;
}

static void cpm_idle_wait(void)
{
	unsigned long msr_save;

	/* save off initial state */
	msr_save = mfmsr();
	/* sync required when CPM0_ER[CPU] is set */
	mb();
	/* set wait state MSR */
	mtmsr(msr_save|MSR_WE|MSR_EE|MSR_CE|MSR_DE);
	isync();
	/* return to initial state */
	mtmsr(msr_save);
	isync();
}

static void cpm_idle_sleep(unsigned int mask)
{
	unsigned int er_save;

	/* update CPM_ER state */
	er_save = cpm_set(CPM_ER, mask);

	/* go to wait state so that CPM0_ER[CPU] can take effect */
	cpm_idle_wait();

	/* restore CPM_ER state */
	dcr_write(cpm.dcr_host, cpm.dcr_offset[CPM_ER], er_save);
}

static void cpm_idle_doze(void)
{
	cpm_idle_sleep(cpm.idle_doze);
}

static void cpm_idle_config(int mode)
{
	int i;

	if (idle_mode[mode].enabled)
		return;

	for (i = 0; i < ARRAY_SIZE(idle_mode); i++)
		idle_mode[i].enabled = 0;

	idle_mode[mode].enabled = 1;
}

static ssize_t cpm_idle_show(struct kobject *kobj,
			     struct kobj_attribute *attr, char *buf)
{
	char *s = buf;
	int i;

	for (i = 0; i < ARRAY_SIZE(idle_mode); i++) {
		if (idle_mode[i].enabled)
			s += sprintf(s, "[%s] ", idle_mode[i].name);
		else
			s += sprintf(s, "%s ", idle_mode[i].name);
	}

	*(s-1) = '\n'; /* convert the last space to a newline */

	return s - buf;
}

static ssize_t cpm_idle_store(struct kobject *kobj,
			      struct kobj_attribute *attr,
			      const char *buf, size_t n)
{
	int i;
	char *p;
	int len;

	p = memchr(buf, '\n', n);
	len = p ? p - buf : n;

	for (i = 0; i < ARRAY_SIZE(idle_mode); i++) {
		if (strncmp(buf, idle_mode[i].name, len) == 0) {
			cpm_idle_config(i);
			return n;
		}
	}

	return -EINVAL;
}

static struct kobj_attribute cpm_idle_attr =
	__ATTR(idle, 0644, cpm_idle_show, cpm_idle_store);

static void cpm_idle_config_sysfs(void)
{
	struct sys_device *sys_dev;
	unsigned long ret;

	sys_dev = get_cpu_sysdev(0);

	ret = sysfs_create_file(&sys_dev->kobj,
				&cpm_idle_attr.attr);
	if (ret)
		printk(KERN_WARNING
		       "cpm: failed to create idle sysfs entry\n");
}

static void cpm_idle(void)
{
	if (idle_mode[CPM_IDLE_DOZE].enabled)
		cpm_idle_doze();
	else
		cpm_idle_wait();
}

static int cpm_suspend_valid(suspend_state_t state)
{
	switch (state) {
	case PM_SUSPEND_STANDBY:
		return !!cpm.standby;
	case PM_SUSPEND_MEM:
		return !!cpm.suspend;
	default:
		return 0;
	}
}

static void cpm_suspend_standby(unsigned int mask)
{
	unsigned long tcr_save;

	/* disable decrement interrupt */
	tcr_save = mfspr(SPRN_TCR);
	mtspr(SPRN_TCR, tcr_save & ~TCR_DIE);

	/* go to sleep state */
	cpm_idle_sleep(mask);

	/* restore decrement interrupt */
	mtspr(SPRN_TCR, tcr_save);
}

static int cpm_suspend_enter(suspend_state_t state)
{
	switch (state) {
	case PM_SUSPEND_STANDBY:
		cpm_suspend_standby(cpm.standby);
		break;
	case PM_SUSPEND_MEM:
		cpm_suspend_standby(cpm.suspend);
		break;
	}

	return 0;
}

static struct platform_suspend_ops cpm_suspend_ops = {
	.valid		= cpm_suspend_valid,
	.enter		= cpm_suspend_enter,
};

static int cpm_get_uint_property(struct device_node *np,
				 const char *name)
{
	int len;
	const unsigned int *prop = of_get_property(np, name, &len);

	if (prop == NULL || len < sizeof(u32))
		return 0;

	return *prop;
}

static int __init cpm_init(void)
{
	struct device_node *np;
	int dcr_base, dcr_len;
	int ret = 0;

	if (!cpm.powersave_off) {
		cpm_idle_config(CPM_IDLE_WAIT);
		ppc_md.power_save = &cpm_idle;
	}

	np = of_find_compatible_node(NULL, NULL, "ibm,cpm");
	if (!np) {
		ret = -EINVAL;
		goto out;
	}

	dcr_base = dcr_resource_start(np, 0);
	dcr_len = dcr_resource_len(np, 0);

	if (dcr_base == 0 || dcr_len == 0) {
		printk(KERN_ERR "cpm: could not parse dcr property for %s\n",
		       np->full_name);
		ret = -EINVAL;
		goto out;
	}

	cpm.dcr_host = dcr_map(np, dcr_base, dcr_len);

	if (!DCR_MAP_OK(cpm.dcr_host)) {
		printk(KERN_ERR "cpm: failed to map dcr property for %s\n",
		       np->full_name);
		ret = -EINVAL;
		goto out;
	}

	/* All 4xx SoCs with a CPM controller have one of two
	 * different order for the CPM registers. Some have the
	 * CPM registers in the following order (ER,FR,SR). The
	 * others have them in the following order (SR,ER,FR).
	 */

	if (cpm_get_uint_property(np, "er-offset") == 0) {
		cpm.dcr_offset[CPM_ER] = 0;
		cpm.dcr_offset[CPM_FR] = 1;
		cpm.dcr_offset[CPM_SR] = 2;
	} else {
		cpm.dcr_offset[CPM_ER] = 1;
		cpm.dcr_offset[CPM_FR] = 2;
		cpm.dcr_offset[CPM_SR] = 0;
	}

	/* Now let's see what IPs to turn off for the following modes */

	cpm.unused = cpm_get_uint_property(np, "unused-units");
	cpm.idle_doze = cpm_get_uint_property(np, "idle-doze");
	cpm.standby = cpm_get_uint_property(np, "standby");
	cpm.suspend = cpm_get_uint_property(np, "suspend");

	/* If some IPs are unused let's turn them off now */

	if (cpm.unused) {
		cpm_set(CPM_ER, cpm.unused);
		cpm_set(CPM_FR, cpm.unused);
	}

	/* Now let's export interfaces */

	if (!cpm.powersave_off && cpm.idle_doze)
		cpm_idle_config_sysfs();

	if (cpm.standby || cpm.suspend)
		suspend_set_ops(&cpm_suspend_ops);
out:
	if (np)
		of_node_put(np);
	return ret;
}

late_initcall(cpm_init);

static int __init cpm_powersave_off(char *arg)
{
	cpm.powersave_off = 1;
	return 0;
}
__setup("powersave=off", cpm_powersave_off);
