diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c | 227 |
1 files changed, 57 insertions, 170 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c index 8d45753f65ac..7b9ce87f0617 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c @@ -21,9 +21,25 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" +#include "regsnv04.h" -static u64 +void +nv04_timer_time(struct nvkm_timer *tmr, u64 time) +{ + struct nvkm_subdev *subdev = &tmr->subdev; + struct nvkm_device *device = subdev->device; + u32 hi = upper_32_bits(time); + u32 lo = lower_32_bits(time); + + nvkm_debug(subdev, "time low : %08x\n", lo); + nvkm_debug(subdev, "time high : %08x\n", hi); + + nvkm_wr32(device, NV04_PTIMER_TIME_1, hi); + nvkm_wr32(device, NV04_PTIMER_TIME_0, lo); +} + +u64 nv04_timer_read(struct nvkm_timer *tmr) { struct nvkm_device *device = tmr->subdev.device; @@ -37,85 +53,30 @@ nv04_timer_read(struct nvkm_timer *tmr) return ((u64)hi << 32 | lo); } -static void -nv04_timer_alarm_trigger(struct nvkm_timer *obj) -{ - struct nv04_timer *tmr = container_of(obj, typeof(*tmr), base); - struct nvkm_device *device = tmr->base.subdev.device; - struct nvkm_alarm *alarm, *atemp; - unsigned long flags; - LIST_HEAD(exec); - - /* move any due alarms off the pending list */ - spin_lock_irqsave(&tmr->lock, flags); - list_for_each_entry_safe(alarm, atemp, &tmr->alarms, head) { - if (alarm->timestamp <= tmr->base.read(&tmr->base)) - list_move_tail(&alarm->head, &exec); - } - - /* reschedule interrupt for next alarm time */ - if (!list_empty(&tmr->alarms)) { - alarm = list_first_entry(&tmr->alarms, typeof(*alarm), head); - nvkm_wr32(device, NV04_PTIMER_ALARM_0, alarm->timestamp); - nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000001); - } else { - nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000000); - } - spin_unlock_irqrestore(&tmr->lock, flags); - - /* execute any pending alarm handlers */ - list_for_each_entry_safe(alarm, atemp, &exec, head) { - list_del_init(&alarm->head); - alarm->func(alarm); - } -} - -static void -nv04_timer_alarm(struct nvkm_timer *obj, u64 time, struct nvkm_alarm *alarm) +void +nv04_timer_alarm_fini(struct nvkm_timer *tmr) { - struct nv04_timer *tmr = container_of(obj, typeof(*tmr), base); - struct nvkm_alarm *list; - unsigned long flags; - - alarm->timestamp = tmr->base.read(&tmr->base) + time; - - /* append new alarm to list, in soonest-alarm-first order */ - spin_lock_irqsave(&tmr->lock, flags); - if (!time) { - if (!list_empty(&alarm->head)) - list_del(&alarm->head); - } else { - list_for_each_entry(list, &tmr->alarms, head) { - if (list->timestamp > alarm->timestamp) - break; - } - list_add_tail(&alarm->head, &list->head); - } - spin_unlock_irqrestore(&tmr->lock, flags); - - /* process pending alarms */ - nv04_timer_alarm_trigger(&tmr->base); + struct nvkm_device *device = tmr->subdev.device; + nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000000); } -static void -nv04_timer_alarm_cancel(struct nvkm_timer *obj, struct nvkm_alarm *alarm) +void +nv04_timer_alarm_init(struct nvkm_timer *tmr, u32 time) { - struct nv04_timer *tmr = container_of(obj, typeof(*tmr), base); - unsigned long flags; - spin_lock_irqsave(&tmr->lock, flags); - list_del_init(&alarm->head); - spin_unlock_irqrestore(&tmr->lock, flags); + struct nvkm_device *device = tmr->subdev.device; + nvkm_wr32(device, NV04_PTIMER_ALARM_0, time); + nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000001); } -static void -nv04_timer_intr(struct nvkm_subdev *subdev) +void +nv04_timer_intr(struct nvkm_timer *tmr) { - struct nv04_timer *tmr = (void *)subdev; - struct nvkm_device *device = tmr->base.subdev.device; + struct nvkm_subdev *subdev = &tmr->subdev; + struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, NV04_PTIMER_INTR_0); if (stat & 0x00000001) { - nv04_timer_alarm_trigger(&tmr->base); + nvkm_timer_alarm_trigger(tmr); nvkm_wr32(device, NV04_PTIMER_INTR_0, 0x00000001); stat &= ~0x00000001; } @@ -126,62 +87,26 @@ nv04_timer_intr(struct nvkm_subdev *subdev) } } -int -nv04_timer_fini(struct nvkm_object *object, bool suspend) -{ - struct nv04_timer *tmr = (void *)object; - struct nvkm_device *device = tmr->base.subdev.device; - if (suspend) - tmr->suspend_time = nv04_timer_read(&tmr->base); - nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000000); - return nvkm_timer_fini(&tmr->base, suspend); -} - -static int -nv04_timer_init(struct nvkm_object *object) +static void +nv04_timer_init(struct nvkm_timer *tmr) { - struct nv04_timer *tmr = (void *)object; - struct nvkm_subdev *subdev = &tmr->base.subdev; + struct nvkm_subdev *subdev = &tmr->subdev; struct nvkm_device *device = subdev->device; - u32 m = 1, f, n, d, lo, hi; - int ret; - - ret = nvkm_timer_init(&tmr->base); - if (ret) - return ret; + u32 f = 0; /*XXX: nvclk */ + u32 n, d; /* aim for 31.25MHz, which gives us nanosecond timestamps */ d = 1000000 / 32; - - /* determine base clock for timer source */ -#if 0 /*XXX*/ - if (device->chipset < 0x40) { - n = nvkm_hw_get_clock(device, PLL_CORE); - } else -#endif - if (device->chipset <= 0x40) { - /*XXX: figure this out */ - f = -1; - n = 0; - } else { - f = device->crystal; - n = f; - while (n < (d * 2)) { - n += (n / m); - m++; + n = f; + + if (!f) { + n = nvkm_rd32(device, NV04_PTIMER_NUMERATOR); + d = nvkm_rd32(device, NV04_PTIMER_DENOMINATOR); + if (!n || !d) { + n = 1; + d = 1; } - - nvkm_wr32(device, 0x009220, m - 1); - } - - if (!n) { nvkm_warn(subdev, "unknown input clock freq\n"); - if (!nvkm_rd32(device, NV04_PTIMER_NUMERATOR) || - !nvkm_rd32(device, NV04_PTIMER_DENOMINATOR)) { - nvkm_wr32(device, NV04_PTIMER_NUMERATOR, 1); - nvkm_wr32(device, NV04_PTIMER_DENOMINATOR, 1); - } - return 0; } /* reduce ratio to acceptable values */ @@ -200,65 +125,27 @@ nv04_timer_init(struct nvkm_object *object) d >>= 1; } - /* restore the time before suspend */ - lo = tmr->suspend_time; - hi = (tmr->suspend_time >> 32); - nvkm_debug(subdev, "input frequency : %dHz\n", f); - nvkm_debug(subdev, "input multiplier: %d\n", m); nvkm_debug(subdev, "numerator : %08x\n", n); nvkm_debug(subdev, "denominator : %08x\n", d); - nvkm_debug(subdev, "timer frequency : %dHz\n", (f * m) * d / n); - nvkm_debug(subdev, "time low : %08x\n", lo); - nvkm_debug(subdev, "time high : %08x\n", hi); + nvkm_debug(subdev, "timer frequency : %dHz\n", f * d / n); nvkm_wr32(device, NV04_PTIMER_NUMERATOR, n); nvkm_wr32(device, NV04_PTIMER_DENOMINATOR, d); - nvkm_wr32(device, NV04_PTIMER_INTR_0, 0xffffffff); - nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000000); - nvkm_wr32(device, NV04_PTIMER_TIME_1, hi); - nvkm_wr32(device, NV04_PTIMER_TIME_0, lo); - return 0; } -void -nv04_timer_dtor(struct nvkm_object *object) -{ - struct nv04_timer *tmr = (void *)object; - return nvkm_timer_destroy(&tmr->base); -} +static const struct nvkm_timer_func +nv04_timer = { + .init = nv04_timer_init, + .intr = nv04_timer_intr, + .read = nv04_timer_read, + .time = nv04_timer_time, + .alarm_init = nv04_timer_alarm_init, + .alarm_fini = nv04_timer_alarm_fini, +}; int -nv04_timer_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_timer_new(struct nvkm_device *device, int index, struct nvkm_timer **ptmr) { - struct nv04_timer *tmr; - int ret; - - ret = nvkm_timer_create(parent, engine, oclass, &tmr); - *pobject = nv_object(tmr); - if (ret) - return ret; - - tmr->base.subdev.intr = nv04_timer_intr; - tmr->base.read = nv04_timer_read; - tmr->base.alarm = nv04_timer_alarm; - tmr->base.alarm_cancel = nv04_timer_alarm_cancel; - tmr->suspend_time = 0; - - INIT_LIST_HEAD(&tmr->alarms); - spin_lock_init(&tmr->lock); - return 0; + return nvkm_timer_new_(&nv04_timer, device, index, ptmr); } - -struct nvkm_oclass -nv04_timer_oclass = { - .handle = NV_SUBDEV(TIMER, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_timer_ctor, - .dtor = nv04_timer_dtor, - .init = nv04_timer_init, - .fini = nv04_timer_fini, - } -}; |