1  /*
2   * Copyright 2013 Red Hat Inc.
3   *
4   * Permission is hereby granted, free of charge, to any person obtaining a
5   * copy of this software and associated documentation files (the "Software"),
6   * to deal in the Software without restriction, including without limitation
7   * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8   * and/or sell copies of the Software, and to permit persons to whom the
9   * Software is furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17   * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18   * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19   * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20   * OTHER DEALINGS IN THE SOFTWARE.
21   *
22   * Authors: Ben Skeggs
23   */
24  #include <subdev/bios.h>
25  #include <subdev/bios/bit.h>
26  #include <subdev/bios/rammap.h>
27  
28  u32
nvbios_rammapTe(struct nvkm_bios * bios,u8 * ver,u8 * hdr,u8 * cnt,u8 * len,u8 * snr,u8 * ssz)29  nvbios_rammapTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr,
30  		u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
31  {
32  	struct bit_entry bit_P;
33  	u32 rammap = 0x0000;
34  
35  	if (!bit_entry(bios, 'P', &bit_P)) {
36  		if (bit_P.version == 2)
37  			rammap = nvbios_rd32(bios, bit_P.offset + 4);
38  
39  		if (rammap) {
40  			*ver = nvbios_rd08(bios, rammap + 0);
41  			switch (*ver) {
42  			case 0x10:
43  			case 0x11:
44  				*hdr = nvbios_rd08(bios, rammap + 1);
45  				*cnt = nvbios_rd08(bios, rammap + 5);
46  				*len = nvbios_rd08(bios, rammap + 2);
47  				*snr = nvbios_rd08(bios, rammap + 4);
48  				*ssz = nvbios_rd08(bios, rammap + 3);
49  				return rammap;
50  			default:
51  				break;
52  			}
53  		}
54  	}
55  
56  	return 0x0000;
57  }
58  
59  u32
nvbios_rammapEe(struct nvkm_bios * bios,int idx,u8 * ver,u8 * hdr,u8 * cnt,u8 * len)60  nvbios_rammapEe(struct nvkm_bios *bios, int idx,
61  		u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
62  {
63  	u8  snr, ssz;
64  	u32 rammap = nvbios_rammapTe(bios, ver, hdr, cnt, len, &snr, &ssz);
65  	if (rammap && idx < *cnt) {
66  		rammap = rammap + *hdr + (idx * (*len + (snr * ssz)));
67  		*hdr = *len;
68  		*cnt = snr;
69  		*len = ssz;
70  		return rammap;
71  	}
72  	return 0x0000;
73  }
74  
75  /* Pretend a performance mode is also a rammap entry, helps coalesce entries
76   * later on */
77  u32
nvbios_rammapEp_from_perf(struct nvkm_bios * bios,u32 data,u8 size,struct nvbios_ramcfg * p)78  nvbios_rammapEp_from_perf(struct nvkm_bios *bios, u32 data, u8 size,
79  		struct nvbios_ramcfg *p)
80  {
81  	memset(p, 0x00, sizeof(*p));
82  
83  	p->rammap_00_16_20 = (nvbios_rd08(bios, data + 0x16) & 0x20) >> 5;
84  	p->rammap_00_16_40 = (nvbios_rd08(bios, data + 0x16) & 0x40) >> 6;
85  	p->rammap_00_17_02 = (nvbios_rd08(bios, data + 0x17) & 0x02) >> 1;
86  
87  	return data;
88  }
89  
90  u32
nvbios_rammapEp(struct nvkm_bios * bios,int idx,u8 * ver,u8 * hdr,u8 * cnt,u8 * len,struct nvbios_ramcfg * p)91  nvbios_rammapEp(struct nvkm_bios *bios, int idx,
92  		u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *p)
93  {
94  	u32 data = nvbios_rammapEe(bios, idx, ver, hdr, cnt, len), temp;
95  	memset(p, 0x00, sizeof(*p));
96  	p->rammap_ver = *ver;
97  	p->rammap_hdr = *hdr;
98  	switch (!!data * *ver) {
99  	case 0x10:
100  		p->rammap_min      =  nvbios_rd16(bios, data + 0x00);
101  		p->rammap_max      =  nvbios_rd16(bios, data + 0x02);
102  		p->rammap_10_04_02 = (nvbios_rd08(bios, data + 0x04) & 0x02) >> 1;
103  		p->rammap_10_04_08 = (nvbios_rd08(bios, data + 0x04) & 0x08) >> 3;
104  		break;
105  	case 0x11:
106  		p->rammap_min      =  nvbios_rd16(bios, data + 0x00);
107  		p->rammap_max      =  nvbios_rd16(bios, data + 0x02);
108  		p->rammap_11_08_01 = (nvbios_rd08(bios, data + 0x08) & 0x01) >> 0;
109  		p->rammap_11_08_0c = (nvbios_rd08(bios, data + 0x08) & 0x0c) >> 2;
110  		p->rammap_11_08_10 = (nvbios_rd08(bios, data + 0x08) & 0x10) >> 4;
111  		temp = nvbios_rd32(bios, data + 0x09);
112  		p->rammap_11_09_01ff = (temp & 0x000001ff) >> 0;
113  		p->rammap_11_0a_03fe = (temp & 0x0003fe00) >> 9;
114  		p->rammap_11_0a_0400 = (temp & 0x00040000) >> 18;
115  		p->rammap_11_0a_0800 = (temp & 0x00080000) >> 19;
116  		p->rammap_11_0b_01f0 = (temp & 0x01f00000) >> 20;
117  		p->rammap_11_0b_0200 = (temp & 0x02000000) >> 25;
118  		p->rammap_11_0b_0400 = (temp & 0x04000000) >> 26;
119  		p->rammap_11_0b_0800 = (temp & 0x08000000) >> 27;
120  		p->rammap_11_0d    =  nvbios_rd08(bios, data + 0x0d);
121  		p->rammap_11_0e    =  nvbios_rd08(bios, data + 0x0e);
122  		p->rammap_11_0f    =  nvbios_rd08(bios, data + 0x0f);
123  		p->rammap_11_11_0c = (nvbios_rd08(bios, data + 0x11) & 0x0c) >> 2;
124  		break;
125  	default:
126  		data = 0;
127  		break;
128  	}
129  	return data;
130  }
131  
132  u32
nvbios_rammapEm(struct nvkm_bios * bios,u16 mhz,u8 * ver,u8 * hdr,u8 * cnt,u8 * len,struct nvbios_ramcfg * info)133  nvbios_rammapEm(struct nvkm_bios *bios, u16 mhz,
134  		u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *info)
135  {
136  	int idx = 0;
137  	u32 data;
138  	while ((data = nvbios_rammapEp(bios, idx++, ver, hdr, cnt, len, info))) {
139  		if (mhz >= info->rammap_min && mhz <= info->rammap_max)
140  			break;
141  	}
142  	return data;
143  }
144  
145  u32
nvbios_rammapSe(struct nvkm_bios * bios,u32 data,u8 ever,u8 ehdr,u8 ecnt,u8 elen,int idx,u8 * ver,u8 * hdr)146  nvbios_rammapSe(struct nvkm_bios *bios, u32 data,
147  		u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx, u8 *ver, u8 *hdr)
148  {
149  	if (idx < ecnt) {
150  		data = data + ehdr + (idx * elen);
151  		*ver = ever;
152  		*hdr = elen;
153  		return data;
154  	}
155  	return 0;
156  }
157  
158  u32
nvbios_rammapSp_from_perf(struct nvkm_bios * bios,u32 data,u8 size,int idx,struct nvbios_ramcfg * p)159  nvbios_rammapSp_from_perf(struct nvkm_bios *bios, u32 data, u8 size, int idx,
160  		struct nvbios_ramcfg *p)
161  {
162  	data += (idx * size);
163  
164  	if (size < 11)
165  		return 0x00000000;
166  
167  	p->ramcfg_ver = 0;
168  	p->ramcfg_timing   =  nvbios_rd08(bios, data + 0x01);
169  	p->ramcfg_00_03_01 = (nvbios_rd08(bios, data + 0x03) & 0x01) >> 0;
170  	p->ramcfg_00_03_02 = (nvbios_rd08(bios, data + 0x03) & 0x02) >> 1;
171  	p->ramcfg_DLLoff   = (nvbios_rd08(bios, data + 0x03) & 0x04) >> 2;
172  	p->ramcfg_00_03_08 = (nvbios_rd08(bios, data + 0x03) & 0x08) >> 3;
173  	p->ramcfg_RON      = (nvbios_rd08(bios, data + 0x03) & 0x10) >> 3;
174  	p->ramcfg_FBVDDQ   = (nvbios_rd08(bios, data + 0x03) & 0x80) >> 7;
175  	p->ramcfg_00_04_02 = (nvbios_rd08(bios, data + 0x04) & 0x02) >> 1;
176  	p->ramcfg_00_04_04 = (nvbios_rd08(bios, data + 0x04) & 0x04) >> 2;
177  	p->ramcfg_00_04_20 = (nvbios_rd08(bios, data + 0x04) & 0x20) >> 5;
178  	p->ramcfg_00_05    = (nvbios_rd08(bios, data + 0x05) & 0xff) >> 0;
179  	p->ramcfg_00_06    = (nvbios_rd08(bios, data + 0x06) & 0xff) >> 0;
180  	p->ramcfg_00_07    = (nvbios_rd08(bios, data + 0x07) & 0xff) >> 0;
181  	p->ramcfg_00_08    = (nvbios_rd08(bios, data + 0x08) & 0xff) >> 0;
182  	p->ramcfg_00_09    = (nvbios_rd08(bios, data + 0x09) & 0xff) >> 0;
183  	p->ramcfg_00_0a_0f = (nvbios_rd08(bios, data + 0x0a) & 0x0f) >> 0;
184  	p->ramcfg_00_0a_f0 = (nvbios_rd08(bios, data + 0x0a) & 0xf0) >> 4;
185  
186  	return data;
187  }
188  
189  u32
nvbios_rammapSp(struct nvkm_bios * bios,u32 data,u8 ever,u8 ehdr,u8 ecnt,u8 elen,int idx,u8 * ver,u8 * hdr,struct nvbios_ramcfg * p)190  nvbios_rammapSp(struct nvkm_bios *bios, u32 data,
191  		u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
192  		u8 *ver, u8 *hdr, struct nvbios_ramcfg *p)
193  {
194  	data = nvbios_rammapSe(bios, data, ever, ehdr, ecnt, elen, idx, ver, hdr);
195  	p->ramcfg_ver = *ver;
196  	p->ramcfg_hdr = *hdr;
197  	switch (!!data * *ver) {
198  	case 0x10:
199  		p->ramcfg_timing   =  nvbios_rd08(bios, data + 0x01);
200  		p->ramcfg_10_02_01 = (nvbios_rd08(bios, data + 0x02) & 0x01) >> 0;
201  		p->ramcfg_10_02_02 = (nvbios_rd08(bios, data + 0x02) & 0x02) >> 1;
202  		p->ramcfg_10_02_04 = (nvbios_rd08(bios, data + 0x02) & 0x04) >> 2;
203  		p->ramcfg_10_02_08 = (nvbios_rd08(bios, data + 0x02) & 0x08) >> 3;
204  		p->ramcfg_10_02_10 = (nvbios_rd08(bios, data + 0x02) & 0x10) >> 4;
205  		p->ramcfg_10_02_20 = (nvbios_rd08(bios, data + 0x02) & 0x20) >> 5;
206  		p->ramcfg_DLLoff   = (nvbios_rd08(bios, data + 0x02) & 0x40) >> 6;
207  		p->ramcfg_10_03_0f = (nvbios_rd08(bios, data + 0x03) & 0x0f) >> 0;
208  		p->ramcfg_10_04_01 = (nvbios_rd08(bios, data + 0x04) & 0x01) >> 0;
209  		p->ramcfg_FBVDDQ   = (nvbios_rd08(bios, data + 0x04) & 0x08) >> 3;
210  		p->ramcfg_10_05    = (nvbios_rd08(bios, data + 0x05) & 0xff) >> 0;
211  		p->ramcfg_10_06    = (nvbios_rd08(bios, data + 0x06) & 0xff) >> 0;
212  		p->ramcfg_10_07    = (nvbios_rd08(bios, data + 0x07) & 0xff) >> 0;
213  		p->ramcfg_10_08    = (nvbios_rd08(bios, data + 0x08) & 0xff) >> 0;
214  		p->ramcfg_10_09_0f = (nvbios_rd08(bios, data + 0x09) & 0x0f) >> 0;
215  		p->ramcfg_10_09_f0 = (nvbios_rd08(bios, data + 0x09) & 0xf0) >> 4;
216  		break;
217  	case 0x11:
218  		p->ramcfg_timing   =  nvbios_rd08(bios, data + 0x00);
219  		p->ramcfg_11_01_01 = (nvbios_rd08(bios, data + 0x01) & 0x01) >> 0;
220  		p->ramcfg_11_01_02 = (nvbios_rd08(bios, data + 0x01) & 0x02) >> 1;
221  		p->ramcfg_11_01_04 = (nvbios_rd08(bios, data + 0x01) & 0x04) >> 2;
222  		p->ramcfg_11_01_08 = (nvbios_rd08(bios, data + 0x01) & 0x08) >> 3;
223  		p->ramcfg_11_01_10 = (nvbios_rd08(bios, data + 0x01) & 0x10) >> 4;
224  		p->ramcfg_DLLoff =   (nvbios_rd08(bios, data + 0x01) & 0x20) >> 5;
225  		p->ramcfg_11_01_40 = (nvbios_rd08(bios, data + 0x01) & 0x40) >> 6;
226  		p->ramcfg_11_01_80 = (nvbios_rd08(bios, data + 0x01) & 0x80) >> 7;
227  		p->ramcfg_11_02_03 = (nvbios_rd08(bios, data + 0x02) & 0x03) >> 0;
228  		p->ramcfg_11_02_04 = (nvbios_rd08(bios, data + 0x02) & 0x04) >> 2;
229  		p->ramcfg_11_02_08 = (nvbios_rd08(bios, data + 0x02) & 0x08) >> 3;
230  		p->ramcfg_11_02_10 = (nvbios_rd08(bios, data + 0x02) & 0x10) >> 4;
231  		p->ramcfg_11_02_40 = (nvbios_rd08(bios, data + 0x02) & 0x40) >> 6;
232  		p->ramcfg_11_02_80 = (nvbios_rd08(bios, data + 0x02) & 0x80) >> 7;
233  		p->ramcfg_11_03_0f = (nvbios_rd08(bios, data + 0x03) & 0x0f) >> 0;
234  		p->ramcfg_11_03_30 = (nvbios_rd08(bios, data + 0x03) & 0x30) >> 4;
235  		p->ramcfg_11_03_c0 = (nvbios_rd08(bios, data + 0x03) & 0xc0) >> 6;
236  		p->ramcfg_11_03_f0 = (nvbios_rd08(bios, data + 0x03) & 0xf0) >> 4;
237  		p->ramcfg_11_04    = (nvbios_rd08(bios, data + 0x04) & 0xff) >> 0;
238  		p->ramcfg_11_06    = (nvbios_rd08(bios, data + 0x06) & 0xff) >> 0;
239  		p->ramcfg_11_07_02 = (nvbios_rd08(bios, data + 0x07) & 0x02) >> 1;
240  		p->ramcfg_11_07_04 = (nvbios_rd08(bios, data + 0x07) & 0x04) >> 2;
241  		p->ramcfg_11_07_08 = (nvbios_rd08(bios, data + 0x07) & 0x08) >> 3;
242  		p->ramcfg_11_07_10 = (nvbios_rd08(bios, data + 0x07) & 0x10) >> 4;
243  		p->ramcfg_11_07_40 = (nvbios_rd08(bios, data + 0x07) & 0x40) >> 6;
244  		p->ramcfg_11_07_80 = (nvbios_rd08(bios, data + 0x07) & 0x80) >> 7;
245  		p->ramcfg_11_08_01 = (nvbios_rd08(bios, data + 0x08) & 0x01) >> 0;
246  		p->ramcfg_11_08_02 = (nvbios_rd08(bios, data + 0x08) & 0x02) >> 1;
247  		p->ramcfg_11_08_04 = (nvbios_rd08(bios, data + 0x08) & 0x04) >> 2;
248  		p->ramcfg_11_08_08 = (nvbios_rd08(bios, data + 0x08) & 0x08) >> 3;
249  		p->ramcfg_11_08_10 = (nvbios_rd08(bios, data + 0x08) & 0x10) >> 4;
250  		p->ramcfg_11_08_20 = (nvbios_rd08(bios, data + 0x08) & 0x20) >> 5;
251  		p->ramcfg_11_09    = (nvbios_rd08(bios, data + 0x09) & 0xff) >> 0;
252  		break;
253  	default:
254  		data = 0;
255  		break;
256  	}
257  	return data;
258  }
259