summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c')
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c227
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,
- }
-};