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 §ion) 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