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