tsunami_io.cc revision 811
110268SGeoffrey.Blake@arm.com/*
211527Sdavid.guillen@arm.com * Copyright (c) 2003 The Regents of The University of Michigan
310268SGeoffrey.Blake@arm.com * All rights reserved.
410268SGeoffrey.Blake@arm.com *
510268SGeoffrey.Blake@arm.com * Redistribution and use in source and binary forms, with or without
610268SGeoffrey.Blake@arm.com * modification, are permitted provided that the following conditions are
710268SGeoffrey.Blake@arm.com * met: redistributions of source code must retain the above copyright
810268SGeoffrey.Blake@arm.com * notice, this list of conditions and the following disclaimer;
910268SGeoffrey.Blake@arm.com * redistributions in binary form must reproduce the above copyright
1010268SGeoffrey.Blake@arm.com * notice, this list of conditions and the following disclaimer in the
1110268SGeoffrey.Blake@arm.com * documentation and/or other materials provided with the distribution;
1210268SGeoffrey.Blake@arm.com * neither the name of the copyright holders nor the names of its
1310268SGeoffrey.Blake@arm.com * contributors may be used to endorse or promote products derived from
1410268SGeoffrey.Blake@arm.com * this software without specific prior written permission.
1510268SGeoffrey.Blake@arm.com *
1610268SGeoffrey.Blake@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1710268SGeoffrey.Blake@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1810268SGeoffrey.Blake@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1910268SGeoffrey.Blake@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2010268SGeoffrey.Blake@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2110268SGeoffrey.Blake@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2210268SGeoffrey.Blake@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2310268SGeoffrey.Blake@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2410268SGeoffrey.Blake@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2510268SGeoffrey.Blake@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2610268SGeoffrey.Blake@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2710268SGeoffrey.Blake@arm.com */
2810268SGeoffrey.Blake@arm.com
2910268SGeoffrey.Blake@arm.com/* @file
3010268SGeoffrey.Blake@arm.com * Tsunami I/O including PIC, PIT, RTC, DMA
3110268SGeoffrey.Blake@arm.com */
3210268SGeoffrey.Blake@arm.com
3310268SGeoffrey.Blake@arm.com#include <sys/time.h>
3410268SGeoffrey.Blake@arm.com
3510268SGeoffrey.Blake@arm.com#include <deque>
3610268SGeoffrey.Blake@arm.com#include <string>
3710268SGeoffrey.Blake@arm.com#include <vector>
3810268SGeoffrey.Blake@arm.com
3910268SGeoffrey.Blake@arm.com#include "base/trace.hh"
4010268SGeoffrey.Blake@arm.com#include "cpu/exec_context.hh"
4110268SGeoffrey.Blake@arm.com#include "dev/console.hh"
4210268SGeoffrey.Blake@arm.com#include "dev/tlaser_clock.hh"
4310268SGeoffrey.Blake@arm.com#include "dev/tsunami_io.hh"
4410268SGeoffrey.Blake@arm.com#include "dev/tsunamireg.h"
4510268SGeoffrey.Blake@arm.com#include "dev/tsunami.hh"
4610268SGeoffrey.Blake@arm.com#include "mem/functional_mem/memory_control.hh"
4710268SGeoffrey.Blake@arm.com#include "sim/builder.hh"
4811527Sdavid.guillen@arm.com#include "dev/tsunami_cchip.hh"
4911527Sdavid.guillen@arm.com
5011420Sdavid.guillen@arm.comusing namespace std;
5110268SGeoffrey.Blake@arm.com
5210268SGeoffrey.Blake@arm.com#define UNIX_YEAR_OFFSET 52
5311527Sdavid.guillen@arm.com
5411527Sdavid.guillen@arm.com// Timer Event for Periodic interrupt of RTC
5510268SGeoffrey.Blake@arm.comTsunamiIO::RTCEvent::RTCEvent(Tsunami* t)
5610268SGeoffrey.Blake@arm.com    : Event(&mainEventQueue), tsunami(t)
5710268SGeoffrey.Blake@arm.com{
5810268SGeoffrey.Blake@arm.com    DPRINTF(MC146818, "RTC Event Initilizing\n");
5910268SGeoffrey.Blake@arm.com    schedule(curTick + ticksPerSecond/RTC_RATE);
6010268SGeoffrey.Blake@arm.com}
6110268SGeoffrey.Blake@arm.com
6211420Sdavid.guillen@arm.comvoid
6311420Sdavid.guillen@arm.comTsunamiIO::RTCEvent::process()
6411527Sdavid.guillen@arm.com{
6511527Sdavid.guillen@arm.com    DPRINTF(MC146818, "RTC Timer Interrupt\n");
6611527Sdavid.guillen@arm.com    schedule(curTick + ticksPerSecond/RTC_RATE);
6711527Sdavid.guillen@arm.com    //Actually interrupt the processor here
6811527Sdavid.guillen@arm.com    if (!tsunami->cchip->RTCInterrupting) {
6911527Sdavid.guillen@arm.com        tsunami->cchip->misc |= 1 << 7;
7011527Sdavid.guillen@arm.com        tsunami->cchip->RTCInterrupting = true;
7111527Sdavid.guillen@arm.com        tsunami->intrctrl->post(0, TheISA::INTLEVEL_IRQ2, 0);
7211527Sdavid.guillen@arm.com    }
7311527Sdavid.guillen@arm.com}
7411527Sdavid.guillen@arm.com
7510268SGeoffrey.Blake@arm.comconst char *
7610268SGeoffrey.Blake@arm.comTsunamiIO::RTCEvent::description()
7710268SGeoffrey.Blake@arm.com{
78    return "tsunami RTC 1024Hz interrupt";
79}
80
81// Timer Event for PIT Timers
82TsunamiIO::ClockEvent::ClockEvent()
83    : Event(&mainEventQueue)
84{
85    DPRINTF(Tsunami, "Clock Event Initilizing\n");
86    mode = 0;
87}
88
89void
90TsunamiIO::ClockEvent::process()
91{
92    DPRINTF(Tsunami, "Timer Interrupt\n");
93    if (mode == 0)
94        status = 0x20; // set bit that linux is looking for
95    else
96        schedule(curTick + interval);
97}
98
99void
100TsunamiIO::ClockEvent::Program(int count)
101{
102    DPRINTF(Tsunami, "Timer set to curTick + %d\n", count);
103    // should be count * (cpufreq/pitfreq)
104    interval = count * ticksPerSecond/1193180UL;
105    schedule(curTick + interval);
106    status = 0;
107}
108
109const char *
110TsunamiIO::ClockEvent::description()
111{
112    return "tsunami 8254 Interval timer";
113}
114
115void
116TsunamiIO::ClockEvent::ChangeMode(uint8_t md)
117{
118    mode = md;
119}
120
121uint8_t
122TsunamiIO::ClockEvent::Status()
123{
124    return status;
125}
126
127TsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time,
128                     Addr a, MemoryController *mmu)
129    : FunctionalMemory(name), addr(a), tsunami(t), rtc(t)
130{
131    mmu->add_child(this, Range<Addr>(addr, addr + size));
132
133    // set the back pointer from tsunami to myself
134    tsunami->io = this;
135
136    timerData = 0;
137    set_time(init_time == 0 ? time(NULL) : init_time);
138    uip = 1;
139    picr = 0;
140    picInterrupting = false;
141}
142
143void
144TsunamiIO::set_time(time_t t)
145{
146    gmtime_r(&t, &tm);
147    DPRINTFN("Real-time clock set to %s", asctime(&tm));
148}
149
150Fault
151TsunamiIO::read(MemReqPtr &req, uint8_t *data)
152{
153    DPRINTF(Tsunami, "io read  va=%#x size=%d IOPorrt=%#x\n",
154            req->vaddr, req->size, req->vaddr & 0xfff);
155
156    Addr daddr = (req->paddr & size);
157//    ExecContext *xc = req->xc;
158//    int cpuid = xc->cpu_id;
159
160    switch(req->size) {
161      case sizeof(uint8_t):
162        switch(daddr) {
163          case TSDEV_TMR_CTL:
164            *(uint8_t*)data = timer2.Status();
165            return No_Fault;
166          case TSDEV_RTC_DATA:
167            switch(RTCAddress) {
168              case RTC_CONTROL_REGISTERA:
169                *(uint8_t*)data = uip << 7 | 0x26;
170                uip = !uip;
171                return No_Fault;
172              case RTC_CONTROL_REGISTERB:
173                // DM and 24/12 and UIE
174                *(uint8_t*)data = 0x46;
175                return No_Fault;
176              case RTC_CONTROL_REGISTERC:
177                // If we want to support RTC user access in linux
178                // This won't work, but for now it's fine
179                *(uint8_t*)data = 0x00;
180                return No_Fault;
181              case RTC_CONTROL_REGISTERD:
182                panic("RTC Control Register D not implemented");
183              case RTC_SECOND:
184                *(uint8_t *)data = tm.tm_sec;
185                return No_Fault;
186              case RTC_MINUTE:
187                *(uint8_t *)data = tm.tm_min;
188                return No_Fault;
189              case RTC_HOUR:
190                *(uint8_t *)data = tm.tm_hour;
191                return No_Fault;
192              case RTC_DAY_OF_WEEK:
193                *(uint8_t *)data = tm.tm_wday;
194                return No_Fault;
195              case RTC_DAY_OF_MONTH:
196                *(uint8_t *)data = tm.tm_mday;
197              case RTC_MONTH:
198                *(uint8_t *)data = tm.tm_mon + 1;
199                return No_Fault;
200              case RTC_YEAR:
201                *(uint8_t *)data = tm.tm_year - UNIX_YEAR_OFFSET;
202                return No_Fault;
203              default:
204                panic("Unknown RTC Address\n");
205            }
206
207          default:
208            panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
209        }
210      case sizeof(uint16_t):
211      case sizeof(uint32_t):
212      case sizeof(uint64_t):
213      default:
214        panic("I/O Read - invalid size - va %#x size %d\n",
215              req->vaddr, req->size);
216    }
217    panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
218
219    return No_Fault;
220}
221
222Fault
223TsunamiIO::write(MemReqPtr &req, const uint8_t *data)
224{
225    uint8_t dt = *(uint8_t*)data;
226    uint64_t dt64 = dt;
227
228    DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
229            req->vaddr, req->size, req->vaddr & 0xfff, dt64);
230
231    Addr daddr = (req->paddr & size);
232
233    switch(req->size) {
234      case sizeof(uint8_t):
235        switch(daddr) {
236          case TSDEV_PIC1_MASK:
237            mask1 = *(uint8_t*)data;
238            if ((picr & mask1) && !picInterrupting) {
239                picInterrupting = true;
240                tsunami->cchip->postDRIR(uint64_t(1) << 55);
241                DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
242            }
243            return No_Fault;
244          case TSDEV_PIC2_MASK:
245            mask2 = *(uint8_t*)data;
246            //PIC2 Not implemented to interrupt
247            return No_Fault;
248          case TSDEV_DMA1_RESET:
249            return No_Fault;
250          case TSDEV_DMA2_RESET:
251            return No_Fault;
252          case TSDEV_DMA1_MODE:
253            mode1 = *(uint8_t*)data;
254            return No_Fault;
255          case TSDEV_DMA2_MODE:
256            mode2 = *(uint8_t*)data;
257            return No_Fault;
258          case TSDEV_DMA1_MASK:
259          case TSDEV_DMA2_MASK:
260            return No_Fault;
261          case TSDEV_TMR_CTL:
262            return No_Fault;
263          case TSDEV_TMR2_CTL:
264            if ((*(uint8_t*)data & 0x30) != 0x30)
265                panic("Only L/M write supported\n");
266
267            switch(*(uint8_t*)data >> 6) {
268              case 0:
269                timer0.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
270                break;
271              case 2:
272                timer2.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
273                break;
274              default:
275                panic("Read Back Command not implemented\n");
276            }
277            return No_Fault;
278          case TSDEV_TMR2_DATA:
279            /* two writes before we actually start the Timer
280               so I set a flag in the timerData */
281            if(timerData & 0x1000) {
282                timerData &= 0x1000;
283                timerData += *(uint8_t*)data << 8;
284                timer2.Program(timerData);
285            } else {
286                timerData = *(uint8_t*)data;
287                timerData |= 0x1000;
288            }
289            return No_Fault;
290          case TSDEV_TMR0_DATA:
291            /* two writes before we actually start the Timer
292               so I set a flag in the timerData */
293            if(timerData & 0x1000) {
294                timerData &= 0x1000;
295                timerData += *(uint8_t*)data << 8;
296                timer0.Program(timerData);
297            } else {
298                timerData = *(uint8_t*)data;
299                timerData |= 0x1000;
300            }
301            return No_Fault;
302          case TSDEV_RTC_ADDR:
303            RTCAddress = *(uint8_t*)data;
304            return No_Fault;
305          case TSDEV_RTC_DATA:
306            panic("RTC Write not implmented (rtc.o won't work)\n");
307          default:
308            panic("I/O Write - va%#x size %d\n", req->vaddr, req->size);
309        }
310      case sizeof(uint16_t):
311      case sizeof(uint32_t):
312      case sizeof(uint64_t):
313      default:
314        panic("I/O Write - invalid size - va %#x size %d\n",
315              req->vaddr, req->size);
316    }
317
318
319    return No_Fault;
320}
321
322void
323TsunamiIO::postPIC(uint8_t bitvector)
324{
325    //PIC2 Is not implemented, because nothing of interest there
326    picr |= bitvector;
327    if ((picr & mask1) && !picInterrupting) {
328        picInterrupting = true;
329        tsunami->cchip->postDRIR(uint64_t(1) << 55);
330        DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
331    }
332}
333
334void
335TsunamiIO::clearPIC(uint8_t bitvector)
336{
337    //PIC2 Is not implemented, because nothing of interest there
338    picr &= ~bitvector;
339    if (!(picr & mask1)) {
340        picInterrupting = false;
341        tsunami->cchip->clearDRIR(uint64_t(1) << 55);
342        DPRINTF(Tsunami, "clearing pic interrupt to cchip\n");
343    }
344}
345
346void
347TsunamiIO::serialize(std::ostream &os)
348{
349    SERIALIZE_SCALAR(timerData);
350    SERIALIZE_SCALAR(uip);
351    SERIALIZE_SCALAR(picr);
352    SERIALIZE_SCALAR(picInterrupting);
353    Tick time0when = timer0.when();
354    Tick time2when = timer2.when();
355    Tick rtcwhen = rtc.when();
356    SERIALIZE_SCALAR(time0when);
357    SERIALIZE_SCALAR(time2when);
358    SERIALIZE_SCALAR(rtcwhen);
359
360}
361
362void
363TsunamiIO::unserialize(Checkpoint *cp, const std::string &section)
364{
365    UNSERIALIZE_SCALAR(timerData);
366    UNSERIALIZE_SCALAR(uip);
367    UNSERIALIZE_SCALAR(picr);
368    UNSERIALIZE_SCALAR(picInterrupting);
369    Tick time0when;
370    Tick time2when;
371    Tick rtcwhen;
372    UNSERIALIZE_SCALAR(time0when);
373    UNSERIALIZE_SCALAR(time2when);
374    UNSERIALIZE_SCALAR(rtcwhen);
375    timer0.reschedule(time0when);
376    timer2.reschedule(time2when);
377    rtc.reschedule(rtcwhen);
378}
379
380BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
381
382    SimObjectParam<Tsunami *> tsunami;
383    Param<time_t> time;
384    SimObjectParam<MemoryController *> mmu;
385    Param<Addr> addr;
386
387END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
388
389BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
390
391    INIT_PARAM(tsunami, "Tsunami"),
392    INIT_PARAM_DFLT(time, "System time to use "
393            "(0 for actual time, default is 1/1/06", ULL(1136073600)),
394    INIT_PARAM(mmu, "Memory Controller"),
395    INIT_PARAM(addr, "Device Address")
396
397END_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
398
399CREATE_SIM_OBJECT(TsunamiIO)
400{
401    return new TsunamiIO(getInstanceName(), tsunami, time,  addr, mmu);
402}
403
404REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO)
405