1 #include <vm/vm.h> 2 3 #include "soc_omap3.h" 4 5 enum { 6 INTCPS_REVISION = 0, 7 INTCPS_SYSCONFIG = 4, 8 INTCPS_SYSSTATUS, 9 INTCPS_SIR_IRQ = 16, 10 INTCPS_SIR_FIQ = 17, 11 INTCPS_CONTROL = 18, 12 INTCPS_PROTECTION = 19, 13 INTCPS_IDLE = 20, 14 INTCPS_IRQ_PRIORITY = 24, 15 INTCPS_FIQ_PRIORITY = 25, 16 INTCPS_THRESHOLD = 26, 17 INTCPS_ITRn = 32, 18 INTCPS_MIRn = 33, 19 INTCPS_MIR_CLEARn = 34, 20 INTCPS_MIR_SETn = 35, 21 INTCPS_ISR_SETn = 36, 22 INTCPS_ISR_CLEARn = 37, 23 INTCPS_PENDING_IRQn = 38, 24 INTCPS_PENDING_FIQn = 39, 25 INTCPS_ILRm = 40, 26 }; 27 28 29 void 30 OMAP3InterruptController::EnableInterrupt(int32 irq) 31 { 32 uint32 bit = irq % 32, bank = irq / 32; 33 fRegBase[INTCPS_MIR_CLEARn + (8 * bank)] = 1 << bit; 34 } 35 36 37 void 38 OMAP3InterruptController::DisableInterrupt(int32 irq) 39 { 40 uint32 bit = irq % 32, bank = irq / 32; 41 fRegBase[INTCPS_MIR_SETn + (8 * bank)] = 1 << bit; 42 } 43 44 45 void 46 OMAP3InterruptController::HandleInterrupt() 47 { 48 bool handledIRQ = false; 49 int irqnr = 0; 50 51 do { 52 for (uint32 i=0; i < fNumPending; i++) { 53 irqnr = fRegBase[INTCPS_PENDING_IRQn + (8 * i)]; 54 if (irqnr) 55 break; 56 } 57 58 if (!irqnr) 59 break; 60 61 irqnr = fRegBase[INTCPS_SIR_IRQ]; 62 irqnr &= 0x7f; /* ACTIVEIRQ */ 63 64 if (irqnr) { 65 int_io_interrupt_handler(irqnr, true); 66 handledIRQ = true; 67 } 68 } while(irqnr); 69 70 // If IRQ got cleared before we could handle it, simply 71 // ack it. 72 if (!handledIRQ) 73 fRegBase[INTCPS_CONTROL] = 1; 74 } 75 76 77 void 78 OMAP3InterruptController::SoftReset() 79 { 80 uint32 tmp = fRegBase[INTCPS_REVISION] & 0xff; 81 82 dprintf("OMAP: INTC found at 0x%p (rev %" B_PRIu32 ".%" B_PRIu32 ")\n", 83 fRegBase, tmp >> 4, tmp & 0xf); 84 85 tmp = fRegBase[INTCPS_SYSCONFIG]; 86 tmp |= 1 << 1; /* soft reset */ 87 fRegBase[INTCPS_SYSCONFIG] = tmp; 88 89 while (!(fRegBase[INTCPS_SYSSTATUS] & 0x1)) 90 /* Wait for reset to complete */; 91 92 /* Enable autoidle */ 93 fRegBase[INTCPS_SYSCONFIG] = 1; 94 } 95 96 97 OMAP3InterruptController::OMAP3InterruptController(uint32_t reg_base) 98 : fNumPending(3) 99 { 100 fRegArea = vm_map_physical_memory(B_SYSTEM_TEAM, "intc-omap3", (void**)&fRegBase, 101 B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 102 reg_base, false); 103 if (fRegArea < 0) 104 panic("OMAP3InterruptController: cannot map registers!"); 105 106 SoftReset(); 107 108 // Enable protection (MPU registers only available in privileged mode) 109 fRegBase[INTCPS_PROTECTION] |= 1; 110 } 111 112 113 enum { 114 TIDR = 0, 115 TIOCP_CFG = 4, 116 TISTAT, 117 TISR, 118 TIER, 119 TWER, 120 TCLR, 121 TCRR, 122 TLDR, 123 TTGR, 124 TWPS, 125 TMAR, 126 TCAR1, 127 TSICR, 128 TCAR2, 129 TPIR, 130 TNIR, 131 TCVR, 132 TOCR, 133 TOWR, 134 }; 135 136 int32 137 OMAP3Timer::_InterruptWrapper(void *data) 138 { 139 return ((OMAP3Timer*)data)->HandleInterrupt(); 140 } 141 142 143 int32 144 OMAP3Timer::HandleInterrupt() 145 { 146 uint32 ints = fRegBase[TISR] & 7; 147 148 if (ints & 1) { // Match? 149 dprintf("OMAP3Timer: match!\n"); 150 timer_interrupt(); 151 } else if (ints & 2) { // Overflow? 152 dprintf("OMAP3Timer: overflow!\n"); 153 fSystemTime += UINT_MAX +1; 154 } else if (ints & 4) { // Capture? 155 dprintf("OMAP3Timer: capture!\n"); 156 } 157 158 // clear interrupt 159 fRegBase[TISR] = ints; 160 161 return B_HANDLED_INTERRUPT; 162 } 163 164 165 void 166 OMAP3Timer::SetTimeout(bigtime_t timeout) 167 { 168 fRegBase[TMAR] = fRegBase[TCRR] + timeout / 1000ULL; 169 fRegBase[TIER] |= 1; // Enable match interrupt 170 } 171 172 173 bigtime_t 174 OMAP3Timer::Time() 175 { 176 return fSystemTime + fRegBase[TCRR]; 177 } 178 179 180 void 181 OMAP3Timer::Clear() 182 { 183 fRegBase[TIER] &= ~1; // Disable match interrupt 184 } 185 186 187 OMAP3Timer::OMAP3Timer(uint32_t reg_base, uint32_t interrupt) 188 : fSystemTime(0) 189 { 190 fRegArea = vm_map_physical_memory(B_SYSTEM_TEAM, "timer-omap3", (void**)&fRegBase, 191 B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 192 reg_base, false); 193 if (fRegArea < 0) 194 panic("Cannot map OMAP3Timer registers!"); 195 196 fInterrupt = interrupt; 197 if (fInterrupt < 0) 198 panic("Cannot get OMAP3Timer interrupt!"); 199 200 uint32 rev = fRegBase[TIDR]; 201 dprintf("OMAP: Found timer @ 0x%p, IRQ %d (rev %" B_PRIu32 ".%" B_PRIu32 ")\n", 202 fRegBase, fInterrupt, (rev >> 4) & 0xf, rev & 0xf); 203 204 // Let the timer run (so we can use it as clocksource) 205 fRegBase[TCLR] |= 1; 206 fRegBase[TIER] = 2; // Enable overflow interrupt 207 208 install_io_interrupt_handler(fInterrupt, &OMAP3Timer::_InterruptWrapper, this, 0); 209 } 210