|
|
1.1 root 1: /* $Id: mm58167.c,v 1.4 2003/05/16 21:48:10 fredette Exp $ */
2:
3: /* ic/ic-vol0/mm58167.c - implementation of National Semiconductor MM58167 emulation: */
4:
5: /*
6: * Copyright (c) 2003 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: mm58167.c,v 1.4 2003/05/16 21:48:10 fredette Exp $");
38:
39: /* includes: */
40: #include <tme/generic/bus-device.h>
41: #include <tme/ic/mm58167.h>
42: #include <time.h>
43:
44: /* macros: */
45:
46: /* register addresses: */
47: #define TME_MM58167_REG_MSEC_XXX (0)
48: #define TME_MM58167_REG_CSEC (1)
49: #define TME_MM58167_REG_SEC (2)
50: #define TME_MM58167_REG_MIN (3)
51: #define TME_MM58167_REG_HOUR (4)
52: #define TME_MM58167_REG_WDAY (5)
53: #define TME_MM58167_REG_DAY (6)
54: #define TME_MM58167_REG_MON (7)
55: #define TME_MM58167_REG_STATUS (20)
56: #define TME_MM58167_REG_GO (21)
57: #define TME_MM58167_REG_BANK_SZ (24)
58:
59: /* bits in the status register: */
60: #define TME_MM58167_STATUS_RIPPLING TME_BIT(0)
61:
62: #define TME_MM58167_LOG_HANDLE(mm) (&(mm)->tme_mm58167_element->tme_element_log_handle)
63:
64: /* structures: */
65:
66: struct tme_mm58167 {
67:
68: /* our simple bus device header: */
69: struct tme_bus_device tme_mm58167_device;
70: #define tme_mm58167_element tme_mm58167_device.tme_bus_device_element
71:
72: /* our socket: */
73: struct tme_mm58167_socket tme_mm58167_socket;
74: #define tme_mm58167_addr_shift tme_mm58167_socket.tme_mm58167_socket_addr_shift
75: #define tme_mm58167_port_least_lane tme_mm58167_socket.tme_mm58167_socket_port_least_lane
76:
77: /* the mutex protecting the chip: */
78: tme_mutex_t tme_mm58167_mutex;
79:
80: /* the last time sampled: */
81: time_t tme_mm58167_sampled_time;
82:
83: /* the struct tm for the last time sampled: */
84: struct tm tme_mm58167_sampled_tm;
85:
86: /* the status register: */
87: tme_uint8_t tme_mm58167_status;
88: };
89:
90: /* the mm58167 bus router: */
91: static const tme_bus_lane_t tme_mm58167_router[TME_BUS_ROUTER_SIZE(TME_BUS8_LOG2)] = {
92:
93: /* [gen] initiator port size: 8 bits
94: [gen] initiator port least lane: 0: */
95: /* D7-D0 */ TME_BUS_LANE_ROUTE(0),
96: };
97:
98: /* the mm58167 bus cycle handler: */
99: static int
100: _tme_mm58167_bus_cycle(void *_mm58167, struct tme_bus_cycle *cycle_init)
101: {
102: struct tme_mm58167 *mm58167;
103: tme_bus_addr_t address, mm58167_address_last;
104: tme_uint8_t buffer, value;
105: struct tme_bus_cycle cycle_resp;
106: unsigned int reg;
107: time_t now;
108: struct tm *now_tm;
109: int reg_is_bcd;
110:
111: /* recover our data structure: */
112: mm58167 = (struct tme_mm58167 *) _mm58167;
113:
114: /* the requested cycle must be within range: */
115: mm58167_address_last = mm58167->tme_mm58167_device.tme_bus_device_address_last;
116: assert(cycle_init->tme_bus_cycle_address <= mm58167_address_last);
117: assert(cycle_init->tme_bus_cycle_size <= (mm58167_address_last - cycle_init->tme_bus_cycle_address) + 1);
118:
119: /* get the register being accessed: */
120: address = cycle_init->tme_bus_cycle_address;
121: reg = address >> mm58167->tme_mm58167_addr_shift;
122: reg_is_bcd = (reg <= TME_MM58167_REG_MON);
123:
124: /* lock the mutex: */
125: tme_mutex_lock(&mm58167->tme_mm58167_mutex);
126:
127: /* sample the time. if it's changed, update our status: */
128: now = time(NULL);
129: if (now == mm58167->tme_mm58167_sampled_time) {
130: now_tm = &mm58167->tme_mm58167_sampled_tm;
131: }
132: else {
133: mm58167->tme_mm58167_status |= TME_MM58167_STATUS_RIPPLING;
134: mm58167->tme_mm58167_sampled_time = now;
135: now_tm = gmtime_r(&now, &mm58167->tme_mm58167_sampled_tm);
136: if (now_tm != &mm58167->tme_mm58167_sampled_tm) {
137: mm58167->tme_mm58167_sampled_tm = *now_tm;
138: }
139: }
140:
141: /* if this is a write: */
142: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
143:
144: /* run the bus cycle: */
145: cycle_resp.tme_bus_cycle_buffer = &buffer;
146: cycle_resp.tme_bus_cycle_lane_routing = tme_mm58167_router;
147: cycle_resp.tme_bus_cycle_address = 0;
148: cycle_resp.tme_bus_cycle_buffer_increment = 1;
149: cycle_resp.tme_bus_cycle_type = TME_BUS_CYCLE_READ;
150: cycle_resp.tme_bus_cycle_size = sizeof(buffer);
151: cycle_resp.tme_bus_cycle_port =
152: TME_BUS_CYCLE_PORT(mm58167->tme_mm58167_port_least_lane,
153: TME_BUS8_LOG2);
154: tme_bus_cycle_xfer(cycle_init, &cycle_resp);
155: value = buffer;
156:
157: /* log this write: */
158: tme_log(TME_MM58167_LOG_HANDLE(mm58167), 100000, TME_OK,
159: (TME_MM58167_LOG_HANDLE(mm58167),
160: "reg %d write %02x",
161: reg, value));
162:
163: /* otherwise, ignore writes for now: */
164: }
165:
166:
167: /* otherwise, this is a read: */
168: else {
169: assert(cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ);
170:
171: /* dispatch on the register: */
172: switch (reg) {
173: case TME_MM58167_REG_MSEC_XXX:
174: case TME_MM58167_REG_CSEC:
175: value = 0;
176: break;
177: case TME_MM58167_REG_SEC:
178: value = now_tm->tm_sec;
179: break;
180: case TME_MM58167_REG_MIN:
181: value = now_tm->tm_min;
182: break;
183: case TME_MM58167_REG_HOUR:
184: value = now_tm->tm_hour;
185: break;
186: case TME_MM58167_REG_WDAY:
187: value = now_tm->tm_wday;
188: break;
189: case TME_MM58167_REG_DAY:
190: value = now_tm->tm_mday;
191: break;
192: case TME_MM58167_REG_MON:
193: value = now_tm->tm_mon + 1;
194: break;
195: case TME_MM58167_REG_STATUS:
196: value = mm58167->tme_mm58167_status;
197: mm58167->tme_mm58167_status = 0;
198: break;
199: default:
200: abort();
201: }
202:
203: /* if needed, convert this value to BCD: */
204: if (reg_is_bcd) {
205: value = (value % 10) + ((value / 10) << 4);
206: }
207:
208: /* log this read: */
209: tme_log(TME_MM58167_LOG_HANDLE(mm58167), 100000, TME_OK,
210: (TME_MM58167_LOG_HANDLE(mm58167),
211: "reg %d read %02x",
212: reg, value));
213:
214: /* run the bus cycle: */
215: buffer = value;
216: cycle_resp.tme_bus_cycle_buffer = &buffer;
217: cycle_resp.tme_bus_cycle_lane_routing = tme_mm58167_router;
218: cycle_resp.tme_bus_cycle_address = 0;
219: cycle_resp.tme_bus_cycle_buffer_increment = 1;
220: cycle_resp.tme_bus_cycle_type = TME_BUS_CYCLE_WRITE;
221: cycle_resp.tme_bus_cycle_size = sizeof(buffer);
222: cycle_resp.tme_bus_cycle_port =
223: TME_BUS_CYCLE_PORT(mm58167->tme_mm58167_port_least_lane,
224: TME_BUS8_LOG2);
225: tme_bus_cycle_xfer(cycle_init, &cycle_resp);
226: }
227:
228: /* unlock the mutex: */
229: tme_mutex_unlock(&mm58167->tme_mm58167_mutex);
230:
231: /* no faults: */
232: return (TME_OK);
233: }
234:
235: /* the mm58167 TLB filler: */
236: static int
237: _tme_mm58167_tlb_fill(void *_mm58167, struct tme_bus_tlb *tlb,
238: tme_bus_addr_t address, unsigned int cycles)
239: {
240: struct tme_mm58167 *mm58167;
241: tme_bus_addr_t mm58167_address_last;
242:
243: /* recover our data structure: */
244: mm58167 = (struct tme_mm58167 *) _mm58167;
245:
246: /* the address must be within range: */
247: mm58167_address_last = mm58167->tme_mm58167_device.tme_bus_device_address_last;
248: assert(address <= mm58167_address_last);
249:
250: /* initialize the TLB entry: */
251: tme_bus_tlb_initialize(tlb);
252:
253: /* this TLB entry can cover the whole device: */
254: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, 0);
255: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, mm58167_address_last);
256:
257: /* allow reading and writing: */
258: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
259:
260: /* our bus cycle handler: */
261: tlb->tme_bus_tlb_cycle_private = mm58167;
262: tlb->tme_bus_tlb_cycle = _tme_mm58167_bus_cycle;
263:
264: return (TME_OK);
265: }
266:
267: /* the new mm58167 function: */
268: TME_ELEMENT_NEW_DECL(tme_ic_mm58167) {
269: const struct tme_mm58167_socket *socket;
270: struct tme_mm58167 *mm58167;
271: struct tme_mm58167_socket socket_real;
272: tme_bus_addr_t address_mask;
273:
274: /* dispatch on our socket version: */
275: socket = (const struct tme_mm58167_socket *) extra;
276: if (socket == NULL) {
277: tme_output_append_error(_output, _("need an ic socket"));
278: return (ENXIO);
279: }
280: switch (socket->tme_mm58167_socket_version) {
281: case TME_MM58167_SOCKET_0:
282: socket_real = *socket;
283: break;
284: default:
285: tme_output_append_error(_output, _("socket type"));
286: return (EOPNOTSUPP);
287: }
288:
289: /* we take no arguments: */
290: if (args[1] != NULL) {
291: tme_output_append_error(_output,
292: "%s %s, %s %s",
293: args[1],
294: _("unexpected"),
295: _("usage:"),
296: args[0]);
297: return (EINVAL);
298: }
299:
300: /* start the mm58167 structure: */
301: mm58167 = tme_new0(struct tme_mm58167, 1);
302: tme_mutex_init(&mm58167->tme_mm58167_mutex);
303: mm58167->tme_mm58167_socket = socket_real;
304:
305: /* figure our address mask, up to the nearest power of two: */
306: address_mask = TME_MM58167_REG_BANK_SZ * mm58167->tme_mm58167_addr_shift;
307: if (address_mask & (address_mask - 1)) {
308: for (; address_mask & (address_mask - 1); address_mask &= (address_mask - 1));
309: address_mask <<= 1;
310: }
311: address_mask -= 1;
312:
313: /* initialize our simple bus device descriptor: */
314: mm58167->tme_mm58167_device.tme_bus_device_element = element;
315: mm58167->tme_mm58167_device.tme_bus_device_tlb_fill = _tme_mm58167_tlb_fill;
316: mm58167->tme_mm58167_device.tme_bus_device_address_last = address_mask;
317:
318: /* fill the element: */
319: element->tme_element_private = mm58167;
320: element->tme_element_connections_new = tme_bus_device_connections_new;
321:
322: return (TME_OK);
323: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.