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 <core/subdev.h> 25#include <core/device.h> 26#include <core/option.h> 27 28static struct lock_class_key nvkm_subdev_lock_class[NVKM_SUBDEV_NR]; 29 30const char * 31nvkm_subdev_name[NVKM_SUBDEV_NR] = { 32 [NVKM_SUBDEV_BAR ] = "bar", 33 [NVKM_SUBDEV_VBIOS ] = "bios", 34 [NVKM_SUBDEV_BUS ] = "bus", 35 [NVKM_SUBDEV_CLK ] = "clk", 36 [NVKM_SUBDEV_DEVINIT] = "devinit", 37 [NVKM_SUBDEV_FB ] = "fb", 38 [NVKM_SUBDEV_FUSE ] = "fuse", 39 [NVKM_SUBDEV_GPIO ] = "gpio", 40 [NVKM_SUBDEV_I2C ] = "i2c", 41 [NVKM_SUBDEV_IBUS ] = "priv", 42 [NVKM_SUBDEV_INSTMEM] = "imem", 43 [NVKM_SUBDEV_LTC ] = "ltc", 44 [NVKM_SUBDEV_MC ] = "mc", 45 [NVKM_SUBDEV_MMU ] = "mmu", 46 [NVKM_SUBDEV_MXM ] = "mxm", 47 [NVKM_SUBDEV_PCI ] = "pci", 48 [NVKM_SUBDEV_PMU ] = "pmu", 49 [NVKM_SUBDEV_THERM ] = "therm", 50 [NVKM_SUBDEV_TIMER ] = "tmr", 51 [NVKM_SUBDEV_VOLT ] = "volt", 52 [NVKM_ENGINE_BSP ] = "bsp", 53 [NVKM_ENGINE_CE0 ] = "ce0", 54 [NVKM_ENGINE_CE1 ] = "ce1", 55 [NVKM_ENGINE_CE2 ] = "ce2", 56 [NVKM_ENGINE_CIPHER ] = "cipher", 57 [NVKM_ENGINE_DISP ] = "disp", 58 [NVKM_ENGINE_DMAOBJ ] = "dma", 59 [NVKM_ENGINE_FIFO ] = "fifo", 60 [NVKM_ENGINE_GR ] = "gr", 61 [NVKM_ENGINE_IFB ] = "ifb", 62 [NVKM_ENGINE_ME ] = "me", 63 [NVKM_ENGINE_MPEG ] = "mpeg", 64 [NVKM_ENGINE_MSENC ] = "msenc", 65 [NVKM_ENGINE_MSPDEC ] = "mspdec", 66 [NVKM_ENGINE_MSPPP ] = "msppp", 67 [NVKM_ENGINE_MSVLD ] = "msvld", 68 [NVKM_ENGINE_PM ] = "pm", 69 [NVKM_ENGINE_SEC ] = "sec", 70 [NVKM_ENGINE_SW ] = "sw", 71 [NVKM_ENGINE_VIC ] = "vic", 72 [NVKM_ENGINE_VP ] = "vp", 73}; 74 75void 76nvkm_subdev_intr(struct nvkm_subdev *subdev) 77{ 78 if (subdev->func->intr) 79 subdev->func->intr(subdev); 80} 81 82int 83nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend) 84{ 85 struct nvkm_device *device = subdev->device; 86 const char *action = suspend ? "suspend" : "fini"; 87 u32 pmc_enable = subdev->pmc_enable; 88 s64 time; 89 90 nvkm_trace(subdev, "%s running...\n", action); 91 time = ktime_to_us(ktime_get()); 92 93 if (subdev->func->fini) { 94 int ret = subdev->func->fini(subdev, suspend); 95 if (ret) { 96 nvkm_error(subdev, "%s failed, %d\n", action, ret); 97 if (suspend) 98 return ret; 99 } 100 } 101 102 if (pmc_enable) { 103 nvkm_mask(device, 0x000200, pmc_enable, 0x00000000); 104 nvkm_mask(device, 0x000200, pmc_enable, pmc_enable); 105 nvkm_rd32(device, 0x000200); 106 } 107 108 time = ktime_to_us(ktime_get()) - time; 109 nvkm_trace(subdev, "%s completed in %lldus\n", action, time); 110 return 0; 111} 112 113int 114nvkm_subdev_preinit(struct nvkm_subdev *subdev) 115{ 116 s64 time; 117 118 nvkm_trace(subdev, "preinit running...\n"); 119 time = ktime_to_us(ktime_get()); 120 121 if (subdev->func->preinit) { 122 int ret = subdev->func->preinit(subdev); 123 if (ret) { 124 nvkm_error(subdev, "preinit failed, %d\n", ret); 125 return ret; 126 } 127 } 128 129 time = ktime_to_us(ktime_get()) - time; 130 nvkm_trace(subdev, "preinit completed in %lldus\n", time); 131 return 0; 132} 133 134int 135nvkm_subdev_init(struct nvkm_subdev *subdev) 136{ 137 s64 time; 138 int ret; 139 140 nvkm_trace(subdev, "init running...\n"); 141 time = ktime_to_us(ktime_get()); 142 143 if (subdev->func->oneinit && !subdev->oneinit) { 144 s64 time; 145 nvkm_trace(subdev, "one-time init running...\n"); 146 time = ktime_to_us(ktime_get()); 147 ret = subdev->func->oneinit(subdev); 148 if (ret) { 149 nvkm_error(subdev, "one-time init failed, %d\n", ret); 150 return ret; 151 } 152 153 subdev->oneinit = true; 154 time = ktime_to_us(ktime_get()) - time; 155 nvkm_trace(subdev, "one-time init completed in %lldus\n", time); 156 } 157 158 if (subdev->func->init) { 159 ret = subdev->func->init(subdev); 160 if (ret) { 161 nvkm_error(subdev, "init failed, %d\n", ret); 162 return ret; 163 } 164 } 165 166 time = ktime_to_us(ktime_get()) - time; 167 nvkm_trace(subdev, "init completed in %lldus\n", time); 168 return 0; 169} 170 171void 172nvkm_subdev_del(struct nvkm_subdev **psubdev) 173{ 174 struct nvkm_subdev *subdev = *psubdev; 175 s64 time; 176 177 if (subdev && !WARN_ON(!subdev->func)) { 178 nvkm_trace(subdev, "destroy running...\n"); 179 time = ktime_to_us(ktime_get()); 180 if (subdev->func->dtor) 181 *psubdev = subdev->func->dtor(subdev); 182 time = ktime_to_us(ktime_get()) - time; 183 nvkm_trace(subdev, "destroy completed in %lldus\n", time); 184 kfree(*psubdev); 185 *psubdev = NULL; 186 } 187} 188 189void 190nvkm_subdev_ctor(const struct nvkm_subdev_func *func, 191 struct nvkm_device *device, int index, u32 pmc_enable, 192 struct nvkm_subdev *subdev) 193{ 194 const char *name = nvkm_subdev_name[index]; 195 subdev->func = func; 196 subdev->device = device; 197 subdev->index = index; 198 subdev->pmc_enable = pmc_enable; 199 200 __mutex_init(&subdev->mutex, name, &nvkm_subdev_lock_class[index]); 201 subdev->debug = nvkm_dbgopt(device->dbgopt, name); 202} 203