1 /* 2 * Copyright 2012 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 "priv.h" 25 #include "ram.h" 26 27 #include <core/memory.h> 28 #include <core/option.h> 29 #include <subdev/bios.h> 30 #include <subdev/bios/M0203.h> 31 #include <engine/gr.h> 32 #include <engine/mpeg.h> 33 34 bool 35 nvkm_fb_memtype_valid(struct nvkm_fb *fb, u32 memtype) 36 { 37 return fb->func->memtype_valid(fb, memtype); 38 } 39 40 void 41 nvkm_fb_tile_fini(struct nvkm_fb *fb, int region, struct nvkm_fb_tile *tile) 42 { 43 fb->func->tile.fini(fb, region, tile); 44 } 45 46 void 47 nvkm_fb_tile_init(struct nvkm_fb *fb, int region, u32 addr, u32 size, 48 u32 pitch, u32 flags, struct nvkm_fb_tile *tile) 49 { 50 fb->func->tile.init(fb, region, addr, size, pitch, flags, tile); 51 } 52 53 void 54 nvkm_fb_tile_prog(struct nvkm_fb *fb, int region, struct nvkm_fb_tile *tile) 55 { 56 struct nvkm_device *device = fb->subdev.device; 57 if (fb->func->tile.prog) { 58 fb->func->tile.prog(fb, region, tile); 59 if (device->gr) 60 nvkm_engine_tile(&device->gr->engine, region); 61 if (device->mpeg) 62 nvkm_engine_tile(device->mpeg, region); 63 } 64 } 65 66 int 67 nvkm_fb_bios_memtype(struct nvkm_bios *bios) 68 { 69 struct nvkm_subdev *subdev = &bios->subdev; 70 struct nvkm_device *device = subdev->device; 71 const u8 ramcfg = (nvkm_rd32(device, 0x101000) & 0x0000003c) >> 2; 72 struct nvbios_M0203E M0203E; 73 u8 ver, hdr; 74 75 if (nvbios_M0203Em(bios, ramcfg, &ver, &hdr, &M0203E)) { 76 switch (M0203E.type) { 77 case M0203E_TYPE_DDR2 : return NVKM_RAM_TYPE_DDR2; 78 case M0203E_TYPE_DDR3 : return NVKM_RAM_TYPE_DDR3; 79 case M0203E_TYPE_GDDR3: return NVKM_RAM_TYPE_GDDR3; 80 case M0203E_TYPE_GDDR5: return NVKM_RAM_TYPE_GDDR5; 81 default: 82 nvkm_warn(subdev, "M0203E type %02x\n", M0203E.type); 83 return NVKM_RAM_TYPE_UNKNOWN; 84 } 85 } 86 87 nvkm_warn(subdev, "M0203E not matched!\n"); 88 return NVKM_RAM_TYPE_UNKNOWN; 89 } 90 91 static void 92 nvkm_fb_intr(struct nvkm_subdev *subdev) 93 { 94 struct nvkm_fb *fb = nvkm_fb(subdev); 95 if (fb->func->intr) 96 fb->func->intr(fb); 97 } 98 99 static int 100 nvkm_fb_oneinit(struct nvkm_subdev *subdev) 101 { 102 struct nvkm_fb *fb = nvkm_fb(subdev); 103 104 if (fb->func->ram_new) { 105 int ret = fb->func->ram_new(fb, &fb->ram); 106 if (ret) { 107 nvkm_error(subdev, "vram setup failed, %d\n", ret); 108 return ret; 109 } 110 } 111 112 if (fb->func->oneinit) { 113 int ret = fb->func->oneinit(fb); 114 if (ret) 115 return ret; 116 } 117 118 return 0; 119 } 120 121 static int 122 nvkm_fb_init(struct nvkm_subdev *subdev) 123 { 124 struct nvkm_fb *fb = nvkm_fb(subdev); 125 int ret, i; 126 127 if (fb->ram) { 128 ret = nvkm_ram_init(fb->ram); 129 if (ret) 130 return ret; 131 } 132 133 for (i = 0; i < fb->tile.regions; i++) 134 fb->func->tile.prog(fb, i, &fb->tile.region[i]); 135 136 if (fb->func->init) 137 fb->func->init(fb); 138 if (fb->func->init_page) 139 fb->func->init_page(fb); 140 if (fb->func->init_unkn) 141 fb->func->init_unkn(fb); 142 return 0; 143 } 144 145 static void * 146 nvkm_fb_dtor(struct nvkm_subdev *subdev) 147 { 148 struct nvkm_fb *fb = nvkm_fb(subdev); 149 int i; 150 151 nvkm_memory_del(&fb->mmu_wr); 152 nvkm_memory_del(&fb->mmu_rd); 153 154 for (i = 0; i < fb->tile.regions; i++) 155 fb->func->tile.fini(fb, i, &fb->tile.region[i]); 156 157 nvkm_ram_del(&fb->ram); 158 159 if (fb->func->dtor) 160 return fb->func->dtor(fb); 161 return fb; 162 } 163 164 static const struct nvkm_subdev_func 165 nvkm_fb = { 166 .dtor = nvkm_fb_dtor, 167 .oneinit = nvkm_fb_oneinit, 168 .init = nvkm_fb_init, 169 .intr = nvkm_fb_intr, 170 }; 171 172 void 173 nvkm_fb_ctor(const struct nvkm_fb_func *func, struct nvkm_device *device, 174 int index, struct nvkm_fb *fb) 175 { 176 nvkm_subdev_ctor(&nvkm_fb, device, index, &fb->subdev); 177 fb->func = func; 178 fb->tile.regions = fb->func->tile.regions; 179 fb->page = nvkm_longopt(device->cfgopt, "NvFbBigPage", 0); 180 } 181 182 int 183 nvkm_fb_new_(const struct nvkm_fb_func *func, struct nvkm_device *device, 184 int index, struct nvkm_fb **pfb) 185 { 186 if (!(*pfb = kzalloc(sizeof(**pfb), GFP_KERNEL))) 187 return -ENOMEM; 188 nvkm_fb_ctor(func, device, index, *pfb); 189 return 0; 190 } 191