/*
 * Copyright 2010 Red Hat Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Authors: Ben Skeggs
 */

#include "drmP.h"

#include "nouveau_drv.h"
#include "nouveau_pm.h"
#include "nouveau_gpio.h"

static const enum dcb_gpio_tag vidtag[] = { 0x04, 0x05, 0x06, 0x1a, 0x73 };
static int nr_vidtag = sizeof(vidtag) / sizeof(vidtag[0]);

int
nouveau_voltage_gpio_get(struct drm_device *dev)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
	u8 vid = 0;
	int i;

	for (i = 0; i < nr_vidtag; i++) {
		if (!(volt->vid_mask & (1 << i)))
			continue;

		vid |= nouveau_gpio_func_get(dev, vidtag[i]) << i;
	}

	return nouveau_volt_lvl_lookup(dev, vid);
}

int
nouveau_voltage_gpio_set(struct drm_device *dev, int voltage)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
	int vid, i;

	vid = nouveau_volt_vid_lookup(dev, voltage);
	if (vid < 0)
		return vid;

	for (i = 0; i < nr_vidtag; i++) {
		if (!(volt->vid_mask & (1 << i)))
			continue;

		nouveau_gpio_func_set(dev, vidtag[i], !!(vid & (1 << i)));
	}

	return 0;
}

int
nouveau_volt_vid_lookup(struct drm_device *dev, int voltage)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
	int i;

	for (i = 0; i < volt->nr_level; i++) {
		if (volt->level[i].voltage == voltage)
			return volt->level[i].vid;
	}

	return -ENOENT;
}

int
nouveau_volt_lvl_lookup(struct drm_device *dev, int vid)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
	int i;

	for (i = 0; i < volt->nr_level; i++) {
		if (volt->level[i].vid == vid)
			return volt->level[i].voltage;
	}

	return -ENOENT;
}

void
nouveau_volt_init(struct drm_device *dev)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
	struct nouveau_pm_voltage *voltage = &pm->voltage;
	struct nvbios *bios = &dev_priv->vbios;
	struct bit_entry P;
	u8 *volt = NULL, *entry;
	int i, headerlen, recordlen, entries, vidmask, vidshift;

	if (bios->type == NVBIOS_BIT) {
		if (bit_table(dev, 'P', &P))
			return;

		if (P.version == 1)
			volt = ROMPTR(dev, P.data[16]);
		else
		if (P.version == 2)
			volt = ROMPTR(dev, P.data[12]);
		else {
			NV_WARN(dev, "unknown volt for BIT P %d\n", P.version);
		}
	} else {
		if (bios->data[bios->offset + 6] < 0x27) {
			NV_DEBUG(dev, "BMP version too old for voltage\n");
			return;
		}

		volt = ROMPTR(dev, bios->data[bios->offset + 0x98]);
	}

	if (!volt) {
		NV_DEBUG(dev, "voltage table pointer invalid\n");
		return;
	}

	switch (volt[0]) {
	case 0x10:
	case 0x11:
	case 0x12:
		headerlen = 5;
		recordlen = volt[1];
		entries   = volt[2];
		vidshift  = 0;
		vidmask   = volt[4];
		break;
	case 0x20:
		headerlen = volt[1];
		recordlen = volt[3];
		entries   = volt[2];
		vidshift  = 0; /* could be vidshift like 0x30? */
		vidmask   = volt[5];
		break;
	case 0x30:
		headerlen = volt[1];
		recordlen = volt[2];
		entries   = volt[3];
		vidmask   = volt[4];
		/* no longer certain what volt[5] is, if it's related to
		 * the vid shift then it's definitely not a function of
		 * how many bits are set.
		 *
		 * after looking at a number of nva3+ vbios images, they
		 * all seem likely to have a static shift of 2.. lets
		 * go with that for now until proven otherwise.
		 */
		vidshift  = 2;
		break;
	case 0x40:
		headerlen = volt[1];
		recordlen = volt[2];
		entries   = volt[3]; /* not a clue what the entries are for.. */
		vidmask   = volt[11]; /* guess.. */
		vidshift  = 0;
		break;
	default:
		NV_WARN(dev, "voltage table 0x%02x unknown\n", volt[0]);
		return;
	}

	/* validate vid mask */
	voltage->vid_mask = vidmask;
	if (!voltage->vid_mask)
		return;

	i = 0;
	while (vidmask) {
		if (i > nr_vidtag) {
			NV_DEBUG(dev, "vid bit %d unknown\n", i);
			return;
		}

		if (!nouveau_gpio_func_valid(dev, vidtag[i])) {
			NV_DEBUG(dev, "vid bit %d has no gpio tag\n", i);
			return;
		}

		vidmask >>= 1;
		i++;
	}

	/* parse vbios entries into common format */
	voltage->version = volt[0];
	if (voltage->version < 0x40) {
		voltage->nr_level = entries;
		voltage->level =
			kcalloc(entries, sizeof(*voltage->level), GFP_KERNEL);
		if (!voltage->level)
			return;

		entry = volt + headerlen;
		for (i = 0; i < entries; i++, entry += recordlen) {
			voltage->level[i].voltage = entry[0] * 10000;
			voltage->level[i].vid     = entry[1] >> vidshift;
		}
	} else {
		u32 volt_uv = ROM32(volt[4]);
		s16 step_uv = ROM16(volt[8]);
		u8 vid;

		voltage->nr_level = voltage->vid_mask + 1;
		voltage->level = kcalloc(voltage->nr_level,
					 sizeof(*voltage->level), GFP_KERNEL);
		if (!voltage->level)
			return;

		for (vid = 0; vid <= voltage->vid_mask; vid++) {
			voltage->level[vid].voltage = volt_uv;
			voltage->level[vid].vid = vid;
			volt_uv += step_uv;
		}
	}

	voltage->supported = true;
}

void
nouveau_volt_fini(struct drm_device *dev)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;

	kfree(volt->level);
}
