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 "nv04.h" 25 26 static u64 27 nv04_timer_read(struct nvkm_timer *tmr) 28 { 29 struct nvkm_device *device = tmr->subdev.device; 30 u32 hi, lo; 31 32 do { 33 hi = nvkm_rd32(device, NV04_PTIMER_TIME_1); 34 lo = nvkm_rd32(device, NV04_PTIMER_TIME_0); 35 } while (hi != nvkm_rd32(device, NV04_PTIMER_TIME_1)); 36 37 return ((u64)hi << 32 | lo); 38 } 39 40 static void 41 nv04_timer_alarm_trigger(struct nvkm_timer *obj) 42 { 43 struct nv04_timer *tmr = container_of(obj, typeof(*tmr), base); 44 struct nvkm_device *device = tmr->base.subdev.device; 45 struct nvkm_alarm *alarm, *atemp; 46 unsigned long flags; 47 LIST_HEAD(exec); 48 49 /* move any due alarms off the pending list */ 50 spin_lock_irqsave(&tmr->lock, flags); 51 list_for_each_entry_safe(alarm, atemp, &tmr->alarms, head) { 52 if (alarm->timestamp <= tmr->base.read(&tmr->base)) 53 list_move_tail(&alarm->head, &exec); 54 } 55 56 /* reschedule interrupt for next alarm time */ 57 if (!list_empty(&tmr->alarms)) { 58 alarm = list_first_entry(&tmr->alarms, typeof(*alarm), head); 59 nvkm_wr32(device, NV04_PTIMER_ALARM_0, alarm->timestamp); 60 nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000001); 61 } else { 62 nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000000); 63 } 64 spin_unlock_irqrestore(&tmr->lock, flags); 65 66 /* execute any pending alarm handlers */ 67 list_for_each_entry_safe(alarm, atemp, &exec, head) { 68 list_del_init(&alarm->head); 69 alarm->func(alarm); 70 } 71 } 72 73 static void 74 nv04_timer_alarm(struct nvkm_timer *obj, u64 time, struct nvkm_alarm *alarm) 75 { 76 struct nv04_timer *tmr = container_of(obj, typeof(*tmr), base); 77 struct nvkm_alarm *list; 78 unsigned long flags; 79 80 alarm->timestamp = tmr->base.read(&tmr->base) + time; 81 82 /* append new alarm to list, in soonest-alarm-first order */ 83 spin_lock_irqsave(&tmr->lock, flags); 84 if (!time) { 85 if (!list_empty(&alarm->head)) 86 list_del(&alarm->head); 87 } else { 88 list_for_each_entry(list, &tmr->alarms, head) { 89 if (list->timestamp > alarm->timestamp) 90 break; 91 } 92 list_add_tail(&alarm->head, &list->head); 93 } 94 spin_unlock_irqrestore(&tmr->lock, flags); 95 96 /* process pending alarms */ 97 nv04_timer_alarm_trigger(&tmr->base); 98 } 99 100 static void 101 nv04_timer_alarm_cancel(struct nvkm_timer *obj, struct nvkm_alarm *alarm) 102 { 103 struct nv04_timer *tmr = container_of(obj, typeof(*tmr), base); 104 unsigned long flags; 105 spin_lock_irqsave(&tmr->lock, flags); 106 list_del_init(&alarm->head); 107 spin_unlock_irqrestore(&tmr->lock, flags); 108 } 109 110 static void 111 nv04_timer_intr(struct nvkm_subdev *subdev) 112 { 113 struct nv04_timer *tmr = (void *)subdev; 114 struct nvkm_device *device = tmr->base.subdev.device; 115 u32 stat = nvkm_rd32(device, NV04_PTIMER_INTR_0); 116 117 if (stat & 0x00000001) { 118 nv04_timer_alarm_trigger(&tmr->base); 119 nvkm_wr32(device, NV04_PTIMER_INTR_0, 0x00000001); 120 stat &= ~0x00000001; 121 } 122 123 if (stat) { 124 nvkm_error(subdev, "intr %08x\n", stat); 125 nvkm_wr32(device, NV04_PTIMER_INTR_0, stat); 126 } 127 } 128 129 int 130 nv04_timer_fini(struct nvkm_object *object, bool suspend) 131 { 132 struct nv04_timer *tmr = (void *)object; 133 struct nvkm_device *device = tmr->base.subdev.device; 134 if (suspend) 135 tmr->suspend_time = nv04_timer_read(&tmr->base); 136 nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000000); 137 return nvkm_timer_fini(&tmr->base, suspend); 138 } 139 140 static int 141 nv04_timer_init(struct nvkm_object *object) 142 { 143 struct nv04_timer *tmr = (void *)object; 144 struct nvkm_subdev *subdev = &tmr->base.subdev; 145 struct nvkm_device *device = subdev->device; 146 u32 m = 1, f, n, d, lo, hi; 147 int ret; 148 149 ret = nvkm_timer_init(&tmr->base); 150 if (ret) 151 return ret; 152 153 /* aim for 31.25MHz, which gives us nanosecond timestamps */ 154 d = 1000000 / 32; 155 156 /* determine base clock for timer source */ 157 #if 0 /*XXX*/ 158 if (device->chipset < 0x40) { 159 n = nvkm_hw_get_clock(device, PLL_CORE); 160 } else 161 #endif 162 if (device->chipset <= 0x40) { 163 /*XXX: figure this out */ 164 f = -1; 165 n = 0; 166 } else { 167 f = device->crystal; 168 n = f; 169 while (n < (d * 2)) { 170 n += (n / m); 171 m++; 172 } 173 174 nvkm_wr32(device, 0x009220, m - 1); 175 } 176 177 if (!n) { 178 nvkm_warn(subdev, "unknown input clock freq\n"); 179 if (!nvkm_rd32(device, NV04_PTIMER_NUMERATOR) || 180 !nvkm_rd32(device, NV04_PTIMER_DENOMINATOR)) { 181 nvkm_wr32(device, NV04_PTIMER_NUMERATOR, 1); 182 nvkm_wr32(device, NV04_PTIMER_DENOMINATOR, 1); 183 } 184 return 0; 185 } 186 187 /* reduce ratio to acceptable values */ 188 while (((n % 5) == 0) && ((d % 5) == 0)) { 189 n /= 5; 190 d /= 5; 191 } 192 193 while (((n % 2) == 0) && ((d % 2) == 0)) { 194 n /= 2; 195 d /= 2; 196 } 197 198 while (n > 0xffff || d > 0xffff) { 199 n >>= 1; 200 d >>= 1; 201 } 202 203 /* restore the time before suspend */ 204 lo = tmr->suspend_time; 205 hi = (tmr->suspend_time >> 32); 206 207 nvkm_debug(subdev, "input frequency : %dHz\n", f); 208 nvkm_debug(subdev, "input multiplier: %d\n", m); 209 nvkm_debug(subdev, "numerator : %08x\n", n); 210 nvkm_debug(subdev, "denominator : %08x\n", d); 211 nvkm_debug(subdev, "timer frequency : %dHz\n", (f * m) * d / n); 212 nvkm_debug(subdev, "time low : %08x\n", lo); 213 nvkm_debug(subdev, "time high : %08x\n", hi); 214 215 nvkm_wr32(device, NV04_PTIMER_NUMERATOR, n); 216 nvkm_wr32(device, NV04_PTIMER_DENOMINATOR, d); 217 nvkm_wr32(device, NV04_PTIMER_INTR_0, 0xffffffff); 218 nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000000); 219 nvkm_wr32(device, NV04_PTIMER_TIME_1, hi); 220 nvkm_wr32(device, NV04_PTIMER_TIME_0, lo); 221 return 0; 222 } 223 224 void 225 nv04_timer_dtor(struct nvkm_object *object) 226 { 227 struct nv04_timer *tmr = (void *)object; 228 return nvkm_timer_destroy(&tmr->base); 229 } 230 231 int 232 nv04_timer_ctor(struct nvkm_object *parent, struct nvkm_object *engine, 233 struct nvkm_oclass *oclass, void *data, u32 size, 234 struct nvkm_object **pobject) 235 { 236 struct nv04_timer *tmr; 237 int ret; 238 239 ret = nvkm_timer_create(parent, engine, oclass, &tmr); 240 *pobject = nv_object(tmr); 241 if (ret) 242 return ret; 243 244 tmr->base.subdev.intr = nv04_timer_intr; 245 tmr->base.read = nv04_timer_read; 246 tmr->base.alarm = nv04_timer_alarm; 247 tmr->base.alarm_cancel = nv04_timer_alarm_cancel; 248 tmr->suspend_time = 0; 249 250 INIT_LIST_HEAD(&tmr->alarms); 251 spin_lock_init(&tmr->lock); 252 return 0; 253 } 254 255 struct nvkm_oclass 256 nv04_timer_oclass = { 257 .handle = NV_SUBDEV(TIMER, 0x04), 258 .ofuncs = &(struct nvkm_ofuncs) { 259 .ctor = nv04_timer_ctor, 260 .dtor = nv04_timer_dtor, 261 .init = nv04_timer_init, 262 .fini = nv04_timer_fini, 263 } 264 }; 265