|
|
1.1 root 1: /* $Id: isil7170.c,v 1.3 2005/05/10 00:37:43 fredette Exp $ */
2:
3: /* ic/isil7170.c - implementation of Intersil 7170 emulation: */
4:
5: /*
6: * Copyright (c) 2004 Matt Fredette
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by Matt Fredette.
20: * 4. The name of the author may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33: * POSSIBILITY OF SUCH DAMAGE.
34: */
35:
36: #include <tme/common.h>
37: _TME_RCSID("$Id: isil7170.c,v 1.3 2005/05/10 00:37:43 fredette Exp $");
38:
39: /* includes: */
40: #include <tme/generic/bus-device.h>
41: #include <tme/ic/isil7170.h>
42: #include <tme/misc.h>
43: #include <time.h>
44: #include <sys/time.h>
45:
46: /* macros: */
47:
48: /* register addresses: */
49: #define TME_ISIL7170_REG_CSEC (0)
50: #define TME_ISIL7170_REG_HOUR (1)
51: #define TME_ISIL7170_REG_MIN (2)
52: #define TME_ISIL7170_REG_SEC (3)
53: #define TME_ISIL7170_REG_MON (4)
54: #define TME_ISIL7170_REG_DAY (5)
55: #define TME_ISIL7170_REG_YEAR (6)
56: #define TME_ISIL7170_REG_DOW (7)
57: #define TME_ISIL7170_REG_CMP_CSEC (8)
58: #define TME_ISIL7170_REG_CMP_HOUR (9)
59: #define TME_ISIL7170_REG_CMP_MIN (10)
60: #define TME_ISIL7170_REG_CMP_SEC (11)
61: #define TME_ISIL7170_REG_CMP_MON (12)
62: #define TME_ISIL7170_REG_CMP_DAY (13)
63: #define TME_ISIL7170_REG_CMP_YEAR (14)
64: #define TME_ISIL7170_REG_CMP_DOW (15)
65: #define TME_ISIL7170_REG_INT (16)
66: #define TME_ISIL7170_REG_CMD (17)
67: #define TME_ISIL7170_REGS_COUNT (32)
68:
69: /* bits in the Interrupt register: */
70: #define TME_ISIL7170_INT_PENDING TME_BIT(7) /* interrupt pending */
71: #define TME_ISIL7170_INT_DAY TME_BIT(6) /* day periodic interrupt */
72: #define TME_ISIL7170_INT_HOUR TME_BIT(5) /* hour periodic interrupt */
73: #define TME_ISIL7170_INT_MIN TME_BIT(4) /* minute periodic interrupt */
74: #define TME_ISIL7170_INT_SEC TME_BIT(3) /* second periodic interrupt */
75: #define TME_ISIL7170_INT_TSEC TME_BIT(2) /* 1/10 second periodic interrupt */
76: #define TME_ISIL7170_INT_HSEC TME_BIT(1) /* 1/100 periodic second interrupt */
77: #define TME_ISIL7170_INT_ALARM TME_BIT(0) /* time match interrupt */
78:
79: /* bits in the Command register: */
80: #define TME_ISIL7170_CMD_TEST TME_BIT(5) /* test mode */
81: #define TME_ISIL7170_CMD_INTENA TME_BIT(4) /* interrupt enable */
82: #define TME_ISIL7170_CMD_RUN TME_BIT(3) /* running */
83: #define TME_ISIL7170_CMD_FMT24 TME_BIT(2) /* 24-hour format (instead of 12-hour) */
84: #define TME_ISIL7170_CMD_FREQ_MASK (0x3) /* frequency mask */
85: #define TME_ISIL7170_CMD_FREQ_4M (0x3) /* frequency 4.194304MHz */
86: #define TME_ISIL7170_CMD_FREQ_2M (0x2) /* frequency 2.097152MHz */
87: #define TME_ISIL7170_CMD_FREQ_1M (0x1) /* frequency 1.048576MHz */
88: #define TME_ISIL7170_CMD_FREQ_32K (0x0) /* frequency 32.768KHz */
89:
90: /* year zero in the chip corresponds to 1968: */
91: #define TME_ISIL7170_REG_YEAR_0 (1968)
92:
93: /* define this to track interrupt rates, reporting once every N
94: seconds: */
95: #if 1
96: #define TME_ISIL7170_TRACK_INT_RATE (10)
97: #endif
98:
99: #define TME_ISIL7170_LOG_HANDLE(am) (&(am)->tme_isil7170_element->tme_element_log_handle)
100:
101: /* structures: */
102: struct tme_isil7170 {
103:
104: /* our simple bus device header: */
105: struct tme_bus_device tme_isil7170_device;
106: #define tme_isil7170_element tme_isil7170_device.tme_bus_device_element
107:
108: /* our socket: */
109: struct tme_isil7170_socket tme_isil7170_socket;
110: #define tme_isil7170_addr_shift tme_isil7170_socket.tme_isil7170_socket_addr_shift
111: #define tme_isil7170_port_least_lane tme_isil7170_socket.tme_isil7170_socket_port_least_lane
112: #define tme_isil7170_clock_basic tme_isil7170_socket.tme_isil7170_socket_clock_basic
113: #define tme_isil7170_int_signal tme_isil7170_socket.tme_isil7170_socket_int_signal
114:
115: /* our mutex: */
116: tme_mutex_t tme_isil7170_mutex;
117:
118: /* our timer condition: */
119: tme_cond_t tme_isil7170_cond_timer;
120:
121: /* this is nonzero iff callouts are running: */
122: int tme_isil7170_callouts_running;
123:
124: /* it's easiest to just model the chip as a chunk of memory: */
125: tme_uint8_t tme_isil7170_regs[TME_ISIL7170_REGS_COUNT];
126:
127: /* the real-time durations, in microseconds, of a hundredth of a
128: second and a tenth of a second: */
129: unsigned long tme_isil7170_clock_hsec_usec;
130: unsigned long tme_isil7170_clock_tsec_usec;
131:
132: /* if nonzero, the internal time-of-day needs to be updated: */
133: tme_uint8_t tme_isil7170_tod_update;
134:
135: /* if nonzero, the interrupt the timer thread is sleeping for: */
136: tme_uint8_t tme_isil7170_timer_sleeping;
137:
138: /* the interrupt mask: */
139: tme_uint8_t tme_isil7170_int_mask;
140:
141: /* nonzero if the interrupt signal is asserted: */
142: int tme_isil7170_int_asserted;
143:
144: /* any scaling factor: */
145: unsigned long tme_isil7170_clock_scale;
146:
147: #ifdef TME_ISIL7170_TRACK_INT_RATE
148:
149: /* the end time of this sample: */
150: struct timeval tme_isil7170_int_sample_time;
151:
152: /* the number of distinct interrupts that have been delivered during
153: this sample: */
154: unsigned long tme_isil7170_int_sample;
155: #endif /* TME_ISIL7170_TRACK_INT_RATE */
156: };
157:
158: /* the isil7170 bus router: */
159: static const tme_bus_lane_t tme_isil7170_router[TME_BUS_ROUTER_SIZE(TME_BUS8_LOG2)] = {
160:
161: /* [gen] initiator port size: 8 bits
162: [gen] initiator port least lane: 0: */
163: /* D7-D0 */ TME_BUS_LANE_ROUTE(0),
164: };
165:
166: /* this sets the frequency on an isil7170: */
167: static void
168: _tme_isil7170_freq(struct tme_isil7170 *isil7170)
169: {
170: tme_uint32_t clock_user, clock_basic;
171: unsigned long hsec_usec, tsec_usec;
172:
173: /* get the user clock frequency: */
174: switch (isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD] & TME_ISIL7170_CMD_FREQ_MASK) {
175: case TME_ISIL7170_CMD_FREQ_4M: clock_user = TME_ISIL7170_FREQ_4M; break;
176: case TME_ISIL7170_CMD_FREQ_2M: clock_user = TME_ISIL7170_FREQ_2M; break;
177: case TME_ISIL7170_CMD_FREQ_1M: clock_user = TME_ISIL7170_FREQ_1M; break;
178: default:
179: case TME_ISIL7170_CMD_FREQ_32K: clock_user = TME_ISIL7170_FREQ_32K; break;
180: }
181:
182: /* get the hardware basic clock frequency: */
183: clock_basic = isil7170->tme_isil7170_clock_basic;
184:
185: /* calculate the real-time durations, in microseconds, of a tenth
186: and hundredth of a second, given the actual basic clock into the
187: chip, and what the user claims is the basic clock into the chip.
188: we have to be careful to avoid overflow here: */
189: if (clock_user == clock_basic) {
190: hsec_usec = 10000;
191: tsec_usec = 100000;
192: }
193: else {
194: hsec_usec = ((1000 * clock_user) / (clock_basic / 10));
195: tsec_usec = ((1000 * clock_user) / (clock_basic / 100));
196: }
197:
198: /* scale the result: */
199: hsec_usec *= isil7170->tme_isil7170_clock_scale;
200: tsec_usec *= isil7170->tme_isil7170_clock_scale;
201:
202: isil7170->tme_isil7170_clock_hsec_usec = hsec_usec;
203: isil7170->tme_isil7170_clock_tsec_usec = tsec_usec;
204: }
205:
206: /* this makes isil7170 callouts. it must be called with the mutex held: */
207: static void
208: _tme_isil7170_callout(struct tme_isil7170 *isil7170)
209: {
210: struct tme_bus_connection *conn_bus;
211: int again;
212: int int_asserted;
213: int rc;
214:
215: /* if this function is already running in another thread, return
216: now. the other thread will do our work: */
217: if (isil7170->tme_isil7170_callouts_running) {
218: return;
219: }
220:
221: /* callouts are now running: */
222: isil7170->tme_isil7170_callouts_running = TRUE;
223:
224: /* get our bus connection: */
225: conn_bus = TME_ATOMIC_READ(struct tme_bus_connection *,
226: isil7170->tme_isil7170_device.tme_bus_device_connection);
227:
228: /* loop forever: */
229: for (again = TRUE; again;) {
230: again = FALSE;
231:
232: /* see if there are any pending, unmasked interrupts: */
233: int_asserted = (isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT]
234: & isil7170->tme_isil7170_int_mask);
235:
236: /* update our interrupt-pending flag: */
237: if (int_asserted) {
238: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT]
239: = ((isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT]
240: & ~TME_ISIL7170_INT_PENDING)
241: | (int_asserted
242: ? TME_ISIL7170_INT_PENDING
243: : 0));
244: }
245:
246: /* see if our interrupt signal should be asserted: */
247: int_asserted
248: = (int_asserted
249: && (isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD]
250: & TME_ISIL7170_CMD_INTENA));
251:
252: /* if our interrupt signal has changed: */
253: if (!int_asserted != !isil7170->tme_isil7170_int_asserted) {
254:
255: /* unlock our mutex: */
256: tme_mutex_unlock(&isil7170->tme_isil7170_mutex);
257:
258: rc = (*conn_bus->tme_bus_signal)
259: (conn_bus,
260: isil7170->tme_isil7170_int_signal
261: | (int_asserted
262: ? TME_BUS_SIGNAL_LEVEL_ASSERTED
263: : TME_BUS_SIGNAL_LEVEL_NEGATED));
264:
265: /* lock our mutex: */
266: tme_mutex_lock(&isil7170->tme_isil7170_mutex);
267:
268: /* if this call out succeeded, update the interrupt-asserted flag: */
269: if (rc == TME_OK) {
270: isil7170->tme_isil7170_int_asserted = int_asserted;
271: again = TRUE;
272: }
273: }
274: }
275:
276: /* there are no more callouts to make: */
277: isil7170->tme_isil7170_callouts_running = FALSE;
278: }
279:
280: /* this resets an isil7170: */
281: static void
282: _tme_isil7170_reset(struct tme_isil7170 *isil7170)
283: {
284:
285: /* clear the interrupt mask: */
286: isil7170->tme_isil7170_int_mask = 0;
287:
288: /* clear the command register: */
289: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD] = 0;
290:
291: /* update the frequency: */
292: _tme_isil7170_freq(isil7170);
293:
294: /* callout to update our interrupt signal: */
295: _tme_isil7170_callout(isil7170);
296: }
297:
298: /* the isil7170 timer thread: */
299: static void
300: _tme_isil7170_th_timer(struct tme_isil7170 *isil7170)
301: {
302: tme_uint8_t int_mask;
303: tme_uint32_t sleep_usec;
304: #ifdef TME_ISIL7170_TRACK_INT_RATE
305: struct timeval now;
306: #endif /* TME_ISIL7170_TRACK_INT_RATE */
307:
308: /* lock the mutex: */
309: tme_mutex_lock(&isil7170->tme_isil7170_mutex);
310:
311: /* loop forever: */
312: for (;;) {
313:
314: /* if we were sleeping: */
315: int_mask = isil7170->tme_isil7170_timer_sleeping;
316: isil7170->tme_isil7170_timer_sleeping = 0;
317: if (int_mask) {
318:
319: #ifdef TME_ISIL7170_TRACK_INT_RATE
320:
321: /* if no interrupt is pending, and this interrupt is not masked,
322: we will deliver another interrupt: */
323: if (!(isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT]
324: & TME_ISIL7170_INT_PENDING)
325: && (int_mask
326: & isil7170->tme_isil7170_int_mask)) {
327: isil7170->tme_isil7170_int_sample++;
328: }
329:
330: /* if the sample time has finished, report on the interrupt rate: */
331: gettimeofday(&now, NULL);
332: if (now.tv_sec > isil7170->tme_isil7170_int_sample_time.tv_sec
333: || (now.tv_sec == isil7170->tme_isil7170_int_sample_time.tv_sec
334: && now.tv_usec > isil7170->tme_isil7170_int_sample_time.tv_usec)) {
335: if (isil7170->tme_isil7170_int_sample > 0) {
336: tme_log(TME_ISIL7170_LOG_HANDLE(isil7170),
337: 0, TME_OK,
338: (TME_ISIL7170_LOG_HANDLE(isil7170),
339: "timer interrupt rate: %ld/sec",
340: (isil7170->tme_isil7170_int_sample
341: / (TME_ISIL7170_TRACK_INT_RATE
342: + now.tv_sec
343: - isil7170->tme_isil7170_int_sample_time.tv_sec))));
344: }
345:
346: /* reset the sample: */
347: isil7170->tme_isil7170_int_sample_time.tv_sec = now.tv_sec + TME_ISIL7170_TRACK_INT_RATE;
348: isil7170->tme_isil7170_int_sample_time.tv_usec = now.tv_usec;
349: isil7170->tme_isil7170_int_sample = 0;
350: }
351:
352: #endif /* TME_ISIL7170_TRACK_INT_RATE */
353:
354: /* update the interrupt register: */
355: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT] |= int_mask;
356:
357: /* callout to update our interrupt signal: */
358: _tme_isil7170_callout(isil7170);
359: }
360:
361: /* get the interrupt mask: */
362: int_mask = isil7170->tme_isil7170_int_mask;
363:
364: /* if the 1/100 second periodic interrupt is unmasked: */
365: if (int_mask & TME_ISIL7170_INT_HSEC) {
366: int_mask = TME_ISIL7170_INT_HSEC;
367: sleep_usec = isil7170->tme_isil7170_clock_hsec_usec;
368: }
369:
370: /* if the 1/10 second periodic interrupt is unmasked: */
371: else if (int_mask & TME_ISIL7170_INT_TSEC) {
372: int_mask = TME_ISIL7170_INT_TSEC;
373: sleep_usec = isil7170->tme_isil7170_clock_tsec_usec;
374: }
375:
376: /* otherwise, all periodic interrupts are masked. wait until one
377: of them is not: */
378: else {
379: tme_cond_wait_yield(&isil7170->tme_isil7170_cond_timer,
380: &isil7170->tme_isil7170_mutex);
381: continue;
382: }
383:
384: /* we are sleeping: */
385: isil7170->tme_isil7170_timer_sleeping = int_mask;
386:
387: /* unlock our mutex: */
388: tme_mutex_unlock(&isil7170->tme_isil7170_mutex);
389:
390: /* sleep: */
391: tme_thread_sleep_yield(0, sleep_usec);
392:
393: /* lock our mutex: */
394: tme_mutex_unlock(&isil7170->tme_isil7170_mutex);
395: }
396: /* NOTREACHED */
397: }
398:
399: /* the isil7170 bus cycle handler: */
400: static int
401: _tme_isil7170_bus_cycle(void *_isil7170, struct tme_bus_cycle *cycle_init)
402: {
403: struct tme_isil7170 *isil7170;
404: tme_bus_addr_t address, isil7170_address_last;
405: tme_uint8_t buffer, value, value_old;
406: struct tme_bus_cycle cycle_resp;
407: unsigned int reg;
408: struct timeval now;
409: time_t _now;
410: struct tm *now_tm, now_tm_buffer;
411:
412: /* recover our data structure: */
413: isil7170 = (struct tme_isil7170 *) _isil7170;
414:
415: /* the requested cycle must be within range: */
416: isil7170_address_last = isil7170->tme_isil7170_device.tme_bus_device_address_last;
417: assert(cycle_init->tme_bus_cycle_address <= isil7170_address_last);
418: assert(cycle_init->tme_bus_cycle_size <= (isil7170_address_last - cycle_init->tme_bus_cycle_address) + 1);
419:
420: /* get the register being accessed: */
421: address = cycle_init->tme_bus_cycle_address;
422: reg = address >> isil7170->tme_isil7170_addr_shift;
423:
424: /* lock the mutex: */
425: tme_mutex_lock(&isil7170->tme_isil7170_mutex);
426:
427: /* if the clock is running and this address is in the time-of-day
428: registers, or if this is a write to the command register: */
429: if (((isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD] & TME_ISIL7170_CMD_RUN)
430: && reg <= TME_ISIL7170_REG_DOW)
431: || (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE
432: && reg == TME_ISIL7170_REG_CMD)) {
433:
434: /* sample the time of day: */
435: gettimeofday(&now, NULL);
436: _now = now.tv_sec;
437: now_tm = gmtime_r(&_now, &now_tm_buffer);
438:
439: /* put the time-of-day into the registers: */
440: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CSEC] = now.tv_usec / 10000;
441: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_HOUR] = now_tm->tm_hour;
442: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_MIN] = now_tm->tm_min;
443: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_SEC] = now_tm->tm_sec;
444: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_MON] = now_tm->tm_mon + 1;
445: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_DAY] = now_tm->tm_mday;
446: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_YEAR] = (1900 + now_tm->tm_year) - TME_ISIL7170_REG_YEAR_0;
447: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_DOW] = now_tm->tm_wday;
448: }
449:
450: /* if this is a write: */
451: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
452:
453: /* run the bus cycle: */
454: cycle_resp.tme_bus_cycle_buffer = &buffer;
455: cycle_resp.tme_bus_cycle_lane_routing = tme_isil7170_router;
456: cycle_resp.tme_bus_cycle_address = 0;
457: cycle_resp.tme_bus_cycle_buffer_increment = 1;
458: cycle_resp.tme_bus_cycle_type = TME_BUS_CYCLE_READ;
459: cycle_resp.tme_bus_cycle_size = sizeof(buffer);
460: cycle_resp.tme_bus_cycle_port =
461: TME_BUS_CYCLE_PORT(isil7170->tme_isil7170_port_least_lane,
462: TME_BUS8_LOG2);
463: tme_bus_cycle_xfer(cycle_init, &cycle_resp);
464: value = buffer;
465:
466: /* log this write: */
467: tme_log(TME_ISIL7170_LOG_HANDLE(isil7170), 100000, TME_OK,
468: (TME_ISIL7170_LOG_HANDLE(isil7170),
469: "reg %d write %02x",
470: reg, value));
471:
472: /* dispatch on the register: */
473: switch (reg) {
474:
475: case TME_ISIL7170_REG_CSEC:
476: case TME_ISIL7170_REG_HOUR:
477: case TME_ISIL7170_REG_MIN:
478: case TME_ISIL7170_REG_SEC:
479: case TME_ISIL7170_REG_MON:
480: case TME_ISIL7170_REG_DAY:
481: case TME_ISIL7170_REG_YEAR:
482: case TME_ISIL7170_REG_DOW:
483:
484: /* flag that the time-of-day needs to be updated: */
485: isil7170->tme_isil7170_tod_update = TRUE;
486:
487: /* FALLTHROUGH */
488:
489: case TME_ISIL7170_REG_CMP_CSEC:
490: case TME_ISIL7170_REG_CMP_HOUR:
491: case TME_ISIL7170_REG_CMP_MIN:
492: case TME_ISIL7170_REG_CMP_SEC:
493: case TME_ISIL7170_REG_CMP_MON:
494: case TME_ISIL7170_REG_CMP_DAY:
495: case TME_ISIL7170_REG_CMP_YEAR:
496: case TME_ISIL7170_REG_CMP_DOW:
497:
498: /* update the register: */
499: isil7170->tme_isil7170_regs[reg] = value;
500: break;
501:
502: case TME_ISIL7170_REG_INT:
503:
504: /* we don't support the alarm interrupt, or any of the daily,
505: hourly, etc., interrupts: */
506: if (value & (TME_ISIL7170_INT_DAY
507: | TME_ISIL7170_INT_HOUR
508: | TME_ISIL7170_INT_MIN
509: | TME_ISIL7170_INT_SEC
510: | TME_ISIL7170_INT_ALARM)) {
511: abort();
512: }
513:
514: /* update the interrupt mask: */
515: isil7170->tme_isil7170_int_mask = (value & ~TME_ISIL7170_INT_PENDING);
516:
517: /* callout to update our interrupt signal: */
518: _tme_isil7170_callout(isil7170);
519:
520: /* notify the timer thread: */
521: tme_cond_notify(&isil7170->tme_isil7170_cond_timer, FALSE);
522:
523: break;
524:
525: case TME_ISIL7170_REG_CMD:
526:
527: /* we don't support the test mode: */
528: if (value & TME_ISIL7170_CMD_TEST) {
529: abort();
530: }
531:
532: /* update the command register: */
533: value_old = isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD];
534: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD] = value;
535:
536: /* if the frequency changed, update our periodic intervals: */
537: if ((value_old ^ value) & TME_ISIL7170_CMD_FREQ_MASK) {
538: _tme_isil7170_freq(isil7170);
539: }
540:
541: /* if the interrupt enable changed, callout to update our
542: interrupt signal: */
543: if ((value_old ^ value) & TME_ISIL7170_CMD_INTENA) {
544: _tme_isil7170_callout(isil7170);
545: }
546:
547: break;
548:
549: default:
550: /* ignore */
551: break;
552: }
553: }
554:
555: /* otherwise, this is a read: */
556: else {
557: assert(cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ);
558:
559: /* dispatch on the register: */
560: switch (reg) {
561:
562: case TME_ISIL7170_REG_CSEC:
563: case TME_ISIL7170_REG_HOUR:
564: case TME_ISIL7170_REG_MIN:
565: case TME_ISIL7170_REG_SEC:
566: case TME_ISIL7170_REG_MON:
567: case TME_ISIL7170_REG_DAY:
568: case TME_ISIL7170_REG_YEAR:
569: case TME_ISIL7170_REG_DOW:
570: case TME_ISIL7170_REG_CMP_CSEC:
571: case TME_ISIL7170_REG_CMP_HOUR:
572: case TME_ISIL7170_REG_CMP_MIN:
573: case TME_ISIL7170_REG_CMP_SEC:
574: case TME_ISIL7170_REG_CMP_MON:
575: case TME_ISIL7170_REG_CMP_DAY:
576: case TME_ISIL7170_REG_CMP_YEAR:
577: case TME_ISIL7170_REG_CMP_DOW:
578:
579: /* read the register: */
580: value = isil7170->tme_isil7170_regs[reg];
581: break;
582:
583: case TME_ISIL7170_REG_INT:
584:
585: /* reading the Interrupt register clears the interrupt: */
586: value = isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT];
587: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT] = 0;
588:
589: /* callout to update our interrupt signal: */
590: _tme_isil7170_callout(isil7170);
591:
592: break;
593:
594: /* the Command register, and all undefined registers, return
595: garbage when read: */
596: case TME_ISIL7170_REG_CMD:
597: default:
598: value = 0xff;
599: break;
600: }
601:
602: /* log this read: */
603: tme_log(TME_ISIL7170_LOG_HANDLE(isil7170), 100000, TME_OK,
604: (TME_ISIL7170_LOG_HANDLE(isil7170),
605: "reg %d read %02x",
606: reg, value));
607:
608: /* run the bus cycle: */
609: buffer = value;
610: cycle_resp.tme_bus_cycle_buffer = &buffer;
611: cycle_resp.tme_bus_cycle_lane_routing = tme_isil7170_router;
612: cycle_resp.tme_bus_cycle_address = 0;
613: cycle_resp.tme_bus_cycle_buffer_increment = 1;
614: cycle_resp.tme_bus_cycle_type = TME_BUS_CYCLE_WRITE;
615: cycle_resp.tme_bus_cycle_size = sizeof(buffer);
616: cycle_resp.tme_bus_cycle_port =
617: TME_BUS_CYCLE_PORT(isil7170->tme_isil7170_port_least_lane,
618: TME_BUS8_LOG2);
619: tme_bus_cycle_xfer(cycle_init, &cycle_resp);
620: }
621:
622: /* if the time-of-day registers have been updated, and the clock
623: is running: */
624: if (isil7170->tme_isil7170_tod_update
625: && (isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD]
626: & TME_ISIL7170_CMD_RUN)) {
627:
628: /* XXX update the host's time-of-day clock? */
629: isil7170->tme_isil7170_tod_update = FALSE;
630: }
631:
632: /* unlock the mutex: */
633: tme_mutex_unlock(&isil7170->tme_isil7170_mutex);
634:
635: /* no faults: */
636: return (TME_OK);
637: }
638:
639: /* the isil7170 TLB filler: */
640: static int
641: _tme_isil7170_tlb_fill(void *_isil7170, struct tme_bus_tlb *tlb,
642: tme_bus_addr_t address, unsigned int cycles)
643: {
644: struct tme_isil7170 *isil7170;
645: tme_bus_addr_t isil7170_address_last;
646:
647: /* recover our data structure: */
648: isil7170 = (struct tme_isil7170 *) _isil7170;
649:
650: /* the address must be within range: */
651: isil7170_address_last = isil7170->tme_isil7170_device.tme_bus_device_address_last;
652: assert(address <= isil7170_address_last);
653:
654: /* initialize the TLB entry: */
655: tme_bus_tlb_initialize(tlb);
656:
657: /* this TLB entry can cover the whole device: */
658: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, 0);
659: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, isil7170_address_last);
660:
661: /* allow reading and writing: */
662: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
663:
664: /* our bus cycle handler: */
665: tlb->tme_bus_tlb_cycle_private = isil7170;
666: tlb->tme_bus_tlb_cycle = _tme_isil7170_bus_cycle;
667:
668: return (TME_OK);
669: }
670:
671: /* the new isil7170 element function: */
672: TME_ELEMENT_NEW_DECL(tme_ic_isil7170) {
673: const struct tme_isil7170_socket *socket;
674: struct tme_isil7170 *isil7170;
675: struct tme_isil7170_socket socket_real;
676: tme_bus_addr_t address_mask;
677: unsigned long scale;
678: int arg_i;
679: int usage;
680:
681: /* dispatch on our socket version: */
682: socket = (const struct tme_isil7170_socket *) extra;
683: if (socket == NULL) {
684: tme_output_append_error(_output, _("need an ic socket"));
685: return (ENXIO);
686: }
687: switch (socket->tme_isil7170_socket_version) {
688: case TME_ISIL7170_SOCKET_0:
689: socket_real = *socket;
690: break;
691: default:
692: tme_output_append_error(_output, _("socket type"));
693: return (EOPNOTSUPP);
694: }
695:
696: /* check our arguments: */
697: usage = 0;
698: scale = 1;
699: arg_i = 1;
700: for (;;) {
701:
702: /* a scale factor: */
703: if (TME_ARG_IS(args[arg_i + 0], "scale")) {
704: scale = tme_misc_unumber_parse(args[arg_i + 1], 0);
705: if (scale == 0) {
706: usage = TRUE;
707: break;
708: }
709: arg_i += 2;
710: }
711:
712: /* if we ran out of arguments: */
713: else if (args[arg_i] == NULL) {
714:
715: break;
716: }
717:
718: /* otherwise this is a bad argument: */
719: else {
720: tme_output_append_error(_output,
721: "%s %s, ",
722: args[arg_i],
723: _("unexpected"));
724: usage = TRUE;
725: break;
726: }
727: }
728:
729: if (usage) {
730: tme_output_append_error(_output,
731: "%s %s [ scale %s ]",
732: _("usage:"),
733: args[0],
734: _("SCALE"));
735: return (EINVAL);
736: }
737:
738: /* start the isil7170 structure: */
739: isil7170 = tme_new0(struct tme_isil7170, 1);
740: isil7170->tme_isil7170_socket = socket_real;
741: isil7170->tme_isil7170_element = element;
742: isil7170->tme_isil7170_clock_scale = scale;
743: _tme_isil7170_reset(isil7170);
744:
745: /* figure our address mask, up to the nearest power of two: */
746: address_mask = TME_ISIL7170_REGS_COUNT << isil7170->tme_isil7170_addr_shift;
747: if (address_mask & (address_mask - 1)) {
748: for (; address_mask & (address_mask - 1); address_mask &= (address_mask - 1));
749: address_mask <<= 1;
750: }
751: address_mask -= 1;
752:
753: /* initialize our simple bus device descriptor: */
754: isil7170->tme_isil7170_device.tme_bus_device_tlb_fill = _tme_isil7170_tlb_fill;
755: isil7170->tme_isil7170_device.tme_bus_device_address_last = address_mask;
756:
757: /* start the timer thread: */
758: tme_mutex_init(&isil7170->tme_isil7170_mutex);
759: tme_cond_init(&isil7170->tme_isil7170_cond_reader);
760: tme_thread_create((tme_thread_t) _tme_isil7170_th_timer, isil7170);
761:
762: /* fill the element: */
763: element->tme_element_private = isil7170;
764: element->tme_element_connections_new = tme_bus_device_connections_new;
765:
766: return (TME_OK);
767: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.