Example #1
0
void
init_qtime_ixp2400()
{
	struct qtime_entry	*qtime = alloc_qtime();

	/*
	 * Map the timer registers
	 */
	ixp2400_timer_base = startup_io_map(IXP2400_TIMER_SIZE, IXP2400_TIMER_BASE);


	/*
	 * Set the timer free running with maximum countdown
	 */

	out32(ixp2400_timer_base + IXP2400_TIMER1_LOAD, 0xffffffff);
	out32(ixp2400_timer_base + IXP2400_TIMER1_CONTROL,0x80);

	timer_start = timer_start_ixp2400;
	timer_diff = timer_diff_ixp2400;

	qtime->intr = 4;

	qtime->timer_rate  = IXP2400_CLOCK_RATE;
	qtime->timer_scale = IXP2400_CLOCK_SCALE;
	qtime->cycles_per_sec = (uint64_t)IXP2400_CLOCK_FREQ;

	add_callout_array(timer_callouts, sizeof(timer_callouts));
}
Example #2
0
void
init_qtime_ixp23xx()
{
	struct qtime_entry	*qtime = alloc_qtime();

	/*
	 * Map the timer registers
	 */
	ixp23xx_timer_base = startup_io_map(IXP23XX_OST_SIZE, IXP23XX_OST_BASE);

	/*
	 * Set the timer with maximum countdown, auto reload. The two least significant
	 * bits of the reload register are actually control bits, and are written as zero
	 * when loading the count value. Bit one selects one-shot (1) or Auto-reload (0), 
	 * and bit 0 starts the timer running.
	 */

	out32(ixp23xx_timer_base + IXP23XX_OST_TIM0_RL, 0xfffffffc);
	
	/* clear any pending interrupt on the timer */
	out32(ixp23xx_timer_base + IXP23XX_OST_STS, 0x01);

	timer_start = timer_start_ixp23xx;
	timer_diff = timer_diff_ixp23xx;

	qtime->intr = 3;

	qtime->timer_rate  = IXP23XX_CLOCK_RATE;
	qtime->timer_scale = IXP23XX_CLOCK_SCALE;
	qtime->cycles_per_sec = (uint64_t)IXP23XX_CLOCK_FREQ;

	add_callout_array(timer_callouts, sizeof(timer_callouts));
}
Example #3
0
void
init_qtime_pxa270()
{
	struct qtime_entry	*qtime = alloc_qtime();

	/*
	 * Map the timer registers
	 */
	pxa270_timer_base = startup_io_map(0x20, PXA250_TIMER_BASE);

	/*
	 * Clear match status and interrupt enable, and disable watchdog reset
	 */
	out32(pxa270_timer_base + PXA250_OIER, in32(pxa270_timer_base + PXA250_OIER) & ~0xf);;
	out32(pxa270_timer_base + PXA250_OSSR, in32(pxa270_timer_base + PXA250_OSSR) | 0x0f);
	out32(pxa270_timer_base + PXA250_OWER, 0);

	timer_start = timer_start_pxa270;
	timer_diff = timer_diff_pxa270;

	qtime->intr = 26;

	qtime->timer_rate  = PXA270_CLOCK_RATE;
	qtime->timer_scale = PXA270_CLOCK_SCALE;
	qtime->cycles_per_sec = (uint64_t)PXA270_CLOCK_FREQ;

	add_callout_array(timer_callouts, sizeof(timer_callouts));
}
Example #4
0
void
init_qtime_ixp425()
{
	struct qtime_entry	*qtime = alloc_qtime();

	/*
	 * Map the timer registers
	 */
	ixp425_timer_base = startup_io_map(IXP425_TIMER_SIZE, IXP425_TIMER_BASE);


	/*
	 * Set the timer free running with maximum countdown
	 */

	out32(ixp425_timer_base + IXP425_TIMER0_RELOAD, 0xfffffffc);
	out32(ixp425_timer_base + IXP425_TIMER_STATUS, 0x5);


	timer_start = timer_start_ixp425;
	timer_diff = timer_diff_ixp425;

	qtime->intr = 5; //timer0 interrupt

	qtime->timer_rate  = IXP425_CLOCK_RATE;
	qtime->timer_scale = IXP425_CLOCK_SCALE;
	qtime->cycles_per_sec = (uint64_t)IXP425_CLOCK_FREQ;

	add_callout_array(timer_callouts, sizeof(timer_callouts));
}
Example #5
0
void
init_qtime_omap3530()
{
	struct qtime_entry	*qtime = alloc_qtime();
	uint32_t			prcm_wkup_base = OMAP3530_PRCM_WKUP_CM;
	
	/*
	 * Enable GPT1 clock, select sys_clk as timer input clock
	 */
	out32(prcm_wkup_base + OMAP3530_CM_FCLKEN_WKUP,
		in32(prcm_wkup_base + OMAP3530_CM_FCLKEN_WKUP) | 1);
	out32(prcm_wkup_base + OMAP3530_CM_ICLKEN_WKUP,
		in32(prcm_wkup_base + OMAP3530_CM_ICLKEN_WKUP) | 1);
	out32(prcm_wkup_base + OMAP3530_CM_CLKSEL_WKUP,
		in32(prcm_wkup_base + OMAP3530_CM_CLKSEL_WKUP) | 1);

	while ((in32(prcm_wkup_base + OMAP3530_CM_IDLEST_WKUP) & 1));

	/*
	 * Map GPT1 registers
	 */
	timer_base = startup_io_map(OMAP3530_GPT_SIZE, OMAP3530_GPT1_BASE);

	/* Reset the timer */
	out32(timer_base + OMAP3530_GPT_TIOCP_CFG, 0x02);

	/* Wait for reset to complete */
	while (!(in32(timer_base + OMAP3530_GPT_TISTAT)) & 1)
		;

	/* Clear timer count and reload count */
	out32(timer_base + OMAP3530_GPT_TLDR, 0);
	out32(timer_base + OMAP3530_GPT_TCRR, 0);

	/*
	 * Setup GPT1
	 * Auto-reload enable
	 * Prescaler disable
	 * Stop timer, timer_load will enable it
	 */
	out32(timer_base + OMAP3530_GPT_TCLR, (1 << 1));

	timer_start = timer_start_omap3530;
	timer_diff  = timer_diff_omap3530;

	qtime->intr = 37;	/* GPT1 irq */

#define	OMAP_CLOCK_FREQ		13000000UL
#define	OMAP_CLOCK_RATE		76923077UL
#define	OMAP_CLOCK_SCALE	-15
	qtime->timer_rate = OMAP_CLOCK_RATE;
	qtime->timer_scale = OMAP_CLOCK_SCALE;
	qtime->cycles_per_sec = (uint64_t)OMAP_CLOCK_FREQ;

	add_callout_array(timer_callouts, sizeof(timer_callouts));
}
/*
 * init_qtime
 * 
 * Initialize the qtime entry. The timer to use has been added to the HWINFO
 * section as "qtimer"
*/
void init_qtime()
{
	struct qtime_entry	*qtime = alloc_qtime();		// alloc_qtime() call rtc_time()
	unsigned hwi_off = hwi_find_device("qtimer", 0);
    hwiattr_timer_t qtimer_attr;
    int r = hwiattr_get_timer(hwi_off, &qtimer_attr);
    long best_freq;
    unsigned hires_timer;
    unsigned i;

    /* both asserts tells us which operation failed */
    ASSERT(hwi_off != HWI_NULL_OFF);
    ASSERT(r == EOK);
    ASSERT(qtimer_attr.common.location.len > 0);
    ASSERT(qtimer_attr.common.location.base != NULL);
    ASSERT(qtimer_attr.num_clks > 0);

	qtime->intr = hwitag_find_ivec(hwi_off, NULL);
	ASSERT(qtime->intr != HWI_ILLEGAL_VECTOR);
	
	/* if multiple clock sources have been provided, choose the highest resolution */
	best_freq = 0;
	hires_timer = 0;	// we already know there is at least 1 clock source (see ASSERT above)
	for (i=0; i<qtimer_attr.num_clks; i++)
	{
		long freq = hwitag_find_clkfreq(hwi_off, &i);
		if ((i > 0) && (freq > best_freq)) {
			hires_timer = i;
			best_freq = freq;
		}
	}
	ASSERT(hires_timer <= 1);	// I know CLKSEL is only 1 bit (ie. only 2 clock sources)

	qtime->timer_scale = -15;
	i = hires_timer;
	qtime->cycles_per_sec = (uint64_t)hwitag_find_clkfreq(hwi_off, &i);	// don't pass hires_timer as its changed by the call
	ASSERT(qtime->cycles_per_sec > 0);
	qtime->timer_rate = QTIME_CLK_RATE(qtime->timer_scale, qtime->cycles_per_sec);
// kprintf("cps = %x %x, rate = %d\n", ((uint32_t *)&qtime->cycles_per_sec)[0], ((uint32_t *)&qtime->cycles_per_sec)[1], qtime->timer_rate);
	/* Map the registers (timer_base) and select the hires_timer clock source and periodic mode */
	timer_base = startup_io_map(qtimer_attr.common.location.len, qtimer_attr.common.location.base);
	ASSERT(timer_base != NULL);
	out32(timer_base + EP93xx_TIMER_LOAD, UINT32_MAX);	// preset the LOAD register
// kprintf("clksel(%d) = 0x%x\n", hires_timer, EP93xx_TIMER_CTRL_CLKSEL(hires_timer));
	out32(timer_base + EP93xx_TIMER_CTRL,
			EP93xx_TIMER_CTRL_CLKSEL(hires_timer) |		// hires_timer holds which clock to select
			EP93xx_TIMER_CTRL_CLKMODE_PERIODIC);

	timer_start = timer_start_ep93xx;
	timer_diff  = timer_diff_ep93xx;

	add_callout_array(timer_callouts, sizeof(timer_callouts));
	
	/* start the timer */
	timer_start();
}
Example #7
0
void
pcnet_reset(paddr_t base, int mem_mapped) {
	uintptr_t	io_base;

	io_base = startup_io_map(0x100, base);

	outle16(io_base + PCNET_RAP, PCNET_CSR0);
	outle16(io_base + PCNET_RDP, PCNET_CSR0_STOP);

	startup_io_unmap(io_base);
}
Example #8
0
void
init_qtime_ixp1200()
{
    struct qtime_entry	*qtime = alloc_qtime();
    unsigned			pll;
    static const char	pll_mult[] = {
        /*
         * Multiplier for IXP1200_CLOCK_FREQ for PLL_CFG values
         * FIXME: these are taken from the Programmer's Reference Manual,
         *        but I'm not sure they are actually 100% correct...
         */
        8,
        10,
        12,
        14,
        16,
        18,
        20,
        22,
        24,
        26,
        28,
        30,
        36,
        40,
        42,
        44,
        45,
        48,
        52,
        54,
        56,
        60,
        63
    };

    /*
     * Map the timer registers
     */
    ixp1200_timer_base = startup_io_map(IXP1200_TIMER_SIZE, IXP1200_TIMER_BASE);

    /*
     * Calulate CPU core PLL frequency
     */
    pll = in32(IXP1200_PLL_CFG_BASE) & IXP1200_PLL_CFG_CCF;
    if (pll > 22) {
        crash("PLL_CFG is %d. Max supported value is 22\n", pll);
    }
    pll = IXP1200_CLOCK_FREQ * pll_mult[pll];

    /*
     * Set the timer free running, divide by 16, with maximum countdown
     */
    pll = pll / 16;
    out32(ixp1200_timer_base + IXP1200_TIMER_1_LOAD, 0x00ffffff);
    out32(ixp1200_timer_base + IXP1200_TIMER_1_CONTROL, IXP1200_TIMER_CONTROL_EN | IXP1200_TIMER_CONTROL_STP_16 | IXP1200_TIMER_CONTROL_FREE);

    timer_start = timer_start_ixp1200;
    timer_diff = timer_diff_ixp1200;

    qtime->intr = 36;

    qtime->timer_rate  = IXP1200_CLOCK_RATE;
    qtime->timer_scale = IXP1200_CLOCK_SCALE;
    qtime->cycles_per_sec = (uint64_t)pll;
    invert_timer_freq(qtime, pll);

    add_callout_array(timer_callouts, sizeof(timer_callouts));
}
Example #9
0
/*******************************************************************************
 * ep9301_config_pic
 *
 * This routine will initialize the 2 Vectored Interrupt Controllers in the
 * Cirrus Logic EP93xx family of processors.
 *
 * In order to handle the number of interrupts within the EP93xx, 2 separate
 * interrupt controllers are cascaded together to form 1 larger controller.
 * There is not much documentation on how this cascading of interrupts works as
 * it is not a true cascade. There is some logic which allows the second
 * controller to be daisy chained through the first controller which is actually
 * connected to the processor. There is no documentation on how prioritization
 * works for non vectored interrupts or the prioritization of the second
 * controller relative to the first. The only remote suggestion that they are
 * handled as 32 priority interrupts starting with controller 1 followed by
 * controller 2 is on page 118 of the User Guide which says ...
 *
 * 		"Vector Control Registers. The 32 VICxVectCntl0 through VICxVectCnt15
 * 		 registers select the interrupt source for the vectored interrupt."
 *
 * My interpretation is that vector 0 through 15 on controller 1 followed by
 * vector 0 through 15 on controller 2 is the prioritization.
 *
 * This still leaves the problem that we don't know which controller to look
 * at first without looking at the status register for each ... which implies
 * that the prioritization is completely under software control. In other words,
 * software must decide to either read controller 1 or 2 status first, effectively
 * prioritizing one set of 32 interrupts over the other 32. Then, because some of
 * the interrupts are not vectored, we must choose bits in the status register.
 * However, if the vector address read when none of the interrupts programmed as
 * vectored interrupts is the default vector, then the sequence can flow as
 * follows (I will prioritize controller 1 interrupts over controller 2)
 *
 * 		if (vic1_status != 0)
 * 		{
 * 			if (vic1_vector != default vector)
 * 				id = vect_table[vic1_vector]
 * 			else
 * 				id = first bit set in vic1_status
 * 		}
 * 		else if (vic2_status != 0)
 * 		{
 * 			if (vic1_vector != default vector)
 * 				id = vect_table[vic2_vector]
 * 			else
 * 				id = first bit set in vic2_status
 * 		}
 * 		else
 * 			spurious interrupt
 *
 * 		return id
 *
 * This is all greatly complicated by the fact that only 1/2 of the interrupts
 * in each controller are vectored and prioritized not to mention the
 * prioritization between IRQ and FIQ interrupts.
 * To properly support prioritized interrupts and decouple them from the assigned
 * internal id's is going to require some more thought so for now I am not going
 * to use the hardware prioritization of the vectored interrupts and instead
 * simply do a first bit set prioritization of interrupts as follows
 *
 * 			VIC1, 31 -> 0
 * 			VIC2, 31 -> 0
 *
 * implying that in the case of multiple occurring interrupts, VIC1, interrupt
 * 31 (documented interrupt source 31) is the highest in the system and VIC2,
 * interrupt 0 (documented interrupt source 32) is the lowest.
 *
 * Additionally, FIQ is not going to be used for now.
 *
 * Returns: the number of interrupt vectors assigned
 *
 * Implementation Note:
 *
*/
uint32_t ep9301_config_pic(uint32_t os_vector_base, uint32_t pic_vector_base, vector_tbl_t *reg_vectors)
{
	uintptr_t base = startup_io_map((EP93xx_VIC_CTRL2_BASE - EP93xx_VIC_CTRL1_BASE) + EP93xx_VIC_CTRL2_SIZE, EP93xx_VIC_CTRL1_BASE);
	unsigned hwi_off;
	unsigned i;

	/*
	 * check the peripheral ID registers. We will assert on the truth of valid_pic_id() since a change
	 * may suggest a difference in the device behaviour which may need to be reflected in a
	 * code change
	*/
	ASSERT(valid_pic_id());
	ASSERT(pic_vector_base == os_vector_base);	// re-mapping not supported (yet)

	reg_vectors->start = pic_vector_base;
	reg_vectors->num = 0;

	/* set all the vector bases */
	intrs[0].vector_base = os_vector_base;
	ASSERT(intrs[0].num_vectors > 0);
	reg_vectors->num += intrs[0].num_vectors;
	for (i=1; i<NUM_ELTS(intrs); i++)
	{
		intrs[i].vector_base = intrs[i - 1].vector_base + intrs[i - 1].num_vectors;
		ASSERT(intrs[i].num_vectors > 0);
		reg_vectors->num += intrs[i].num_vectors;
	}
	/* add the interrupt info section */
	add_interrupt_array(intrs, sizeof(intrs));

	/* disable and clear all interrupts. Note that we do not check EP93xx_VIC_INT_RAW because
	 * some devices do actually have interrupts asserted and this is reflected in the RAW register(s) */
	out32(VIC1(EP93xx_VIC_INT_CLEAR), 0xFFFFFFFFU);
	out32(VIC1(EP93xx_VIC_SWINT_CLEAR), 0xFFFFFFFFU);
	ASSERT(in32(VIC1(EP93xx_VIC_INT_ENABLE)) == 0);
	ASSERT(in32(VIC1(EP93xx_VIC_SWINT_ENABLE)) == 0);
	ASSERT(in32(VIC1(EP93xx_VIC_IRQ_STATUS)) == 0);
	ASSERT(in32(VIC1(EP93xx_VIC_FIQ_STATUS)) == 0);

	out32(VIC2(EP93xx_VIC_INT_CLEAR), 0xFFFFFFFFU);
	out32(VIC2(EP93xx_VIC_SWINT_CLEAR), 0xFFFFFFFFU);
	ASSERT(in32(VIC2(EP93xx_VIC_INT_ENABLE)) == 0);
	ASSERT(in32(VIC2(EP93xx_VIC_SWINT_ENABLE)) == 0);
	ASSERT(in32(VIC2(EP93xx_VIC_IRQ_STATUS)) == 0);
	ASSERT(in32(VIC2(EP93xx_VIC_FIQ_STATUS)) == 0);

	/* set privileged access to interrupt controller registers */
	out32(VIC1(EP93xx_VIC_PROTECTION), 0x0);
	out32(VIC2(EP93xx_VIC_PROTECTION), 0x0);

	/* by default, all interrupts will generate an IRQ (FIQ not used) */
	out32(VIC1(EP93xx_VIC_INT_SELECT), 0);
	out32(VIC2(EP93xx_VIC_INT_SELECT), 0);

	/* place HWI_ILLEGAL_VECTOR into the default vector(s) */
	out32(VIC1(EP93xx_VIC_VEC_ADDR_DFLT), HWI_ILLEGAL_VECTOR);
	out32(VIC2(EP93xx_VIC_VEC_ADDR_DFLT), HWI_ILLEGAL_VECTOR);

	/* disable the use of vectored interrupts for now */
	in32(VIC1(EP93xx_VIC_VEC_ADDR_CURR));
	out32(VIC1(EP93xx_VIC_VEC_ADDR_CURR), 0);
	in32(VIC2(EP93xx_VIC_VEC_ADDR_CURR));
	out32(VIC2(EP93xx_VIC_VEC_ADDR_CURR), 0);
	for (i=0; i<16; i++)
	{
		out32(VIC1(EP93xx_VIC_VEC_ADDR(i)), HWI_ILLEGAL_VECTOR);
		out32(VIC1(EP93xx_VIC_VEC_CTRL(i)), 0);
		out32(VIC2(EP93xx_VIC_VEC_ADDR(i)), HWI_ILLEGAL_VECTOR);
		out32(VIC2(EP93xx_VIC_VEC_CTRL(i)), 0);
	}

	/* TIMER1 - interrupt 4 */
	hwitag_set_avail_ivec(hwi_find_device(EP93xx_HWI_TIMER, 0), -1, 4);

	/* TIMER2 - interrupt 5 */
	hwitag_set_avail_ivec(hwi_find_device(EP93xx_HWI_TIMER, 1), -1, 5);

	/* TIMER3 - interrupt 51 */
	hwitag_set_avail_ivec(hwi_find_device(EP93xx_HWI_TIMER, 2), -1, 51);

	/* WATCHDOG TIMER - interrupt 36 */
	hwitag_set_avail_ivec(hwi_find_device(EP93xx_HWI_WDOG, 0), -1, 36);

	/* DMA channels - Note that the order of vector assignment in the HWINFO section will be
	 * memory to memory 0 - 17
	 * memory to memory 1 - 18
	 * memory to peripheral 0 - 7
	 * memory to peripheral 1 - 8
	 * memory to peripheral 2 - 9
	 * memory to peripheral 3 - 10
	 * memory to peripheral 4 - 11
	 * memory to peripheral 5 - 12
	 * memory to peripheral 6 - 13
	 * memory to peripheral 7 - 14
	 * memory to peripheral 8 - 15
	 * memory to peripheral 9 - 16
	*/
	if ((hwi_off = hwi_find_device(EP93xx_HWI_DMA, 0)) != HWI_NULL_OFF)
	{
		hwitag_set_ivec(hwi_off, 0, 17);
		hwitag_set_ivec(hwi_off, 1, 18);
		hwitag_set_ivec(hwi_off, 2, 7);
		hwitag_set_ivec(hwi_off, 3, 8);
		hwitag_set_ivec(hwi_off, 4, 9);
		hwitag_set_ivec(hwi_off, 5, 10);
		hwitag_set_ivec(hwi_off, 6, 11);
		hwitag_set_ivec(hwi_off, 7, 12);
		hwitag_set_ivec(hwi_off, 8, 13);
		hwitag_set_ivec(hwi_off, 9, 14);
		hwitag_set_ivec(hwi_off, 10, 15);
		hwitag_set_ivec(hwi_off, 11, 16);
	}

	/* GPIO
	 * 19 of the EP9301 GPIO ports are interruptible and are handled via a
	 * cascaded interrupt entry. In order for devices specifically connected to
	 * those GPIO pins to have a driver InterruptAttach() we provide the assigned
	 * vector ranges with 3 irqrange tags corresponding to the PORTA, PORTB and
	 * PORTF interrupting port pins respectively. Within the range tag assignments,
	 * the 'irq' field corresponds to the LSb (pin 0 of the port) and 'irq' + 'num' - 1
	 * corresponds to the MSb (pin 7 of the port).
	*/
	if ((hwi_off = hwi_find_device(EP93xx_HWI_GPIO, 0)) != HWI_NULL_OFF)
	{
		const unsigned num_pAB_vectors = intrs[1].num_vectors / 2;
		const unsigned num_pF_vectors = intrs[2].num_vectors + intrs[3].num_vectors + intrs[4].num_vectors;
		hwitag_set_ivecrange(hwi_off, 0, intrs[1].vector_base, num_pAB_vectors);	// PORT A
		hwitag_set_ivecrange(hwi_off, 1, intrs[1].vector_base + num_pAB_vectors, num_pAB_vectors);	// PORT B
		hwitag_set_ivecrange(hwi_off, 2, intrs[2].vector_base, num_pF_vectors);	// PORT F
	}

	/* UART1 - Note that the order of vector assignment in the HWINFO section will be
	 * combined - 52
	 * Rx - 23
	 * Tx - 24
	*/
	if ((hwi_off = hwi_find_device(EP93xx_HWI_UART, 0)) != HWI_NULL_OFF)
	{
		hwitag_set_ivec(hwi_off, 0, 52);
		hwitag_set_ivec(hwi_off, 1, 23);
		hwitag_set_ivec(hwi_off, 2, 24);
	}

	/* UART2 - Note that the order of vector assignment in the HWINFO section will be
	 * combined - 54
	 * Rx - 25
	 * Tx - 26
	*/
	if ((hwi_off = hwi_find_device(EP93xx_HWI_UART, 1)) != HWI_NULL_OFF)
	{
		hwitag_set_ivec(hwi_off, 0, 54);
		hwitag_set_ivec(hwi_off, 1, 25);
		hwitag_set_ivec(hwi_off, 2, 26);
	}

	/* EXTERNAL IRQ - 2 interrupts 32, 33 and 40 for IQR0, IRQ1 and IRQ2 respectively */
	if ((hwi_off = hwi_find_device(EP93xx_HWI_EXT_IRQ, 0)) != HWI_NULL_OFF)
	{
		hwitag_set_ivec(hwi_off, 0, 32);
		hwitag_set_ivec(hwi_off, 1, 33);
		hwitag_set_ivec(hwi_off, 2, 40);
	}

	/* RTC - Note that the order of vector assignment in the HWINFO section will be
	 * rtc - 37
	 * 64 Hz clock - 35
	 * 1 Hz clock - 42 (edge sensitive)
	*/
	if ((hwi_off = hwi_find_device(EP93xx_HWI_RTC, 0)) != HWI_NULL_OFF)
	{
		hwitag_set_ivec(hwi_off, 0, 37);
		hwitag_set_ivec(hwi_off, 1, 35);
		hwitag_set_ivec(hwi_off, 2, 42);
	}

	/* IrDA Device - 38 */
	if ((hwi_off = hwi_find_device(EP93xx_HWI_IrDA, 0)) != HWI_NULL_OFF) {
		hwitag_set_avail_ivec(hwi_off, 0, 38);
	}

	/* Ethernet Device */
	if ((hwi_off = hwi_find_device(EP93xx_HWI_ENET, 0)) != HWI_NULL_OFF) {
		hwitag_set_avail_ivec(hwi_off, 0, 39);
	}

	/* SSP - Note that the order of vector assignment in the HWINFO section will be
	 * combined - 53
	 * Rx - 45
	 * Tx - 46
	*/
	if ((hwi_off = hwi_find_bus(EP93xx_HWI_SSP, 0)) != HWI_NULL_OFF)
	{
		hwitag_set_ivec(hwi_off, 0, 53);
		hwitag_set_ivec(hwi_off, 1, 45);
		hwitag_set_ivec(hwi_off, 2, 46);
	}

	/* USB host controller - 56 */
	if ((hwi_off = hwi_find_bus(EP93xx_HWI_USB, 0)) != HWI_NULL_OFF) {
		hwitag_set_avail_ivec(hwi_off, 0, 56);
	}

	/* I2S device - 60 */
	if ((hwi_off = hwi_find_device(EP93xx_HWI_I2S, 0)) != HWI_NULL_OFF) {
		hwitag_set_avail_ivec(hwi_off, 0, 60);
	}

	/* ACC (AC97) device - 6 */
	if ((hwi_off = hwi_find_device(EP93xx_HWI_AUDIO, 0)) != HWI_NULL_OFF) {
		hwitag_set_avail_ivec(hwi_off, 0, 6);
	}

	startup_io_unmap(base);

	return reg_vectors->num;
}