1238730Sdelphij/*	$NetBSD: nouveau_nvkm_subdev_fb_sddr3.c,v 1.4 2021/12/18 23:45:39 riastradh Exp $	*/
2293190Sdelphij
3238730Sdelphij/*
4238730Sdelphij * Copyright 2013 Red Hat Inc.
5238730Sdelphij *
6238730Sdelphij * Permission is hereby granted, free of charge, to any person obtaining a
7238730Sdelphij * copy of this software and associated documentation files (the "Software"),
8238730Sdelphij * to deal in the Software without restriction, including without limitation
960786Sps * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1060786Sps * and/or sell copies of the Software, and to permit persons to whom the
11238730Sdelphij * Software is furnished to do so, subject to the following conditions:
1260786Sps *
1360786Sps * The above copyright notice and this permission notice shall be included in
1460786Sps * all copies or substantial portions of the Software.
1560786Sps *
1660786Sps * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1760786Sps * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1860786Sps * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1960786Sps * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
2060786Sps * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2160786Sps * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2260786Sps * OTHER DEALINGS IN THE SOFTWARE.
2360786Sps *
2460786Sps * Authors: Ben Skeggs <bskeggs@redhat.com>
2560786Sps * 	    Roy Spliet <rspliet@eclipso.eu>
2660786Sps */
2760786Sps#include <sys/cdefs.h>
2860786Sps__KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_subdev_fb_sddr3.c,v 1.4 2021/12/18 23:45:39 riastradh Exp $");
2960786Sps
3060786Sps#include "ram.h"
3160786Sps#include "priv.h"
3260786Sps#include "ram.h"
3360786Sps
3460786Spsstruct ramxlat {
3560786Sps	int id;
3660786Sps	u8 enc;
3760786Sps};
3860786Sps
3960786Spsstatic inline int
4060786Spsramxlat(const struct ramxlat *xlat, int id)
4160786Sps{
4260786Sps	while (xlat->id >= 0) {
4360786Sps		if (xlat->id == id)
4460786Sps			return xlat->enc;
4560786Sps		xlat++;
4660786Sps	}
4760786Sps	return -EINVAL;
4860786Sps}
4960786Sps
5060786Spsstatic const struct ramxlat
5160786Spsramddr3_cl[] = {
5260786Sps	{ 5, 2 }, { 6, 4 }, { 7, 6 }, { 8, 8 }, { 9, 10 }, { 10, 12 },
5360786Sps	{ 11, 14 },
5460786Sps	/* the below are mentioned in some, but not all, ddr3 docs */
5560786Sps	{ 12, 1 }, { 13, 3 }, { 14, 5 },
5660786Sps	{ -1 }
5760786Sps};
5860786Sps
5960786Spsstatic const struct ramxlat
6060786Spsramddr3_wr[] = {
6160786Sps	{ 5, 1 }, { 6, 2 }, { 7, 3 }, { 8, 4 }, { 10, 5 }, { 12, 6 },
6260786Sps	/* the below are mentioned in some, but not all, ddr3 docs */
6360786Sps	{ 14, 7 }, { 15, 7 }, { 16, 0 },
6460786Sps	{ -1 }
6589019Sps};
6689019Sps
67191930Sdelphijstatic const struct ramxlat
68237613Sdelphijramddr3_cwl[] = {
69293190Sdelphij	{ 5, 0 }, { 6, 1 }, { 7, 2 }, { 8, 3 },
7060786Sps	/* the below are mentioned in some, but not all, ddr3 docs */
7160786Sps	{ 9, 4 }, { 10, 5 },
7260786Sps	{ -1 }
7360786Sps};
7460786Sps
7560786Spsint
7660786Spsnvkm_sddr3_calc(struct nvkm_ram *ram)
7760786Sps{
7860786Sps	int CWL, CL, WR, DLL = 0, ODT = 0;
7960786Sps
8060786Sps	DLL = !ram->next->bios.ramcfg_DLLoff;
8160786Sps
82237613Sdelphij	switch (ram->next->bios.timing_ver) {
8360786Sps	case 0x10:
8460786Sps		if (ram->next->bios.timing_hdr < 0x17) {
8560786Sps			/* XXX: NV50: Get CWL from the timing register */
8660786Sps			return -ENOSYS;
8760786Sps		}
8860786Sps		CWL = ram->next->bios.timing_10_CWL;
8960786Sps		CL  = ram->next->bios.timing_10_CL;
9060786Sps		WR  = ram->next->bios.timing_10_WR;
9160786Sps		ODT = ram->next->bios.timing_10_ODT;
9260786Sps		break;
9360786Sps	case 0x20:
9460786Sps		CWL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
9560786Sps		CL  = (ram->next->bios.timing[1] & 0x0000001f) >> 0;
9660786Sps		WR  = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
9760786Sps		/* XXX: Get these values from the VBIOS instead */
9860786Sps		ODT =   (ram->mr[1] & 0x004) >> 2 |
9960786Sps			(ram->mr[1] & 0x040) >> 5 |
10060786Sps		        (ram->mr[1] & 0x200) >> 7;
10160786Sps		break;
102221715Sdelphij	default:
10360786Sps		return -ENOSYS;
10460786Sps	}
10560786Sps
10660786Sps	CWL = ramxlat(ramddr3_cwl, CWL);
10760786Sps	CL  = ramxlat(ramddr3_cl, CL);
10860786Sps	WR  = ramxlat(ramddr3_wr, WR);
10960786Sps	if (CL < 0 || CWL < 0 || WR < 0)
11060786Sps		return -EINVAL;
11189019Sps
11260786Sps	ram->mr[0] &= ~0xf74;
11360786Sps	ram->mr[0] |= (WR & 0x07) << 9;
11460786Sps	ram->mr[0] |= (CL & 0x0e) << 3;
11560786Sps	ram->mr[0] |= (CL & 0x01) << 2;
11660786Sps
11760786Sps	ram->mr[1] &= ~0x245;
11860786Sps	ram->mr[1] |= (ODT & 0x1) << 2;
11960786Sps	ram->mr[1] |= (ODT & 0x2) << 5;
12060786Sps	ram->mr[1] |= (ODT & 0x4) << 7;
12160786Sps	ram->mr[1] |= !DLL;
12260786Sps
12360786Sps	ram->mr[2] &= ~0x038;
12460786Sps	ram->mr[2] |= (CWL & 0x07) << 3;
12560786Sps	return 0;
12660786Sps}
12760786Sps