diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2015-08-20 06:54:21 +0200 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2015-08-28 04:40:45 +0200 |
commit | 31649ecf47a44e02e73bffc5680c8f56d6cf587a (patch) | |
tree | d59914684674c64bb608fc01b65d7a05f4080c5b /drivers/gpu/drm/nouveau/nvkm/subdev | |
parent | drm/nouveau/therm: convert to new-style nvkm_subdev (diff) | |
download | linux-31649ecf47a44e02e73bffc5680c8f56d6cf587a.tar.xz linux-31649ecf47a44e02e73bffc5680c8f56d6cf587a.zip |
drm/nouveau/tmr: convert to new-style nvkm_subdev
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/subdev')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c | 127 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c | 45 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c | 227 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h | 25 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv40.c | 88 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv41.c | 85 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/timer/regsnv04.h | 7 |
14 files changed, 410 insertions, 249 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c index 860c8bc2b422..6689d0290a7e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c @@ -124,6 +124,7 @@ gk20a_pmu_dvfs_work(struct nvkm_alarm *alarm) struct nvkm_subdev *subdev = &pmu->base.subdev; struct nvkm_device *device = subdev->device; struct nvkm_clk *clk = device->clk; + struct nvkm_timer *tmr = device->timer; struct nvkm_volt *volt = device->volt; u32 utilization = 0; int state, ret; @@ -162,14 +163,14 @@ gk20a_pmu_dvfs_work(struct nvkm_alarm *alarm) resched: gk20a_pmu_dvfs_reset_dev_status(pmu); - nvkm_timer_alarm(pmu, 100000000, alarm); + nvkm_timer_alarm(tmr, 100000000, alarm); } static int gk20a_pmu_fini(struct nvkm_subdev *subdev, bool suspend) { struct gk20a_pmu *pmu = gk20a_pmu(subdev); - nvkm_timer_alarm_cancel(pmu, &pmu->alarm); + nvkm_timer_alarm_cancel(subdev->device->timer, &pmu->alarm); return 0; } @@ -190,7 +191,7 @@ gk20a_pmu_init(struct nvkm_subdev *subdev) nvkm_wr32(device, 0x10a50c + (BUSY_SLOT * 0x10), 0x00000002); nvkm_wr32(device, 0x10a50c + (CLK_SLOT * 0x10), 0x00000003); - nvkm_timer_alarm(pmu, 2000000000, &pmu->alarm); + nvkm_timer_alarm(device->timer, 2000000000, &pmu->alarm); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c index 304bdfc54445..949dc6101a58 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c @@ -102,7 +102,7 @@ nvkm_therm_update(struct nvkm_therm *therm, int mode) switch (mode) { case NVKM_THERM_CTRL_MANUAL: - tmr->alarm_cancel(tmr, &therm->alarm); + nvkm_timer_alarm_cancel(tmr, &therm->alarm); duty = nvkm_therm_fan_get(therm); if (duty < 0) duty = 100; @@ -126,12 +126,12 @@ nvkm_therm_update(struct nvkm_therm *therm, int mode) break; case NVKM_THERM_CTRL_NONE: default: - tmr->alarm_cancel(tmr, &therm->alarm); + nvkm_timer_alarm_cancel(tmr, &therm->alarm); poll = false; } if (list_empty(&therm->alarm.head) && poll) - tmr->alarm(tmr, 1000000000ULL, &therm->alarm); + nvkm_timer_alarm(tmr, 1000000000ULL, &therm->alarm); spin_unlock_irqrestore(&therm->lock, flags); if (duty >= 0) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c index a2be18167770..91198d79393a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c @@ -95,7 +95,7 @@ nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target) else delay = bump_period; - tmr->alarm(tmr, delay * 1000 * 1000, &fan->alarm); + nvkm_timer_alarm(tmr, delay * 1000 * 1000, &fan->alarm); } return ret; @@ -139,7 +139,7 @@ nvkm_therm_fan_sense(struct nvkm_therm *therm) * When the fan spins, it changes the value of GPIO FAN_SENSE. * We get 4 changes (0 -> 1 -> 0 -> 1) per complete rotation. */ - start = tmr->read(tmr); + start = nvkm_timer_read(tmr); prev = nvkm_gpio_get(gpio, 0, therm->fan->tach.func, therm->fan->tach.line); cycles = 0; @@ -150,12 +150,12 @@ nvkm_therm_fan_sense(struct nvkm_therm *therm) therm->fan->tach.line); if (prev != cur) { if (!start) - start = tmr->read(tmr); + start = nvkm_timer_read(tmr); cycles++; prev = cur; } - } while (cycles < 5 && tmr->read(tmr) - start < 250000000); - end = tmr->read(tmr); + } while (cycles < 5 && nvkm_timer_read(tmr) - start < 250000000); + end = nvkm_timer_read(tmr); if (cycles == 5) { tach = (u64)60000000000ULL; @@ -215,7 +215,7 @@ nvkm_therm_fan_fini(struct nvkm_therm *therm, bool suspend) { struct nvkm_timer *tmr = therm->subdev.device->timer; if (suspend) - tmr->alarm_cancel(tmr, &therm->fan->alarm); + nvkm_timer_alarm_cancel(tmr, &therm->fan->alarm); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c index 64fe8f22336c..59701b7a6597 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c @@ -57,7 +57,7 @@ nvkm_fantog_update(struct nvkm_fantog *fan, int percent) u64 next_change = (percent * fan->period_us) / 100; if (!duty) next_change = fan->period_us - next_change; - tmr->alarm(tmr, next_change * 1000, &fan->alarm); + nvkm_timer_alarm(tmr, next_change * 1000, &fan->alarm); } spin_unlock_irqrestore(&fan->lock, flags); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c index 4ab7ef7da254..b9703c02d8ca 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c @@ -186,7 +186,7 @@ alarm_timer_callback(struct nvkm_alarm *alarm) /* schedule the next poll in one second */ if (therm->func->temp_get(therm) >= 0 && list_empty(&alarm->head)) - tmr->alarm(tmr, 1000000000ULL, alarm); + nvkm_timer_alarm(tmr, 1000000000ULL, alarm); } void @@ -220,7 +220,7 @@ nvkm_therm_sensor_fini(struct nvkm_therm *therm, bool suspend) { struct nvkm_timer *tmr = therm->subdev.device->timer; if (suspend) - tmr->alarm_cancel(tmr, &therm->sensor.therm_poll_alarm); + nvkm_timer_alarm_cancel(tmr, &therm->sensor.therm_poll_alarm); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild index d1d38b4ba30a..e436f0ffe3f4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild @@ -1,3 +1,5 @@ nvkm-y += nvkm/subdev/timer/base.o nvkm-y += nvkm/subdev/timer/nv04.o +nvkm-y += nvkm/subdev/timer/nv40.o +nvkm-y += nvkm/subdev/timer/nv41.o nvkm-y += nvkm/subdev/timer/gk20a.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c index 4c34e2bd0487..d4dae1f12d62 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c @@ -21,18 +21,131 @@ * * Authors: Ben Skeggs */ -#include <subdev/timer.h> +#include "priv.h" + +u64 +nvkm_timer_read(struct nvkm_timer *tmr) +{ + return tmr->func->read(tmr); +} + +void +nvkm_timer_alarm_trigger(struct nvkm_timer *tmr) +{ + 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 <= nvkm_timer_read(tmr)) + 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); + tmr->func->alarm_init(tmr, alarm->timestamp); + } else { + tmr->func->alarm_fini(tmr); + } + 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); + } +} void -nvkm_timer_alarm(void *obj, u32 nsec, struct nvkm_alarm *alarm) +nvkm_timer_alarm(struct nvkm_timer *tmr, u32 nsec, struct nvkm_alarm *alarm) { - struct nvkm_timer *tmr = nvkm_timer(obj); - tmr->alarm(tmr, nsec, alarm); + struct nvkm_alarm *list; + unsigned long flags; + + alarm->timestamp = nvkm_timer_read(tmr) + nsec; + + /* append new alarm to list, in soonest-alarm-first order */ + spin_lock_irqsave(&tmr->lock, flags); + if (!nsec) { + 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 */ + nvkm_timer_alarm_trigger(tmr); } void -nvkm_timer_alarm_cancel(void *obj, struct nvkm_alarm *alarm) +nvkm_timer_alarm_cancel(struct nvkm_timer *tmr, struct nvkm_alarm *alarm) +{ + unsigned long flags; + spin_lock_irqsave(&tmr->lock, flags); + list_del_init(&alarm->head); + spin_unlock_irqrestore(&tmr->lock, flags); +} + +static void +nvkm_timer_intr(struct nvkm_subdev *subdev) { - struct nvkm_timer *tmr = nvkm_timer(obj); - tmr->alarm_cancel(tmr, alarm); + struct nvkm_timer *tmr = nvkm_timer(subdev); + tmr->func->intr(tmr); +} + +static int +nvkm_timer_fini(struct nvkm_subdev *subdev, bool suspend) +{ + struct nvkm_timer *tmr = nvkm_timer(subdev); + tmr->func->alarm_fini(tmr); + return 0; +} + +static int +nvkm_timer_init(struct nvkm_subdev *subdev) +{ + struct nvkm_timer *tmr = nvkm_timer(subdev); + if (tmr->func->init) + tmr->func->init(tmr); + tmr->func->time(tmr, ktime_to_ns(ktime_get())); + nvkm_timer_alarm_trigger(tmr); + return 0; +} + +static void * +nvkm_timer_dtor(struct nvkm_subdev *subdev) +{ + return nvkm_timer(subdev); +} + +static const struct nvkm_subdev_func +nvkm_timer = { + .dtor = nvkm_timer_dtor, + .init = nvkm_timer_init, + .fini = nvkm_timer_fini, + .intr = nvkm_timer_intr, +}; + +int +nvkm_timer_new_(const struct nvkm_timer_func *func, struct nvkm_device *device, + int index, struct nvkm_timer **ptmr) +{ + struct nvkm_timer *tmr; + + if (!(tmr = *ptmr = kzalloc(sizeof(*tmr), GFP_KERNEL))) + return -ENOMEM; + + nvkm_subdev_ctor(&nvkm_timer, device, index, 0, &tmr->subdev); + tmr->func = func; + INIT_LIST_HEAD(&tmr->alarms); + spin_lock_init(&tmr->lock); + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c index 46bfa10b5b97..9ed5f64912d0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c @@ -21,38 +21,19 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" -static int -gk20a_timer_init(struct nvkm_object *object) -{ - struct nv04_timer *tmr = (void *)object; - struct nvkm_subdev *subdev = &tmr->base.subdev; - struct nvkm_device *device = subdev->device; - u32 hi = upper_32_bits(tmr->suspend_time); - u32 lo = lower_32_bits(tmr->suspend_time); - int ret; - - ret = nvkm_timer_init(&tmr->base); - if (ret) - return ret; - - nvkm_debug(subdev, "time low : %08x\n", lo); - nvkm_debug(subdev, "time high : %08x\n", hi); +static const struct nvkm_timer_func +gk20a_timer = { + .intr = nv04_timer_intr, + .read = nv04_timer_read, + .time = nv04_timer_time, + .alarm_init = nv04_timer_alarm_init, + .alarm_fini = nv04_timer_alarm_fini, +}; - /* restore the time before suspend */ - nvkm_wr32(device, NV04_PTIMER_TIME_1, hi); - nvkm_wr32(device, NV04_PTIMER_TIME_0, lo); - return 0; +int +gk20a_timer_new(struct nvkm_device *device, int index, struct nvkm_timer **ptmr) +{ + return nvkm_timer_new_(&gk20a_timer, device, index, ptmr); } - -struct nvkm_oclass -gk20a_timer_oclass = { - .handle = NV_SUBDEV(TIMER, 0xff), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_timer_ctor, - .dtor = nv04_timer_dtor, - .init = gk20a_timer_init, - .fini = nv04_timer_fini, - } -}; 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, - } -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h deleted file mode 100644 index 1bc0d7c073ef..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef __NVKM_TIMER_NV04_H__ -#define __NVKM_TIMER_NV04_H__ -#include "priv.h" - -#define NV04_PTIMER_INTR_0 0x009100 -#define NV04_PTIMER_INTR_EN_0 0x009140 -#define NV04_PTIMER_NUMERATOR 0x009200 -#define NV04_PTIMER_DENOMINATOR 0x009210 -#define NV04_PTIMER_TIME_0 0x009400 -#define NV04_PTIMER_TIME_1 0x009410 -#define NV04_PTIMER_ALARM_0 0x009420 - -struct nv04_timer { - struct nvkm_timer base; - struct list_head alarms; - spinlock_t lock; - u64 suspend_time; -}; - -int nv04_timer_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void nv04_timer_dtor(struct nvkm_object *); -int nv04_timer_fini(struct nvkm_object *, bool); -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv40.c new file mode 100644 index 000000000000..bb99a152f26e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv40.c @@ -0,0 +1,88 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "priv.h" +#include "regsnv04.h" + +static void +nv40_timer_init(struct nvkm_timer *tmr) +{ + struct nvkm_subdev *subdev = &tmr->subdev; + struct nvkm_device *device = subdev->device; + u32 f = 0; /*XXX: figure this out */ + u32 n, d; + + /* aim for 31.25MHz, which gives us nanosecond timestamps */ + d = 1000000 / 32; + 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_warn(subdev, "unknown input clock freq\n"); + } + + /* reduce ratio to acceptable values */ + while (((n % 5) == 0) && ((d % 5) == 0)) { + n /= 5; + d /= 5; + } + + while (((n % 2) == 0) && ((d % 2) == 0)) { + n /= 2; + d /= 2; + } + + while (n > 0xffff || d > 0xffff) { + n >>= 1; + d >>= 1; + } + + nvkm_debug(subdev, "input frequency : %dHz\n", f); + nvkm_debug(subdev, "numerator : %08x\n", n); + nvkm_debug(subdev, "denominator : %08x\n", d); + nvkm_debug(subdev, "timer frequency : %dHz\n", f * d / n); + + nvkm_wr32(device, NV04_PTIMER_NUMERATOR, n); + nvkm_wr32(device, NV04_PTIMER_DENOMINATOR, d); +} + +static const struct nvkm_timer_func +nv40_timer = { + .init = nv40_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 +nv40_timer_new(struct nvkm_device *device, int index, struct nvkm_timer **ptmr) +{ + return nvkm_timer_new_(&nv40_timer, device, index, ptmr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv41.c new file mode 100644 index 000000000000..3cf9ec1b1b57 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv41.c @@ -0,0 +1,85 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "priv.h" +#include "regsnv04.h" + +static void +nv41_timer_init(struct nvkm_timer *tmr) +{ + struct nvkm_subdev *subdev = &tmr->subdev; + struct nvkm_device *device = subdev->device; + u32 f = device->crystal; + u32 m = 1, n, d; + + /* aim for 31.25MHz, which gives us nanosecond timestamps */ + d = 1000000 / 32; + n = f; + + while (n < (d * 2)) { + n += (n / m); + m++; + } + + /* reduce ratio to acceptable values */ + while (((n % 5) == 0) && ((d % 5) == 0)) { + n /= 5; + d /= 5; + } + + while (((n % 2) == 0) && ((d % 2) == 0)) { + n /= 2; + d /= 2; + } + + while (n > 0xffff || d > 0xffff) { + n >>= 1; + d >>= 1; + } + + 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_wr32(device, 0x009220, m - 1); + nvkm_wr32(device, NV04_PTIMER_NUMERATOR, n); + nvkm_wr32(device, NV04_PTIMER_DENOMINATOR, d); +} + +static const struct nvkm_timer_func +nv41_timer = { + .init = nv41_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 +nv41_timer_new(struct nvkm_device *device, int index, struct nvkm_timer **ptmr) +{ + return nvkm_timer_new_(&nv41_timer, device, index, ptmr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h index 08e29a3da188..f820ca2aeda4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h @@ -1,4 +1,26 @@ #ifndef __NVKM_TIMER_PRIV_H__ #define __NVKM_TIMER_PRIV_H__ +#define nvkm_timer(p) container_of((p), struct nvkm_timer, subdev) #include <subdev/timer.h> + +int nvkm_timer_new_(const struct nvkm_timer_func *, struct nvkm_device *, + int index, struct nvkm_timer **); + +struct nvkm_timer_func { + void (*init)(struct nvkm_timer *); + void (*intr)(struct nvkm_timer *); + u64 (*read)(struct nvkm_timer *); + void (*time)(struct nvkm_timer *, u64 time); + void (*alarm_init)(struct nvkm_timer *, u32 time); + void (*alarm_fini)(struct nvkm_timer *); +}; + +void nvkm_timer_alarm_trigger(struct nvkm_timer *); + +void nv04_timer_fini(struct nvkm_timer *); +void nv04_timer_intr(struct nvkm_timer *); +void nv04_timer_time(struct nvkm_timer *, u64); +u64 nv04_timer_read(struct nvkm_timer *); +void nv04_timer_alarm_init(struct nvkm_timer *, u32); +void nv04_timer_alarm_fini(struct nvkm_timer *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/regsnv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/regsnv04.h new file mode 100644 index 000000000000..10bef85b485e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/regsnv04.h @@ -0,0 +1,7 @@ +#define NV04_PTIMER_INTR_0 0x009100 +#define NV04_PTIMER_INTR_EN_0 0x009140 +#define NV04_PTIMER_NUMERATOR 0x009200 +#define NV04_PTIMER_DENOMINATOR 0x009210 +#define NV04_PTIMER_TIME_0 0x009400 +#define NV04_PTIMER_TIME_1 0x009410 +#define NV04_PTIMER_ALARM_0 0x009420 |