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 "ram.h" 25 26 #include <subdev/bios.h> 27 #include <subdev/bios/init.h> 28 #include <subdev/bios/rammap.h> 29 30 static int 31 gp100_ram_init(struct nvkm_ram *ram) 32 { 33 struct nvkm_subdev *subdev = &ram->fb->subdev; 34 struct nvkm_device *device = subdev->device; 35 struct nvkm_bios *bios = device->bios; 36 u8 ver, hdr, cnt, len, snr, ssz; 37 u32 data; 38 int i; 39 40 /* run a bunch of tables from rammap table. there's actually 41 * individual pointers for each rammap entry too, but, nvidia 42 * seem to just run the last two entries' scripts early on in 43 * their init, and never again.. we'll just run 'em all once 44 * for now. 45 * 46 * i strongly suspect that each script is for a separate mode 47 * (likely selected by 0x9a065c's lower bits?), and the 48 * binary driver skips the one that's already been setup by 49 * the init tables. 50 */ 51 data = nvbios_rammapTe(bios, &ver, &hdr, &cnt, &len, &snr, &ssz); 52 if (!data || hdr < 0x15) 53 return -EINVAL; 54 55 cnt = nvbios_rd08(bios, data + 0x14); /* guess at count */ 56 data = nvbios_rd32(bios, data + 0x10); /* guess u32... */ 57 if (cnt) { 58 u32 save = nvkm_rd32(device, 0x9a065c) & 0x000000f0; 59 for (i = 0; i < cnt; i++, data += 4) { 60 if (i != save >> 4) { 61 nvkm_mask(device, 0x9a065c, 0x000000f0, i << 4); 62 nvbios_exec(&(struct nvbios_init) { 63 .subdev = subdev, 64 .bios = bios, 65 .offset = nvbios_rd32(bios, data), 66 .execute = 1, 67 }); 68 } 69 } 70 nvkm_mask(device, 0x9a065c, 0x000000f0, save); 71 } 72 73 nvkm_mask(device, 0x9a0584, 0x11000000, 0x00000000); 74 nvkm_wr32(device, 0x10ecc0, 0xffffffff); 75 nvkm_mask(device, 0x9a0160, 0x00000010, 0x00000010); 76 return 0; 77 } 78 79 static const struct nvkm_ram_func 80 gp100_ram_func = { 81 .init = gp100_ram_init, 82 .get = gf100_ram_get, 83 .put = gf100_ram_put, 84 }; 85 86 int 87 gp100_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) 88 { 89 struct nvkm_ram *ram; 90 struct nvkm_subdev *subdev = &fb->subdev; 91 struct nvkm_device *device = subdev->device; 92 enum nvkm_ram_type type = nvkm_fb_bios_memtype(device->bios); 93 const u32 rsvd_head = ( 256 * 1024); /* vga memory */ 94 const u32 rsvd_tail = (1024 * 1024); /* vbios etc */ 95 u32 fbpa_num = nvkm_rd32(device, 0x022438), fbpa; 96 u32 fbio_opt = nvkm_rd32(device, 0x021c14); 97 u64 part, size = 0, comm = ~0ULL; 98 bool mixed = false; 99 int ret; 100 101 nvkm_debug(subdev, "022438: %08x\n", fbpa_num); 102 nvkm_debug(subdev, "021c14: %08x\n", fbio_opt); 103 for (fbpa = 0; fbpa < fbpa_num; fbpa++) { 104 if (!(fbio_opt & (1 << fbpa))) { 105 part = nvkm_rd32(device, 0x90020c + (fbpa * 0x4000)); 106 nvkm_debug(subdev, "fbpa %02x: %lld MiB\n", fbpa, part); 107 part = part << 20; 108 if (part != comm) { 109 if (comm != ~0ULL) 110 mixed = true; 111 comm = min(comm, part); 112 } 113 size = size + part; 114 } 115 } 116 117 ret = nvkm_ram_new_(&gp100_ram_func, fb, type, size, 0, &ram); 118 *pram = ram; 119 if (ret) 120 return ret; 121 122 nvkm_mm_fini(&ram->vram); 123 124 if (mixed) { 125 ret = nvkm_mm_init(&ram->vram, rsvd_head >> NVKM_RAM_MM_SHIFT, 126 ((comm * fbpa_num) - rsvd_head) >> 127 NVKM_RAM_MM_SHIFT, 1); 128 if (ret) 129 return ret; 130 131 ret = nvkm_mm_init(&ram->vram, (0x1000000000ULL + comm) >> 132 NVKM_RAM_MM_SHIFT, 133 (size - (comm * fbpa_num) - rsvd_tail) >> 134 NVKM_RAM_MM_SHIFT, 1); 135 if (ret) 136 return ret; 137 } else { 138 ret = nvkm_mm_init(&ram->vram, rsvd_head >> NVKM_RAM_MM_SHIFT, 139 (size - rsvd_head - rsvd_tail) >> 140 NVKM_RAM_MM_SHIFT, 1); 141 if (ret) 142 return ret; 143 } 144 145 return 0; 146 } 147