0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/init.h>
0012 #include <linux/irq.h>
0013 #include <linux/spinlock.h>
0014 #include "internals.h"
0015
0016 static unsigned long ack_handle[INTC_NR_IRQS];
0017
0018 static intc_enum __init intc_grp_id(struct intc_desc *desc,
0019 intc_enum enum_id)
0020 {
0021 struct intc_group *g = desc->hw.groups;
0022 unsigned int i, j;
0023
0024 for (i = 0; g && enum_id && i < desc->hw.nr_groups; i++) {
0025 g = desc->hw.groups + i;
0026
0027 for (j = 0; g->enum_ids[j]; j++) {
0028 if (g->enum_ids[j] != enum_id)
0029 continue;
0030
0031 return g->enum_id;
0032 }
0033 }
0034
0035 return 0;
0036 }
0037
0038 static unsigned int __init _intc_mask_data(struct intc_desc *desc,
0039 struct intc_desc_int *d,
0040 intc_enum enum_id,
0041 unsigned int *reg_idx,
0042 unsigned int *fld_idx)
0043 {
0044 struct intc_mask_reg *mr = desc->hw.mask_regs;
0045 unsigned int fn, mode;
0046 unsigned long reg_e, reg_d;
0047
0048 while (mr && enum_id && *reg_idx < desc->hw.nr_mask_regs) {
0049 mr = desc->hw.mask_regs + *reg_idx;
0050
0051 for (; *fld_idx < ARRAY_SIZE(mr->enum_ids); (*fld_idx)++) {
0052 if (mr->enum_ids[*fld_idx] != enum_id)
0053 continue;
0054
0055 if (mr->set_reg && mr->clr_reg) {
0056 fn = REG_FN_WRITE_BASE;
0057 mode = MODE_DUAL_REG;
0058 reg_e = mr->clr_reg;
0059 reg_d = mr->set_reg;
0060 } else {
0061 fn = REG_FN_MODIFY_BASE;
0062 if (mr->set_reg) {
0063 mode = MODE_ENABLE_REG;
0064 reg_e = mr->set_reg;
0065 reg_d = mr->set_reg;
0066 } else {
0067 mode = MODE_MASK_REG;
0068 reg_e = mr->clr_reg;
0069 reg_d = mr->clr_reg;
0070 }
0071 }
0072
0073 fn += (mr->reg_width >> 3) - 1;
0074 return _INTC_MK(fn, mode,
0075 intc_get_reg(d, reg_e),
0076 intc_get_reg(d, reg_d),
0077 1,
0078 (mr->reg_width - 1) - *fld_idx);
0079 }
0080
0081 *fld_idx = 0;
0082 (*reg_idx)++;
0083 }
0084
0085 return 0;
0086 }
0087
0088 unsigned int __init
0089 intc_get_mask_handle(struct intc_desc *desc, struct intc_desc_int *d,
0090 intc_enum enum_id, int do_grps)
0091 {
0092 unsigned int i = 0;
0093 unsigned int j = 0;
0094 unsigned int ret;
0095
0096 ret = _intc_mask_data(desc, d, enum_id, &i, &j);
0097 if (ret)
0098 return ret;
0099
0100 if (do_grps)
0101 return intc_get_mask_handle(desc, d, intc_grp_id(desc, enum_id), 0);
0102
0103 return 0;
0104 }
0105
0106 static unsigned int __init _intc_prio_data(struct intc_desc *desc,
0107 struct intc_desc_int *d,
0108 intc_enum enum_id,
0109 unsigned int *reg_idx,
0110 unsigned int *fld_idx)
0111 {
0112 struct intc_prio_reg *pr = desc->hw.prio_regs;
0113 unsigned int fn, n, mode, bit;
0114 unsigned long reg_e, reg_d;
0115
0116 while (pr && enum_id && *reg_idx < desc->hw.nr_prio_regs) {
0117 pr = desc->hw.prio_regs + *reg_idx;
0118
0119 for (; *fld_idx < ARRAY_SIZE(pr->enum_ids); (*fld_idx)++) {
0120 if (pr->enum_ids[*fld_idx] != enum_id)
0121 continue;
0122
0123 if (pr->set_reg && pr->clr_reg) {
0124 fn = REG_FN_WRITE_BASE;
0125 mode = MODE_PCLR_REG;
0126 reg_e = pr->set_reg;
0127 reg_d = pr->clr_reg;
0128 } else {
0129 fn = REG_FN_MODIFY_BASE;
0130 mode = MODE_PRIO_REG;
0131 if (!pr->set_reg)
0132 BUG();
0133 reg_e = pr->set_reg;
0134 reg_d = pr->set_reg;
0135 }
0136
0137 fn += (pr->reg_width >> 3) - 1;
0138 n = *fld_idx + 1;
0139
0140 BUG_ON(n * pr->field_width > pr->reg_width);
0141
0142 bit = pr->reg_width - (n * pr->field_width);
0143
0144 return _INTC_MK(fn, mode,
0145 intc_get_reg(d, reg_e),
0146 intc_get_reg(d, reg_d),
0147 pr->field_width, bit);
0148 }
0149
0150 *fld_idx = 0;
0151 (*reg_idx)++;
0152 }
0153
0154 return 0;
0155 }
0156
0157 unsigned int __init
0158 intc_get_prio_handle(struct intc_desc *desc, struct intc_desc_int *d,
0159 intc_enum enum_id, int do_grps)
0160 {
0161 unsigned int i = 0;
0162 unsigned int j = 0;
0163 unsigned int ret;
0164
0165 ret = _intc_prio_data(desc, d, enum_id, &i, &j);
0166 if (ret)
0167 return ret;
0168
0169 if (do_grps)
0170 return intc_get_prio_handle(desc, d, intc_grp_id(desc, enum_id), 0);
0171
0172 return 0;
0173 }
0174
0175 static unsigned int intc_ack_data(struct intc_desc *desc,
0176 struct intc_desc_int *d, intc_enum enum_id)
0177 {
0178 struct intc_mask_reg *mr = desc->hw.ack_regs;
0179 unsigned int i, j, fn, mode;
0180 unsigned long reg_e, reg_d;
0181
0182 for (i = 0; mr && enum_id && i < desc->hw.nr_ack_regs; i++) {
0183 mr = desc->hw.ack_regs + i;
0184
0185 for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
0186 if (mr->enum_ids[j] != enum_id)
0187 continue;
0188
0189 fn = REG_FN_MODIFY_BASE;
0190 mode = MODE_ENABLE_REG;
0191 reg_e = mr->set_reg;
0192 reg_d = mr->set_reg;
0193
0194 fn += (mr->reg_width >> 3) - 1;
0195 return _INTC_MK(fn, mode,
0196 intc_get_reg(d, reg_e),
0197 intc_get_reg(d, reg_d),
0198 1,
0199 (mr->reg_width - 1) - j);
0200 }
0201 }
0202
0203 return 0;
0204 }
0205
0206 static void intc_enable_disable(struct intc_desc_int *d,
0207 unsigned long handle, int do_enable)
0208 {
0209 unsigned long addr;
0210 unsigned int cpu;
0211 unsigned long (*fn)(unsigned long, unsigned long,
0212 unsigned long (*)(unsigned long, unsigned long,
0213 unsigned long),
0214 unsigned int);
0215
0216 if (do_enable) {
0217 for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
0218 addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
0219 fn = intc_enable_noprio_fns[_INTC_MODE(handle)];
0220 fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0);
0221 }
0222 } else {
0223 for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
0224 addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
0225 fn = intc_disable_fns[_INTC_MODE(handle)];
0226 fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0);
0227 }
0228 }
0229 }
0230
0231 void __init intc_enable_disable_enum(struct intc_desc *desc,
0232 struct intc_desc_int *d,
0233 intc_enum enum_id, int enable)
0234 {
0235 unsigned int i, j, data;
0236
0237
0238 i = j = 0;
0239 do {
0240 data = _intc_mask_data(desc, d, enum_id, &i, &j);
0241 if (data)
0242 intc_enable_disable(d, data, enable);
0243 j++;
0244 } while (data);
0245
0246
0247 i = j = 0;
0248 do {
0249 data = _intc_prio_data(desc, d, enum_id, &i, &j);
0250 if (data)
0251 intc_enable_disable(d, data, enable);
0252
0253 j++;
0254 } while (data);
0255 }
0256
0257 unsigned int __init
0258 intc_get_sense_handle(struct intc_desc *desc, struct intc_desc_int *d,
0259 intc_enum enum_id)
0260 {
0261 struct intc_sense_reg *sr = desc->hw.sense_regs;
0262 unsigned int i, j, fn, bit;
0263
0264 for (i = 0; sr && enum_id && i < desc->hw.nr_sense_regs; i++) {
0265 sr = desc->hw.sense_regs + i;
0266
0267 for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
0268 if (sr->enum_ids[j] != enum_id)
0269 continue;
0270
0271 fn = REG_FN_MODIFY_BASE;
0272 fn += (sr->reg_width >> 3) - 1;
0273
0274 BUG_ON((j + 1) * sr->field_width > sr->reg_width);
0275
0276 bit = sr->reg_width - ((j + 1) * sr->field_width);
0277
0278 return _INTC_MK(fn, 0, intc_get_reg(d, sr->reg),
0279 0, sr->field_width, bit);
0280 }
0281 }
0282
0283 return 0;
0284 }
0285
0286
0287 void intc_set_ack_handle(unsigned int irq, struct intc_desc *desc,
0288 struct intc_desc_int *d, intc_enum id)
0289 {
0290 unsigned long flags;
0291
0292
0293
0294
0295 if (!desc->hw.ack_regs)
0296 return;
0297
0298 raw_spin_lock_irqsave(&intc_big_lock, flags);
0299 ack_handle[irq] = intc_ack_data(desc, d, id);
0300 raw_spin_unlock_irqrestore(&intc_big_lock, flags);
0301 }
0302
0303 unsigned long intc_get_ack_handle(unsigned int irq)
0304 {
0305 return ack_handle[irq];
0306 }