Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d26e7489 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/gk104-/fb/ram: parse ramcfg data for all frequencies up-front



Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 64804a6d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -111,6 +111,7 @@ extern struct nouveau_oclass *gm107_fb_oclass;
#include <subdev/bios/ramcfg.h>

struct nouveau_ram_data {
	struct list_head head;
	struct nvbios_ramcfg bios;
	u32 freq;
};
+88 −48
Original line number Diff line number Diff line
@@ -136,6 +136,7 @@ struct nve0_ram {
	struct nouveau_ram base;
	struct nve0_ramfuc fuc;

	struct list_head cfg;
	u32 parts;
	u32 pmask;
	u32 pnuts;
@@ -934,59 +935,25 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
 ******************************************************************************/

static int
nve0_ram_calc_data(struct nouveau_fb *pfb, u32 freq,
nve0_ram_calc_data(struct nouveau_fb *pfb, u32 khz,
		   struct nouveau_ram_data *data)
{
	struct nouveau_bios *bios = nouveau_bios(pfb);
	struct nve0_ram *ram = (void *)pfb->ram;
	u8 strap, cnt, len;

	/* lookup memory config data relevant to the target frequency */
	ram->base.rammap.data = nvbios_rammapEm(bios, freq / 1000,
					       &ram->base.rammap.version,
					       &ram->base.rammap.size,
					       &cnt, &len, &data->bios);
	if (!ram->base.rammap.data || ram->base.rammap.version != 0x11 ||
	     ram->base.rammap.size < 0x09) {
		nv_error(pfb, "invalid/missing rammap entry\n");
		return -EINVAL;
	struct nouveau_ram_data *cfg;
	u32 mhz = khz / 1000;

	list_for_each_entry(cfg, &ram->cfg, head) {
		if (mhz >= cfg->bios.rammap_min &&
		    mhz <= cfg->bios.rammap_max) {
			*data = *cfg;
			data->freq = khz;
			return 0;
		}

	/* locate specific data set for the attached memory */
	strap = nvbios_ramcfg_index(nv_subdev(pfb));
	ram->base.ramcfg.data = nvbios_rammapSp(bios, ram->base.rammap.data,
						ram->base.rammap.version,
						ram->base.rammap.size,
						cnt, len, strap,
						&ram->base.ramcfg.version,
						&ram->base.ramcfg.size,
						&data->bios);
	if (!ram->base.ramcfg.data || ram->base.ramcfg.version != 0x11 ||
	     ram->base.ramcfg.size < 0x08) {
		nv_error(pfb, "invalid/missing ramcfg entry\n");
		return -EINVAL;
	}

	/* lookup memory timings, if bios says they're present */
	if (data->bios.ramcfg_timing != 0xff) {
		ram->base.timing.data =
			nvbios_timingEp(bios, data->bios.ramcfg_timing,
					&ram->base.timing.version,
					&ram->base.timing.size, &cnt, &len,
					&data->bios);
		if (!ram->base.timing.data ||
		     ram->base.timing.version != 0x20 ||
		     ram->base.timing.size < 0x33) {
			nv_error(pfb, "invalid/missing timing entry\n");
	nv_error(ram, "ramcfg data for %dMHz not found\n", mhz);
	return -EINVAL;
}
	} else {
		ram->base.timing.data = 0;
	}

	data->freq = freq;
	return 0;
}

static int
nve0_ram_calc_xits(struct nouveau_fb *pfb, struct nouveau_ram_data *next)
@@ -1318,6 +1285,66 @@ nve0_ram_init(struct nouveau_object *object)
	return nve0_ram_train_init(pfb);
}

static int
nve0_ram_ctor_data(struct nve0_ram *ram, u8 ramcfg, int i)
{
	struct nouveau_fb *pfb = (void *)nv_object(ram)->parent;
	struct nouveau_bios *bios = nouveau_bios(pfb);
	struct nouveau_ram_data *cfg;
	u8  ver, hdr, cnt, len;
	u32 data;
	int ret;

	if (!(cfg = kmalloc(sizeof(*cfg), GFP_KERNEL)))
		return -ENOMEM;

	/* memory config data for a range of target frequencies */
	data = nvbios_rammapEp(bios, i, &ver, &hdr, &cnt, &len, &cfg->bios);
	if (ret = -ENOENT, !data)
		goto done;
	if (ret = -ENOSYS, ver != 0x11 || hdr < 0x12)
		goto done;

	/* ... and a portion specific to the attached memory */
	data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, ramcfg,
			       &ver, &hdr, &cfg->bios);
	if (ret = -EINVAL, !data)
		goto done;
	if (ret = -ENOSYS, ver != 0x11 || hdr < 0x0a)
		goto done;

	/* lookup memory timings, if bios says they're present */
	if (cfg->bios.ramcfg_timing != 0xff) {
		data = nvbios_timingEp(bios, cfg->bios.ramcfg_timing,
				       &ver, &hdr, &cnt, &len,
				       &cfg->bios);
		if (ret = -EINVAL, !data)
			goto done;
		if (ret = -ENOSYS, ver != 0x20 || hdr < 0x33)
			goto done;
	}

	list_add_tail(&cfg->head, &ram->cfg);
	ret = 0;
done:
	if (ret)
		kfree(cfg);
	return ret;
}

static void
nve0_ram_dtor(struct nouveau_object *object)
{
	struct nve0_ram *ram = (void *)object;
	struct nouveau_ram_data *cfg, *tmp;

	list_for_each_entry_safe(cfg, tmp, &ram->cfg, head) {
		kfree(cfg);
	}

	nouveau_ram_destroy(&ram->base);
}

static int
nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
	      struct nouveau_oclass *oclass, void *data, u32 size,
@@ -1329,6 +1356,7 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
	struct dcb_gpio_func func;
	struct nve0_ram *ram;
	int ret, i;
	u8  ramcfg = nvbios_ramcfg_index(nv_subdev(pfb));
	u32 tmp;

	ret = nvc0_ram_create(parent, engine, oclass, 0x022554, &ram);
@@ -1336,6 +1364,8 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
	if (ret)
		return ret;

	INIT_LIST_HEAD(&ram->cfg);

	switch (ram->base.type) {
	case NV_MEM_TYPE_DDR3:
	case NV_MEM_TYPE_GDDR5:
@@ -1367,7 +1397,16 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
		}
	}

	// parse bios data for both pll's
	/* parse ramcfg data for all possible target frequencies */
	for (i = 0; !ret; i++) {
		ret = nve0_ram_ctor_data(ram, ramcfg, i);
		if (ret && ret != -ENOENT) {
			nv_error(pfb, "failed to parse ramcfg data\n");
			return ret;
		}
	}

	/* parse bios data for both pll's */
	ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll);
	if (ret) {
		nv_error(pfb, "mclk refpll data not found\n");
@@ -1380,6 +1419,7 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
		return ret;
	}

	/* lookup memory voltage gpios */
	ret = gpio->find(gpio, 0, 0x18, DCB_GPIO_UNUSED, &func);
	if (ret == 0) {
		ram->fuc.r_gpioMV = ramfuc_reg(0x00d610 + (func.line * 0x04));
@@ -1488,7 +1528,7 @@ nve0_ram_oclass = {
	.handle = 0,
	.ofuncs = &(struct nouveau_ofuncs) {
		.ctor = nve0_ram_ctor,
		.dtor = _nouveau_ram_dtor,
		.dtor = nve0_ram_dtor,
		.init = nve0_ram_init,
		.fini = _nouveau_ram_fini,
	}