/*
 * Copyright 2012 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 <subdev/ltcg.h>
#include <subdev/fb.h>
#include <subdev/timer.h>

struct nvc0_ltcg_priv {
	struct nouveau_ltcg base;
	u32 part_nr;
	u32 subp_nr;
	struct nouveau_mm tags;
	u32 num_tags;
	struct nouveau_mm_node *tag_ram;
};

static void
nvc0_ltcg_subp_isr(struct nvc0_ltcg_priv *priv, int unit, int subp)
{
	u32 subp_base = 0x141000 + (unit * 0x2000) + (subp * 0x400);
	u32 stat = nv_rd32(priv, subp_base + 0x020);

	if (stat) {
		nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", unit, subp, stat);
		nv_wr32(priv, subp_base + 0x020, stat);
	}
}

static void
nvc0_ltcg_intr(struct nouveau_subdev *subdev)
{
	struct nvc0_ltcg_priv *priv = (void *)subdev;
	u32 units;

	units = nv_rd32(priv, 0x00017c);
	while (units) {
		u32 subp, unit = ffs(units) - 1;
		for (subp = 0; subp < priv->subp_nr; subp++)
			nvc0_ltcg_subp_isr(priv, unit, subp);
		units &= ~(1 << unit);
	}

	/* we do something horribly wrong and upset PMFB a lot, so mask off
	 * interrupts from it after the first one until it's fixed
	 */
	nv_mask(priv, 0x000640, 0x02000000, 0x00000000);
}

static int
nvc0_ltcg_tags_alloc(struct nouveau_ltcg *ltcg, u32 n,
		     struct nouveau_mm_node **pnode)
{
	struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg;
	int ret;

	ret = nouveau_mm_head(&priv->tags, 1, n, n, 1, pnode);
	if (ret)
		*pnode = NULL;

	return ret;
}

static void
nvc0_ltcg_tags_free(struct nouveau_ltcg *ltcg, struct nouveau_mm_node **pnode)
{
	struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg;

	nouveau_mm_free(&priv->tags, pnode);
}

static void
nvc0_ltcg_tags_clear(struct nouveau_ltcg *ltcg, u32 first, u32 count)
{
	struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg;
	u32 last = first + count - 1;
	int p, i;

	BUG_ON((first > last) || (last >= priv->num_tags));

	nv_wr32(priv, 0x17e8cc, first);
	nv_wr32(priv, 0x17e8d0, last);
	nv_wr32(priv, 0x17e8c8, 0x4); /* trigger clear */

	/* wait until it's finished with clearing */
	for (p = 0; p < priv->part_nr; ++p) {
		for (i = 0; i < priv->subp_nr; ++i)
			nv_wait(priv, 0x1410c8 + p * 0x2000 + i * 0x400, ~0, 0);
	}
}

/* TODO: Figure out tag memory details and drop the over-cautious allocation.
 */
static int
nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv)
{
	u32 tag_size, tag_margin, tag_align;
	int ret;

	nv_wr32(priv, 0x17e8d8, priv->part_nr);
	if (nv_device(pfb)->card_type >= NV_E0)
		nv_wr32(priv, 0x17e000, priv->part_nr);

	/* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */
	priv->num_tags = (pfb->ram->size >> 17) / 4;
	if (priv->num_tags > (1 << 17))
		priv->num_tags = 1 << 17; /* we have 17 bits in PTE */
	priv->num_tags = (priv->num_tags + 63) & ~63; /* round up to 64 */

	tag_align = priv->part_nr * 0x800;
	tag_margin = (tag_align < 0x6000) ? 0x6000 : tag_align;

	/* 4 part 4 sub: 0x2000 bytes for 56 tags */
	/* 3 part 4 sub: 0x6000 bytes for 168 tags */
	/*
	 * About 147 bytes per tag. Let's be safe and allocate x2, which makes
	 * 0x4980 bytes for 64 tags, and round up to 0x6000 bytes for 64 tags.
	 *
	 * For 4 GiB of memory we'll have 8192 tags which makes 3 MiB, < 0.1 %.
	 */
	tag_size  = (priv->num_tags / 64) * 0x6000 + tag_margin;
	tag_size += tag_align;
	tag_size  = (tag_size + 0xfff) >> 12; /* round up */

	ret = nouveau_mm_tail(&pfb->vram, 0, tag_size, tag_size, 1,
	                      &priv->tag_ram);
	if (ret) {
		priv->num_tags = 0;
	} else {
		u64 tag_base = (priv->tag_ram->offset << 12) + tag_margin;

		tag_base += tag_align - 1;
		ret = do_div(tag_base, tag_align);

		nv_wr32(priv, 0x17e8d4, tag_base);
	}
	ret = nouveau_mm_init(&priv->tags, 0, priv->num_tags, 1);

	return ret;
}

static int
nvc0_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
	       struct nouveau_oclass *oclass, void *data, u32 size,
	       struct nouveau_object **pobject)
{
	struct nvc0_ltcg_priv *priv;
	struct nouveau_fb *pfb = nouveau_fb(parent);
	u32 parts, mask;
	int ret, i;

	ret = nouveau_ltcg_create(parent, engine, oclass, &priv);
	*pobject = nv_object(priv);
	if (ret)
		return ret;

	parts = nv_rd32(priv, 0x022438);
	mask = nv_rd32(priv, 0x022554);
	for (i = 0; i < parts; i++) {
		if (!(mask & (1 << i)))
			priv->part_nr++;
	}
	priv->subp_nr = nv_rd32(priv, 0x17e8dc) >> 28;

	nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */

	ret = nvc0_ltcg_init_tag_ram(pfb, priv);
	if (ret)
		return ret;

	priv->base.tags_alloc = nvc0_ltcg_tags_alloc;
	priv->base.tags_free  = nvc0_ltcg_tags_free;
	priv->base.tags_clear = nvc0_ltcg_tags_clear;

	nv_subdev(priv)->intr = nvc0_ltcg_intr;
	return 0;
}

static void
nvc0_ltcg_dtor(struct nouveau_object *object)
{
	struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object;
	struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg;
	struct nouveau_fb *pfb = nouveau_fb(ltcg->base.base.parent);

	nouveau_mm_fini(&priv->tags);
	nouveau_mm_free(&pfb->vram, &priv->tag_ram);

	nouveau_ltcg_destroy(ltcg);
}

struct nouveau_oclass
nvc0_ltcg_oclass = {
	.handle = NV_SUBDEV(LTCG, 0xc0),
	.ofuncs = &(struct nouveau_ofuncs) {
		.ctor = nvc0_ltcg_ctor,
		.dtor = nvc0_ltcg_dtor,
		.init = _nouveau_ltcg_init,
		.fini = _nouveau_ltcg_fini,
	},
};
