⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 callout_interrupt_omap.s

📁 Centrality Atlas II development software
💻 S
字号:
## Copyright 2007, 2008, QNX Software Systems. # # Licensed under the Apache License, Version 2.0 (the "License"). You # may not reproduce, modify or distribute this software except in # compliance with the License. You may obtain a copy of the License # at: http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTIES OF ANY KIND, either express or implied.## This file may contain contributions from others, either as # contributors under the License or as licensors under other terms.  # Please review this entire file for other proprietary rights or license # notices, as well as the QNX Development Suite License Guide at # http://licensing.qnx.com/license-guide/ for other information.#/* * TI OMAP 1510 / 5910 / 1610 / 5912 specific interrupt callouts. * * interrupt_id_* and interrupt_eoi_* are copied and intermixed with other * kernel code during initialisation. * * They do not follow normal calling conventions, and must fall through * to the end, rather than attempting to perform a return instruction. * * The OMAP_INTR_GENFLAG_* bits in the intrinfo_entry defines which of the * following values can be loaded on entry to these code fragments: * *	r5 - holds the syspageptr				(OMAP_INTR_GENFLAG_SYSPAGE  set) *	r6 - holds the intrinfo_entry pointer	(OMAP_INTR_GENFLAG_INTRINFO set) *	r7 - holds the interrupt mask count		(OMAP_INTR_GENFLAG_INTRMASK set) * * The interrupt_id_* routine returns the (controller-relative) level in r4 */#include "callout.ah"#include <arm/omap.h>/* * ----------------------------------------------------------------------- * Routine to patch callout code * * On entry: *	r0 - physical address of syspage *	r1 - virtual  address of syspage *	r2 - offset from start of syspage to start of the callout routine *	r3 - offset from start of syspage to read/write data used by callout * ----------------------------------------------------------------------- */interrupt_patch_pri:	stmdb	sp!,{r4,lr}	add		r4, r0, r2					// address of callout routine	/*	 * Map interrupt controller registers	 */	mov		r0, #OMAP_INTR_SIZE	// size of interrupt registers	ldr		r1, Lintr1_base	bl		callout_io_map	/*	 * Patch the callout routine	 */	CALLOUT_PATCH	r4, r0, r1, r2, ip	ldmia	sp!,{r4,pc}interrupt_patch_sec:	stmdb	sp!,{r4,lr}	add		r4, r0, r2					// address of callout routine	/*	 * Map interrupt controller registers	 */	mov		r0, #OMAP_INTR_SIZE	// size of interrupt registers	ldr		r1, Lintr2_base	bl		callout_io_map	CALLOUT_PATCH	r4, r0, r1, r2, ip	/*	 * Patch the callout routine	 */	ldmia	sp!,{r4,pc}/* * The primary and secondary OMAP interrupt controllers each have a control register  * which requires a bit (NEW_IRQ_AGR) to be written to, after each interrupt has been  * cleared and/or masked. Hitting this bit causes the interrupt controller to re-evaluate  * its inputs, and determine the next pending interrupt. That interrupt number is then  * placed into the INTR_SIR_IRQ_CODE register. If no further interrupts are pending, the  * controller will then (and only then) de-assert its output. * * A problem arises when this setup is combined with the QNX interrupt handling scheme; * When an interrupt comes in from a device which is not on the primary controller * (i.e. the secondary, or one of the GPIO interrupt controllers), the following  * situation occurs: * * -the core is interrupted * -the primary ID callout runs * -a cascade vector is identified * -because it's a cascade vector, the primary's EOI callout is run * -the NEW_IRQ_AGR bit is hit on the primary, and the cascade vector is unmasked; *  the secondary controller is still asserting at this point, so the primary *  sees another interrupt from the secondary, and puts it in the INTR_SIR_IRQ_CODE * -the secondary ID callout runs, and then identifies, clears, and masks the interrupt * -the secondary ID callout hits the secondary's NEW_IRQ_AGR bit * -the secondary controller de-asserts its output, but the primary has already *   got a pending interrupt from the secondary, and won't de-assert its output to *  the core until the primary's NEW_IRQ_AGR bit is set.  * -the primary ID callout runs again, and the cascade vector from the secondary is  *  identified again * -the secondary ID callout runs again, but this time, the pending IRQ (determined *  from the INTR_SIR_IRQ_CODE register) is already masked, so a glitch (-1) is returned * * This will have a performance impact, since three extra (and unnecessary) callouts are * run every time an interrupt comes in from any controller other than the primary. * * To work around this, it is necessary for every ID callout (besides the primary) to * hit the primary's NEW_IRQ_AGR bit once the interrupt into the secondary / tertiary * controller has been cleared and/or masked, and the output to the primary has been * de-asserted. This will cause the primary to re-evaluate its inputs _after_ the * cascade vectors have been de-asserted, and thus will not re-run the callouts  * unnecessarily. For GPIO controllers which cascade into the secondary, their ID * callouts will also need to hit NEW_IRQ_AGR on the secondary and primary. * None of this will cause interrupts to be missed, since actual interrupts will * remain asserted until they are explicitly cleared and/or masked. */interrupt_patch_sec_pri:	stmdb	sp!,{r4,lr}	add		r4, r0, r2					// address of callout routine	/*	 * Map interrupt controller registers	 */	mov		r0, #OMAP_INTR_SIZE	// size of interrupt registers	ldr		r1, Lintr2_base	bl		callout_io_map	CALLOUT_PATCH	r4, r0, r1, r2, ip	mov		r0, #OMAP_INTR_SIZE	// size of interrupt registers	ldr		r1, Lintr1_base	bl		callout_io_map	CALLOUT_PATCH	r4, r0, r1, r2, ip	/*	 * Patch the callout routine	 */	ldmia	sp!,{r4,pc}Lintr1_base:	.word	OMAP_INTR1_BASE Lintr2_base:	.word	OMAP_INTR2_BASE /* * ----------------------------------------------------------------------- * Identify interrupt source. * * Returns interrupt number in r4 * ----------------------------------------------------------------------- */CALLOUT_START(interrupt_id_omap_pri, 0, interrupt_patch_pri)	/*	 * Get the interrupt controller base address (patched)	 */	mov		ip,     #0x000000ff	orr		ip, ip, #0x0000ff00	orr		ip, ip, #0x00ff0000	orr		ip, ip, #0xff000000	/*	 * get the binary coded source interrupt - reading this register clears	 * the corresponding bit in the ITR register if it's an edge triggered int	 */	ldr		r4, [ip, #OMAP_INTR_SIR_IRQ_CODE]    mov     r2, #1    /*     * Mask the interrupt     */    ldr     r1, [ip, #OMAP_INTR_MIR]	/*	 * see if level is already masked; if so, return -1	 * 	 */    and     r3, r1, r2, lsl r4    teq     r3, #0    beq     0f    mov     r4, #-1  /* glitch */    b       1f0:    orr     r1, r1, r2, lsl r4    str     r1, [ip, #OMAP_INTR_MIR]    /*     * New IRQ Agreement      */	ldr     r1,[ip, #OMAP_INTR_CONTROL_REG]	orr     r1, r1, #0x01	str     r1,[ip, #OMAP_INTR_CONTROL_REG]1:CALLOUT_END(interrupt_id_omap_pri)/* * ----------------------------------------------------------------------- * Acknowledge specified interrupt * * On entry: *	r4 contains the interrupt number *	r7 contains the interrupt mask count * ----------------------------------------------------------------------- */CALLOUT_START(interrupt_eoi_omap_pri, 0, interrupt_patch_pri)	/*	 * Get the interrupt controller base address (patched)	 */	mov		ip,     #0x000000ff	orr		ip, ip, #0x0000ff00	orr		ip, ip, #0x00ff0000	orr		ip, ip, #0xff000000    /*     * Only unmask interrupt if mask count is zero     */    teq     r7, #0    bne     0f	mov		r2, #1	mov		r2, r2, lsl r4	    ldr     r1, [ip, #OMAP_INTR_MIR]    bic     r1, r1, r2    str     r1, [ip, #OMAP_INTR_MIR]0:CALLOUT_END(interrupt_eoi_omap_pri)/* * ----------------------------------------------------------------------- * Mask specified interrupt * * On entry: *	r0 - syspage_ptr *	r1 - interrupt number * * Returns: *	r0 - error status * ----------------------------------------------------------------------- */CALLOUT_START(interrupt_mask_omap_pri, 0, interrupt_patch_pri)	/*	 * Get the interrupt controller base address (patched)	 */	mov		ip,     #0x000000ff	orr		ip, ip, #0x0000ff00	orr		ip, ip, #0x00ff0000	orr		ip, ip, #0xff000000    mov     r2, #1    /*     * Mask the interrupt     */    ldr     r0, [ip, #OMAP_INTR_MIR]    orr     r0, r0, r2, lsl r1    str     r0, [ip, #OMAP_INTR_MIR]    mov     r0, #0    mov     pc, lrCALLOUT_END(interrupt_mask_omap_pri)/* * ----------------------------------------------------------------------- * Unmask specified interrupt * * On entry: *	r0 - syspage_ptr *	r1 - interrupt number * * Returns: *	r0 - error status * ----------------------------------------------------------------------- */CALLOUT_START(interrupt_unmask_omap_pri, 0, interrupt_patch_pri)	/*	 * Get the interrupt controller base address (patched)	 */	mov		ip,     #0x000000ff	orr		ip, ip, #0x0000ff00	orr		ip, ip, #0x00ff0000	orr		ip, ip, #0xff000000    mov     r2, #1    /*     * Unmask the interrupt     */    ldr     r0, [ip, #OMAP_INTR_MIR]    mov     r2, r2, lsl r1    bic     r0, r0, r2    str     r0, [ip, #OMAP_INTR_MIR]	mov		r0, #0	mov		pc, lrCALLOUT_END(interrupt_unmask_omap_pri)/* * ----------------------------------------------------------------------- * Identify interrupt source. * * Returns interrupt number in r4 * ----------------------------------------------------------------------- */CALLOUT_START(interrupt_id_omap_sec, 0, interrupt_patch_sec_pri)	/*	 * Get the interrupt controller base address (patched)	 */	mov		ip,     #0x000000ff	orr		ip, ip, #0x0000ff00	orr		ip, ip, #0x00ff0000	orr		ip, ip, #0xff000000	/* patch in primary interrupt controller base */	mov		r0,     #0x000000ff	orr		r0, r0, #0x0000ff00	orr		r0, r0, #0x00ff0000	orr		r0, r0, #0xff000000	/*	 * There are 128 total interrupts in the secondary interrupt controller,	 * comprised of 4 sections of 32 bits each. The SIR_IRQ register is not 	 * duplicated, and will hold the value of the current active interrupt,	 * from 0 to 127. Reading it will also clear the appropriate ITR bit for	 * edge triggered interrupts. The 4 sections are duplicated at offsets of 0x100.	 *	 * r5 will be the section value (0, 1, 2, or 3) multiplied by 0x100, and added to ip.	 * r3 will contain the interrupt value adjusted to be within the range 	 * of 0 - 32, for masking, etc. So, for example, if the interrupt 	 * value is 103, this corresponds to the seventh bit of the fourth 	 * section, so r5 will be 0x300, and r3 will be 7.	 * The section value (0,1,2, or 3) is: ((irq >> 5) & 0x03).	 * The offset (0 to 31) is: irq - (section * 32)	 */	ldr		r4, [ip, #OMAP_INTR_SIR_IRQ_CODE]	mov		r5, r4, lsr #5	and 	r5, r5, #3	/* r5 now contains 0, 1, 2, or 3 */	mov		r3, r5, lsl #5	subs	r3, r4, r3	/* r3 now contains irq - (section *32) */	mov		r5, r5, lsl #8	add		r5, ip, r5	mov		r2,#1    /*     * Mask the interrupt     */    ldr     r1, [r5, #OMAP_INTR_MIR]	/*	 * see if level is already masked; if so, return -1	 * 	 */    and     r2, r1, r2, lsl r3    teq     r2, #0    beq     0f    mov     r4, #-1  /* glitch */    b       1f0:	mov		r2, #1    orr     r1, r1, r2, lsl r3    str     r1, [r5, #OMAP_INTR_MIR]    /*     * New IRQ Agreement on secondary     */    ldr     r1,[ip, #OMAP_INTR_CONTROL_REG]    orr     r1, r1, #0x01    str     r1,[ip, #OMAP_INTR_CONTROL_REG]	/*	 * New IRQ Agreement on primary	 */    ldr     r1,[r0, #OMAP_INTR_CONTROL_REG]    orr     r1, r1, #0x01    str     r1,[r0, #OMAP_INTR_CONTROL_REG]1:CALLOUT_END(interrupt_id_omap_sec)/* * ----------------------------------------------------------------------- * Acknowledge specified interrupt * * On entry: *	r4 contains the interrupt number *	r7 contains the interrupt mask count * ----------------------------------------------------------------------- */CALLOUT_START(interrupt_eoi_omap_sec, 0, interrupt_patch_sec)	/*	 * Get the interrupt controller base address (patched)	 */	mov		ip,     #0x000000ff	orr		ip, ip, #0x0000ff00	orr		ip, ip, #0x00ff0000	orr		ip, ip, #0xff000000    /*     * Only unmask interrupt if mask count is zero     */    teq     r7, #0    bne     0f	/*	 * See id_omap_sec callout for an explanation of code	 */	mov		r5, r4, lsr #5	and 	r5, r5, #3	mov		r3, r5, lsl #5	sub		r3, r4, r3	mov		r5, r5, lsl #8	add		ip, r5, ip	mov		r2, #1	mov		r2, r2, lsl r3	    ldr     r1, [ip, #OMAP_INTR_MIR]    bic     r1, r1, r2    str     r1, [ip, #OMAP_INTR_MIR]0:CALLOUT_END(interrupt_eoi_omap_sec)/* * ----------------------------------------------------------------------- * Mask specified interrupt * * On entry: *	r0 - syspage_ptr *	r1 - interrupt number * * Returns: *	r0 - error status * ----------------------------------------------------------------------- */CALLOUT_START(interrupt_mask_omap_sec, 0, interrupt_patch_sec)	/*	 * Get the interrupt controller base address (patched)	 */	mov		ip,     #0x000000ff	orr		ip, ip, #0x0000ff00	orr		ip, ip, #0x00ff0000	orr		ip, ip, #0xff000000	/*	 * See id_omap_sec callout for an explanation of code	 */	mov		r0, r1, lsr #5	and 	r0, r0, #3	mov		r3, r0, lsl #5	sub		r3, r1, r3	mov		r0, r0, lsl #8	add		ip, r0, ip    mov     r2, #1    /*     * Mask the interrupt     */    ldr     r0, [ip, #OMAP_INTR_MIR]    orr     r0, r0, r2, lsl r3    str     r0, [ip, #OMAP_INTR_MIR]    mov     r0, #0    mov     pc, lrCALLOUT_END(interrupt_mask_omap_sec)/* * ----------------------------------------------------------------------- * Unmask specified interrupt * * On entry: *	r0 - syspage_ptr *	r1 - interrupt number * * Returns: *	r0 - error status * ----------------------------------------------------------------------- */CALLOUT_START(interrupt_unmask_omap_sec, 0, interrupt_patch_sec)	/*	 * Get the interrupt controller base address (patched)	 */	mov		ip,     #0x000000ff	orr		ip, ip, #0x0000ff00	orr		ip, ip, #0x00ff0000	orr		ip, ip, #0xff000000	/*	 * See id_omap_sec callout for an explanation of code	 */	mov		r0, r1, lsr #5	and 	r0, r0, #3	mov		r3, r0, lsl #5	sub		r3, r1, r3	mov		r0, r0, lsl #8	add		ip, r0, ip    mov     r2, #1    /*     * Unmask the interrupt     */    ldr     r0, [ip, #OMAP_INTR_MIR]    mov     r2, r2, lsl r3    bic     r0, r0, r2    str     r0, [ip, #OMAP_INTR_MIR]	mov		r0, #0	mov		pc, lrCALLOUT_END(interrupt_unmask_omap_sec)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -