Commit | Line | Data |
---|---|---|
5a5c7432 BS |
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 | */ | |
31649ecf BS |
24 | #include "priv.h" |
25 | #include "regsnv04.h" | |
5a5c7432 | 26 | |
31649ecf BS |
27 | void |
28 | nv04_timer_time(struct nvkm_timer *tmr, u64 time) | |
29 | { | |
30 | struct nvkm_subdev *subdev = &tmr->subdev; | |
31 | struct nvkm_device *device = subdev->device; | |
32 | u32 hi = upper_32_bits(time); | |
33 | u32 lo = lower_32_bits(time); | |
34 | ||
35 | nvkm_debug(subdev, "time low : %08x\n", lo); | |
36 | nvkm_debug(subdev, "time high : %08x\n", hi); | |
37 | ||
38 | nvkm_wr32(device, NV04_PTIMER_TIME_1, hi); | |
39 | nvkm_wr32(device, NV04_PTIMER_TIME_0, lo); | |
40 | } | |
41 | ||
42 | u64 | |
cb8bb9ce | 43 | nv04_timer_read(struct nvkm_timer *tmr) |
5a5c7432 | 44 | { |
c44c049f | 45 | struct nvkm_device *device = tmr->subdev.device; |
5a5c7432 BS |
46 | u32 hi, lo; |
47 | ||
48 | do { | |
c44c049f BS |
49 | hi = nvkm_rd32(device, NV04_PTIMER_TIME_1); |
50 | lo = nvkm_rd32(device, NV04_PTIMER_TIME_0); | |
51 | } while (hi != nvkm_rd32(device, NV04_PTIMER_TIME_1)); | |
5a5c7432 BS |
52 | |
53 | return ((u64)hi << 32 | lo); | |
54 | } | |
55 | ||
31649ecf BS |
56 | void |
57 | nv04_timer_alarm_fini(struct nvkm_timer *tmr) | |
6ee73861 | 58 | { |
31649ecf BS |
59 | struct nvkm_device *device = tmr->subdev.device; |
60 | nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000000); | |
5a5c7432 BS |
61 | } |
62 | ||
31649ecf BS |
63 | void |
64 | nv04_timer_alarm_init(struct nvkm_timer *tmr, u32 time) | |
b925a75d | 65 | { |
31649ecf BS |
66 | struct nvkm_device *device = tmr->subdev.device; |
67 | nvkm_wr32(device, NV04_PTIMER_ALARM_0, time); | |
68 | nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000001); | |
b925a75d MP |
69 | } |
70 | ||
31649ecf BS |
71 | void |
72 | nv04_timer_intr(struct nvkm_timer *tmr) | |
5a5c7432 | 73 | { |
31649ecf BS |
74 | struct nvkm_subdev *subdev = &tmr->subdev; |
75 | struct nvkm_device *device = subdev->device; | |
c44c049f | 76 | u32 stat = nvkm_rd32(device, NV04_PTIMER_INTR_0); |
5a5c7432 BS |
77 | |
78 | if (stat & 0x00000001) { | |
31649ecf | 79 | nvkm_timer_alarm_trigger(tmr); |
c44c049f | 80 | nvkm_wr32(device, NV04_PTIMER_INTR_0, 0x00000001); |
5a5c7432 BS |
81 | stat &= ~0x00000001; |
82 | } | |
83 | ||
84 | if (stat) { | |
9d7b9d9f | 85 | nvkm_error(subdev, "intr %08x\n", stat); |
c44c049f | 86 | nvkm_wr32(device, NV04_PTIMER_INTR_0, stat); |
5a5c7432 BS |
87 | } |
88 | } | |
89 | ||
31649ecf BS |
90 | static void |
91 | nv04_timer_init(struct nvkm_timer *tmr) | |
5a5c7432 | 92 | { |
31649ecf | 93 | struct nvkm_subdev *subdev = &tmr->subdev; |
9d7b9d9f | 94 | struct nvkm_device *device = subdev->device; |
31649ecf BS |
95 | u32 f = 0; /*XXX: nvclk */ |
96 | u32 n, d; | |
6ee73861 | 97 | |
591b06d7 | 98 | /* aim for 31.25MHz, which gives us nanosecond timestamps */ |
afb0c796 | 99 | d = 1000000 / 32; |
31649ecf BS |
100 | n = f; |
101 | ||
102 | if (!f) { | |
103 | n = nvkm_rd32(device, NV04_PTIMER_NUMERATOR); | |
104 | d = nvkm_rd32(device, NV04_PTIMER_DENOMINATOR); | |
105 | if (!n || !d) { | |
106 | n = 1; | |
107 | d = 1; | |
591b06d7 | 108 | } |
9d7b9d9f | 109 | nvkm_warn(subdev, "unknown input clock freq\n"); |
591b06d7 BS |
110 | } |
111 | ||
112 | /* reduce ratio to acceptable values */ | |
113 | while (((n % 5) == 0) && ((d % 5) == 0)) { | |
114 | n /= 5; | |
115 | d /= 5; | |
116 | } | |
117 | ||
118 | while (((n % 2) == 0) && ((d % 2) == 0)) { | |
119 | n /= 2; | |
120 | d /= 2; | |
121 | } | |
122 | ||
123 | while (n > 0xffff || d > 0xffff) { | |
124 | n >>= 1; | |
125 | d >>= 1; | |
126 | } | |
127 | ||
9d7b9d9f | 128 | nvkm_debug(subdev, "input frequency : %dHz\n", f); |
9d7b9d9f BS |
129 | nvkm_debug(subdev, "numerator : %08x\n", n); |
130 | nvkm_debug(subdev, "denominator : %08x\n", d); | |
31649ecf | 131 | nvkm_debug(subdev, "timer frequency : %dHz\n", f * d / n); |
cb8bb9ce | 132 | |
c44c049f BS |
133 | nvkm_wr32(device, NV04_PTIMER_NUMERATOR, n); |
134 | nvkm_wr32(device, NV04_PTIMER_DENOMINATOR, d); | |
6ee73861 BS |
135 | } |
136 | ||
31649ecf BS |
137 | static const struct nvkm_timer_func |
138 | nv04_timer = { | |
139 | .init = nv04_timer_init, | |
140 | .intr = nv04_timer_intr, | |
141 | .read = nv04_timer_read, | |
142 | .time = nv04_timer_time, | |
143 | .alarm_init = nv04_timer_alarm_init, | |
144 | .alarm_fini = nv04_timer_alarm_fini, | |
145 | }; | |
57f74220 BS |
146 | |
147 | int | |
31649ecf | 148 | nv04_timer_new(struct nvkm_device *device, int index, struct nvkm_timer **ptmr) |
57f74220 | 149 | { |
31649ecf | 150 | return nvkm_timer_new_(&nv04_timer, device, index, ptmr); |
6ee73861 | 151 | } |