/*
 * 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 device *dev;
	unsigned long ret;

	dev = get_cpu_device(0);

	ret = sysfs_create_file(&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 node_put;
	}

	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 node_put;
	}

	/* 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);
node_put:
	of_node_put(np);
out:
	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);
