]>
Commit | Line | Data |
---|---|---|
d865fd09 RR |
1 | /* |
2 | * (C) Copyright 2000-2002 | |
3 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | * | |
5 | * (C) Copyright 2002 (440 port) | |
6 | * Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com | |
7 | * | |
8 | * (C) Copyright 2003 (440GX port) | |
9 | * Travis B. Sawyer, Sandburst Corporation, tsawyer@sandburst.com | |
10 | * | |
11 | * (C) Copyright 2008 (PPC440X05 port for Virtex 5 FX) | |
5b218ae1 | 12 | * Ricardo Ribalda-Universidad Autonoma de Madrid-ricardo.ribalda@gmail.com |
d865fd09 RR |
13 | * Work supported by Qtechnology (htpp://qtec.com) |
14 | * | |
1a459660 | 15 | * SPDX-License-Identifier: GPL-2.0+ |
d865fd09 RR |
16 | */ |
17 | ||
18 | #include <common.h> | |
19 | #include <watchdog.h> | |
20 | #include <command.h> | |
21 | #include <asm/processor.h> | |
22 | #include <asm/interrupt.h> | |
b36df561 | 23 | #include <asm/ppc4xx.h> |
d865fd09 | 24 | #include <ppc_asm.tmpl> |
d865fd09 RR |
25 | |
26 | #if (UIC_MAX > 3) | |
27 | #define UICB0_ALL (UIC_MASK(VECNUM_UIC1CI) | UIC_MASK(VECNUM_UIC1NCI) | \ | |
28 | UIC_MASK(VECNUM_UIC2CI) | UIC_MASK(VECNUM_UIC2NCI) | \ | |
29 | UIC_MASK(VECNUM_UIC3CI) | UIC_MASK(VECNUM_UIC3NCI)) | |
30 | #elif (UIC_MAX > 2) | |
31 | #define UICB0_ALL (UIC_MASK(VECNUM_UIC1CI) | UIC_MASK(VECNUM_UIC1NCI) | \ | |
32 | UIC_MASK(VECNUM_UIC2CI) | UIC_MASK(VECNUM_UIC2NCI)) | |
33 | #elif (UIC_MAX > 1) | |
34 | #define UICB0_ALL (UIC_MASK(VECNUM_UIC1CI) | UIC_MASK(VECNUM_UIC1NCI)) | |
35 | #else | |
36 | #define UICB0_ALL 0 | |
37 | #endif | |
38 | ||
39 | u32 get_dcr(u16); | |
40 | ||
41 | DECLARE_GLOBAL_DATA_PTR; | |
42 | ||
43 | void pic_enable(void) | |
44 | { | |
d865fd09 RR |
45 | #if (UIC_MAX > 1) |
46 | /* Install the UIC1 handlers */ | |
60204d06 SR |
47 | irq_install_handler(VECNUM_UIC1NCI, (void *)(void *)external_interrupt, 0); |
48 | irq_install_handler(VECNUM_UIC1CI, (void *)(void *)external_interrupt, 0); | |
d865fd09 RR |
49 | #endif |
50 | #if (UIC_MAX > 2) | |
60204d06 SR |
51 | irq_install_handler(VECNUM_UIC2NCI, (void *)(void *)external_interrupt, 0); |
52 | irq_install_handler(VECNUM_UIC2CI, (void *)(void *)external_interrupt, 0); | |
d865fd09 RR |
53 | #endif |
54 | #if (UIC_MAX > 3) | |
60204d06 SR |
55 | irq_install_handler(VECNUM_UIC3NCI, (void *)(void *)external_interrupt, 0); |
56 | irq_install_handler(VECNUM_UIC3CI, (void *)(void *)external_interrupt, 0); | |
d865fd09 | 57 | #endif |
d865fd09 RR |
58 | } |
59 | ||
60 | /* Handler for UIC interrupt */ | |
61 | static void uic_interrupt(u32 uic_base, int vec_base) | |
62 | { | |
63 | u32 uic_msr; | |
64 | u32 msr_shift; | |
65 | int vec; | |
66 | ||
67 | /* | |
68 | * Read masked interrupt status register to determine interrupt source | |
69 | */ | |
70 | uic_msr = get_dcr(uic_base + UIC_MSR); | |
71 | msr_shift = uic_msr; | |
72 | vec = vec_base; | |
73 | ||
74 | while (msr_shift != 0) { | |
75 | if (msr_shift & 0x80000000) | |
76 | interrupt_run_handler(vec); | |
77 | /* | |
78 | * Shift msr to next position and increment vector | |
79 | */ | |
80 | msr_shift <<= 1; | |
81 | vec++; | |
82 | } | |
83 | } | |
84 | ||
85 | /* | |
86 | * Handle external interrupts | |
87 | */ | |
88 | void external_interrupt(struct pt_regs *regs) | |
89 | { | |
90 | u32 uic_msr; | |
91 | ||
92 | /* | |
93 | * Read masked interrupt status register to determine interrupt source | |
94 | */ | |
952e7760 | 95 | uic_msr = mfdcr(UIC0MSR); |
d865fd09 RR |
96 | |
97 | #if (UIC_MAX > 1) | |
98 | if ((UIC_MASK(VECNUM_UIC1CI) & uic_msr) || | |
99 | (UIC_MASK(VECNUM_UIC1NCI) & uic_msr)) | |
100 | uic_interrupt(UIC1_DCR_BASE, 32); | |
101 | #endif | |
102 | ||
103 | #if (UIC_MAX > 2) | |
104 | if ((UIC_MASK(VECNUM_UIC2CI) & uic_msr) || | |
105 | (UIC_MASK(VECNUM_UIC2NCI) & uic_msr)) | |
106 | uic_interrupt(UIC2_DCR_BASE, 64); | |
107 | #endif | |
108 | ||
109 | #if (UIC_MAX > 3) | |
110 | if ((UIC_MASK(VECNUM_UIC3CI) & uic_msr) || | |
111 | (UIC_MASK(VECNUM_UIC3NCI) & uic_msr)) | |
112 | uic_interrupt(UIC3_DCR_BASE, 96); | |
113 | #endif | |
114 | ||
952e7760 | 115 | mtdcr(UIC0SR, (uic_msr & UICB0_ALL)); |
5bc542a5 | 116 | |
d865fd09 RR |
117 | if (uic_msr & ~(UICB0_ALL)) |
118 | uic_interrupt(UIC0_DCR_BASE, 0); | |
119 | ||
d865fd09 RR |
120 | return; |
121 | } | |
122 | ||
123 | void pic_irq_ack(unsigned int vec) | |
124 | { | |
d865fd09 | 125 | if ((vec >= 0) && (vec < 32)) |
952e7760 | 126 | mtdcr(UIC0SR, UIC_MASK(vec)); |
d865fd09 | 127 | else if ((vec >= 32) && (vec < 64)) |
952e7760 | 128 | mtdcr(UIC1SR, UIC_MASK(vec)); |
d865fd09 | 129 | else if ((vec >= 64) && (vec < 96)) |
952e7760 | 130 | mtdcr(UIC2SR, UIC_MASK(vec)); |
d865fd09 | 131 | else if (vec >= 96) |
952e7760 | 132 | mtdcr(UIC3SR, UIC_MASK(vec)); |
d865fd09 RR |
133 | } |
134 | ||
135 | /* | |
136 | * Install and free a interrupt handler. | |
137 | */ | |
138 | void pic_irq_enable(unsigned int vec) | |
139 | { | |
140 | ||
141 | if ((vec >= 0) && (vec < 32)) | |
952e7760 | 142 | mtdcr(UIC0ER, mfdcr(UIC0ER) | UIC_MASK(vec)); |
d865fd09 | 143 | else if ((vec >= 32) && (vec < 64)) |
952e7760 | 144 | mtdcr(UIC1ER, mfdcr(UIC1ER) | UIC_MASK(vec)); |
d865fd09 | 145 | else if ((vec >= 64) && (vec < 96)) |
952e7760 | 146 | mtdcr(UIC2ER, mfdcr(UIC2ER) | UIC_MASK(vec)); |
d865fd09 | 147 | else if (vec >= 96) |
952e7760 | 148 | mtdcr(UIC3ER, mfdcr(UIC3ER) | UIC_MASK(vec)); |
d865fd09 | 149 | |
04ddae91 | 150 | debug("Install interrupt vector %d\n", vec); |
d865fd09 RR |
151 | } |
152 | ||
153 | void pic_irq_disable(unsigned int vec) | |
154 | { | |
d865fd09 | 155 | if ((vec >= 0) && (vec < 32)) |
952e7760 | 156 | mtdcr(UIC0ER, mfdcr(UIC0ER) & ~UIC_MASK(vec)); |
d865fd09 | 157 | else if ((vec >= 32) && (vec < 64)) |
952e7760 | 158 | mtdcr(UIC1ER, mfdcr(UIC1ER) & ~UIC_MASK(vec)); |
d865fd09 | 159 | else if ((vec >= 64) && (vec < 96)) |
952e7760 | 160 | mtdcr(UIC2ER, mfdcr(UIC2ER) & ~UIC_MASK(vec)); |
d865fd09 | 161 | else if (vec >= 96) |
952e7760 | 162 | mtdcr(UIC3ER, mfdcr(UIC3ER) & ~UIC_MASK(vec)); |
d865fd09 | 163 | } |