void BSP_irqexc_off_fnc(const rtems_irq_connect_data *unused) { uint32_t msr_value; /* * get current MSR value */ _CPU_MSR_GET(msr_value); msr_value &= ~PPC_MSR_EE; _CPU_MSR_SET(msr_value); }
/*********************************************************** * functions to enable/disable/query external/critical interrupts */ void BSP_irqexc_on_fnc(const rtems_irq_connect_data *conn_data) { uint32_t msr_value; /* * get current MSR value */ _CPU_MSR_GET(msr_value); msr_value |= PPC_MSR_EE; _CPU_MSR_SET(msr_value); }
/* * High level IRQ handler called from shared_raw_irq_code_entry */ int C_dispatch_irq_handler (CPU_Interrupt_frame *frame, unsigned int excNum) { register unsigned int irq; register unsigned msr; register unsigned new_msr; if (excNum == ASM_DEC_VECTOR) { _CPU_MSR_GET(msr); new_msr = msr | MSR_EE; _CPU_MSR_SET(new_msr); rtems_hdl_tbl[BSP_DECREMENTER].hdl(rtems_hdl_tbl[BSP_DECREMENTER].handle); _CPU_MSR_SET(msr); return 0; } irq = read_and_clear_irq(); _CPU_MSR_GET(msr); new_msr = msr | MSR_EE; _CPU_MSR_SET(new_msr); /* rtems_hdl_tbl[irq].hdl(rtems_hdl_tbl[irq].handle); */ { rtems_irq_connect_data* vchain; for( vchain = &rtems_hdl_tbl[irq]; ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl); vchain = (rtems_irq_connect_data*)vchain->next_handler ) { vchain->hdl(vchain->handle); } } _CPU_MSR_SET(msr); return 0; }
void _CPU_Context_Initialize( Context_Control *the_context, uint32_t *stack_base, uint32_t size, uint32_t new_level, void *entry_point, bool is_fp ) { uint32_t msr_value; uint32_t sp; sp = (uint32_t)stack_base + size - PPC_MINIMUM_STACK_FRAME_SIZE; sp &= ~(CPU_STACK_ALIGNMENT-1); *((uint32_t*)sp) = 0; _CPU_MSR_GET( msr_value ); /* * Setting the interrupt mask here is not strictly necessary * since the IRQ level will be established from _Thread_Handler() * again, as soon as the task starts execution. * Because we have to establish a defined state anyways we * can as well leave this code here. * I.e., simply (and unconditionally) saying * * msr_value &= ~ppc_interrupt_get_disable_mask(); * * would be an alternative. */ if (!(new_level & CPU_MODES_INTERRUPT_MASK)) { msr_value |= ppc_interrupt_get_disable_mask(); } else { msr_value &= ~ppc_interrupt_get_disable_mask(); } /* * The FP bit of the MSR should only be enabled if this is a floating * point task. Unfortunately, the vfprintf_r routine in newlib * ends up pushing a floating point register regardless of whether or * not a floating point number is being printed. Serious restructuring * of vfprintf.c will be required to avoid this behavior. At this * time (7 July 1997), this restructuring is not being done. */ /* Make sure integer tasks have no FPU access in order to * catch violations. Gcc may implicitely use the FPU and * data corruption may happen. * Since we set the_contex->msr using our current MSR, * we must make sure MSR_FP is off if (!is_fp)... * Unfortunately, this means that users of vfprintf_r have to use FP * tasks or fix vfprintf. Furthermore, users of int-only tasks * must prevent gcc from using the FPU (currently -msoft-float is the * only way...) */ if ( is_fp ) msr_value |= PPC_MSR_FP; else msr_value &= ~PPC_MSR_FP; memset( the_context, 0, sizeof( *the_context ) ); PPC_CONTEXT_SET_SP( the_context, sp ); PPC_CONTEXT_SET_PC( the_context, (uint32_t) entry_point ); PPC_CONTEXT_SET_MSR( the_context, msr_value ); #ifndef __SPE__ #if (PPC_ABI == PPC_ABI_SVR4) /* * SVR4 says R2 is for 'system-reserved' use; it cannot hurt to * propagate R2 to all task contexts. */ { uint32_t r2 = 0; unsigned r13 = 0; __asm__ volatile ("mr %0,2; mr %1,13" : "=r" ((r2)), "=r" ((r13))); the_context->gpr2 = r2; the_context->gpr13 = r13; } #elif (PPC_ABI == PPC_ABI_EABI) { uint32_t r2 = 0; unsigned r13 = 0; __asm__ volatile ("mr %0,2; mr %1,13" : "=r" ((r2)), "=r" ((r13))); the_context->gpr2 = r2; the_context->gpr13 = r13; } #else #error unsupported PPC_ABI #endif #endif /* __SPE__ */ #ifdef __ALTIVEC__ _CPU_Context_initialize_altivec(the_context); #endif }
/* * Initialize SS555 */ void _InitSS555 (void) { register uint32_t plprcr, msr; /* * Initialize the System Protection Control Register (SYPCR). * The SYPCR can only be written once after Reset. */ usiu.sypcr = USIU_SYPCR_SWTC(WATCHDOG_TIMEOUT) /* set watchdog timeout */ | USIU_SYPCR_BMT(0xFF) /* set bus monitor timeout */ | USIU_SYPCR_BME /* enable bus monitor */ | USIU_SYPCR_SWF /* watchdog halted in freeze */ #if WATCHDOG_TIMEOUT != 0xFFFF | USIU_SYPCR_SWE /* enable watchdog */ #endif | USIU_SYPCR_SWRI /* watchdog forces reset */ | USIU_SYPCR_SWP; /* prescale watchdog by 2048 */ TICKLE_WATCHDOG(); /* restart watchdog timer */ /* * Re-tune the PLL to the desired system clock frequency. */ usiu.plprck = USIU_UNLOCK_KEY; /* unlock PLPRCR */ usiu.plprcr = USIU_PLPRCR_TEXPS /* assert TEXP always */ | USIU_PLPRCR_MF(BSP_CLOCK_HZ / BSP_CRYSTAL_HZ); /* PLL multiplication factor */ usiu.plprck = 0; /* lock PLPRCR */ while (((plprcr = usiu.plprcr) & USIU_PLPRCR_SPLS) == 0) ; /* wait for PLL to re-lock */ /* * Enable the timebase and decrementer, then initialize decrementer * register to a large value to guarantee that a decrementer interrupt * will not be generated before the kernel is fully initialized. * Initialize the timebase register to zero. */ usiu.tbscrk = USIU_UNLOCK_KEY; usiu.tbscr |= USIU_TBSCR_TBE; /* enable time base and decrementer */ usiu.tbscrk = 0; usiu.tbk = USIU_UNLOCK_KEY; _write_PPC_DEC(0x7FFFFFFF); _write_TBWU(0x00000000 ); _write_TBWL(0x00000000 ); usiu.tbk = 0; /* * Run the Inter-Module Bus at full speed. */ imb.uimb.umcr &= ~UIMB_UMCR_HSPEED; /* * Initialize Memory Controller for External RAM * * Initialize the Base and Option Registers (BR0-BR7 and OR0-OR7). Note * that for all chip selects, ORx should be programmed before BRx. * * If booting from internal flash ROM, configure the external RAM to * extend the internal RAM. If booting from external RAM, leave it at * zero but set it up appropriately. */ usiu.memc[0]._or = USIU_MEMC_OR_512K /* bank size */ | USIU_MEMC_OR_SCY(0) /* wait states in first beat of burst */ | USIU_MEMC_OR_BSCY(0); /* wait states in subsequent beats */ usiu.memc[0]._br = USIU_MEMC_BR_BA(_read_IMMR() & IMMR_FLEN ? (uint32_t)int_ram_top : 0) /* base address */ | USIU_MEMC_BR_PS32 /* 32-bit data bus */ | USIU_MEMC_BR_TBDIP /* toggle bdip */ | USIU_MEMC_BR_V; /* base register valid */ /* * Initialize Memory Controller for External CPLD * * The SS555 board includes a CPLD to control on-board features and * off-board devices. (Configuration taken from Intec's hwhook.c) */ usiu.memc[3]._or = USIU_MEMC_OR_16M /* bank size */ | USIU_MEMC_OR_CSNT /* negate CS/WE early */ | USIU_MEMC_OR_ACS_HALF /* assert CS half cycle after address */ | USIU_MEMC_OR_SCY(15) /* wait states in first beat of burst */ | USIU_MEMC_OR_TRLX; /* relaxed timing */ usiu.memc[3]._br = USIU_MEMC_BR_BA(&cpld) /* base address */ | USIU_MEMC_BR_PS16 /* 16-bit data bus */ | USIU_MEMC_BR_BI /* inhibit bursting */ | USIU_MEMC_BR_V; /* base register valid */ /* * Disable show cycles and serialization so that burst accesses will work * properly. A different value, such as 0x0, may be more appropriate for * debugging, but can be set with the debugger, if needed. */ _write_ICTRL(0x00000007); /* * Set up Burst Buffer Controller (BBC) */ _write_BBCMCR( BBCMCR_ETRE /* enable exception relocation */ | BBCMCR_BE); /* enable burst accesses */ _isync; _CPU_MSR_GET(msr); msr |= MSR_IP; /* set prefix for exception relocation */ _CPU_MSR_SET(msr); }
/* * mmu_init * * This routine sets up the virtual memory maps on an MPC8xx. * The MPC8xx does not support block address translation (BATs) * and does not have segment registers. Thus, we must set up page * translation. However, its MMU supports variable size pages * (1-, 4-, 16-, 512-Kbyte or 8-Mbyte), which simplifies the task. * * The MPC8xx has separate data and instruction 32-entry translation * lookaside buffers (TLB). By mapping all of DRAM as one huge page, * we can preload the TLBs and not have to be concerned with taking * TLB miss exceptions. * * We set up the virtual memory map so that virtual address of a * location is equal to its real address. */ void mmu_init( void ) { register uint32_t reg1, i; /* * Initialize the TLBs * * Instruction address translation and data address translation * must be disabled during initialization (IR=0, DR=0 in MSR). * We can assume the MSR has already been set this way. */ /* * Initialize IMMU & DMMU Control Registers (MI_CTR & MD_CTR) * GPM [0] 0b0 = PowerPC mode * PPM [1] 0b0 = Page resolution of protection * CIDEF [2] 0b0/0b0 = Default cache-inhibit attribute = * NO for IMMU, NO for DMMU * NOTE: it is vital that data caching is ON, when * DMMU is off, otherwise valid/dirty values in * cache would be ignored during exception entry * reserved/WTDEF [3] 0b0 = Default write-through attribute = not * RSV4x [4] 0b0 = 4 entries not reserved * reserved/TWAM [5] 0b0/0b1 = 4-Kbyte page hardware assist * PPCS [6] 0b0 = Ignore user/supervisor state * reserved [7-18] 0x00 * xTLB_INDX [19-23] 31 = 0x1F * reserved [24-31] 0x00 * * Note: It is important that cache-inhibit be set as the default for the * data cache when the DMMU is disabled in order to prevent internal memory * mapped registers from being cached accidentally when address translation * is turned off at the start of exception processing. */ reg1 = M8xx_MI_CTR_ITLB_INDX(31); _mtspr( M8xx_MI_CTR, reg1 ); reg1 = M8xx_MD_CTR_TWAM | M8xx_MD_CTR_DTLB_INDX(31); _mtspr( M8xx_MD_CTR, reg1 ); _isync; /* * Invalidate all TLB entries in both TLBs. * Note: We rely on the RSV4 bit in MI_CTR and MD_CTR being 0b0, so * all 32 entries are invalidated. */ __asm__ volatile ("tlbia\n"::); _isync; /* * Set Current Address Space ID Register (M_CASID). * Supervisor: CASID = 0 */ reg1 = 0; _mtspr( M8xx_M_CASID, reg1 ); /* * Initialize the MMU Access Protection Registers (MI_AP, MD_AP) * We ignore the Access Protection Group (APG) mechanism globally * by setting all of the Mx_AP fields to 0b01 : client access * permission is defined by page protection bits. */ reg1 = 0x55555555; _mtspr( M8xx_MI_AP, reg1 ); _mtspr( M8xx_MD_AP, reg1 ); /* * Load both 32-entry TLBs with values from the MMU_TLB_table * which is defined in the BSP. * Note the _TLB_Table must have at most 32 entries. This code * makes no effort to enforce this restriction. */ for( i = 0; i < MMU_N_TLB_Table_Entries; ++i ) { reg1 = MMU_TLB_table[i].mmu_epn; _mtspr( M8xx_MI_EPN, reg1 ); _mtspr( M8xx_MD_EPN, reg1 ); reg1 = MMU_TLB_table[i].mmu_twc; _mtspr( M8xx_MI_TWC, reg1 ); _mtspr( M8xx_MD_TWC, reg1 ); reg1 = MMU_TLB_table[i].mmu_rpn; /* RPN must be written last! */ _mtspr( M8xx_MI_RPN, reg1 ); _mtspr( M8xx_MD_RPN, reg1 ); } /* * Turn on address translation by setting MSR[IR] and MSR[DR]. */ _CPU_MSR_GET( reg1 ); reg1 |= PPC_MSR_IR | PPC_MSR_DR; _CPU_MSR_SET( reg1 ); }