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