aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/mpic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/sysdev/mpic.c')
-rw-r--r--arch/powerpc/sysdev/mpic.c102
1 files changed, 85 insertions, 17 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index bfc6211e5422..9c6e535daad2 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -6,7 +6,7 @@
6 * with various broken implementations of this HW. 6 * with various broken implementations of this HW.
7 * 7 *
8 * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp. 8 * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp.
9 * Copyright 2010-2011 Freescale Semiconductor, Inc. 9 * Copyright 2010-2012 Freescale Semiconductor, Inc.
10 * 10 *
11 * This file is subject to the terms and conditions of the GNU General Public 11 * This file is subject to the terms and conditions of the GNU General Public
12 * License. See the file COPYING in the main directory of this archive 12 * License. See the file COPYING in the main directory of this archive
@@ -221,24 +221,24 @@ static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 valu
221 _mpic_write(mpic->reg_type, &mpic->gregs, offset, value); 221 _mpic_write(mpic->reg_type, &mpic->gregs, offset, value);
222} 222}
223 223
224static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm) 224static inline unsigned int mpic_tm_offset(struct mpic *mpic, unsigned int tm)
225{ 225{
226 unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) + 226 return (tm >> 2) * MPIC_TIMER_GROUP_STRIDE +
227 ((tm & 3) * MPIC_INFO(TIMER_STRIDE)); 227 (tm & 3) * MPIC_INFO(TIMER_STRIDE);
228}
228 229
229 if (tm >= 4) 230static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm)
230 offset += 0x1000 / 4; 231{
232 unsigned int offset = mpic_tm_offset(mpic, tm) +
233 MPIC_INFO(TIMER_VECTOR_PRI);
231 234
232 return _mpic_read(mpic->reg_type, &mpic->tmregs, offset); 235 return _mpic_read(mpic->reg_type, &mpic->tmregs, offset);
233} 236}
234 237
235static inline void _mpic_tm_write(struct mpic *mpic, unsigned int tm, u32 value) 238static inline void _mpic_tm_write(struct mpic *mpic, unsigned int tm, u32 value)
236{ 239{
237 unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) + 240 unsigned int offset = mpic_tm_offset(mpic, tm) +
238 ((tm & 3) * MPIC_INFO(TIMER_STRIDE)); 241 MPIC_INFO(TIMER_VECTOR_PRI);
239
240 if (tm >= 4)
241 offset += 0x1000 / 4;
242 242
243 _mpic_write(mpic->reg_type, &mpic->tmregs, offset, value); 243 _mpic_write(mpic->reg_type, &mpic->tmregs, offset, value);
244} 244}
@@ -1026,6 +1026,9 @@ static int mpic_host_map(struct irq_domain *h, unsigned int virq,
1026 return 0; 1026 return 0;
1027 } 1027 }
1028 1028
1029 if (mpic_map_error_int(mpic, virq, hw))
1030 return 0;
1031
1029 if (hw >= mpic->num_sources) 1032 if (hw >= mpic->num_sources)
1030 return -EINVAL; 1033 return -EINVAL;
1031 1034
@@ -1085,7 +1088,16 @@ static int mpic_host_xlate(struct irq_domain *h, struct device_node *ct,
1085 */ 1088 */
1086 switch (intspec[2]) { 1089 switch (intspec[2]) {
1087 case 0: 1090 case 0:
1088 case 1: /* no EISR/EIMR support for now, treat as shared IRQ */ 1091 break;
1092 case 1:
1093 if (!(mpic->flags & MPIC_FSL_HAS_EIMR))
1094 break;
1095
1096 if (intspec[3] >= ARRAY_SIZE(mpic->err_int_vecs))
1097 return -EINVAL;
1098
1099 *out_hwirq = mpic->err_int_vecs[intspec[3]];
1100
1089 break; 1101 break;
1090 case 2: 1102 case 2:
1091 if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs)) 1103 if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs))
@@ -1301,6 +1313,42 @@ struct mpic * __init mpic_alloc(struct device_node *node,
1301 mpic_map(mpic, mpic->paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); 1313 mpic_map(mpic, mpic->paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000);
1302 mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); 1314 mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
1303 1315
1316 if (mpic->flags & MPIC_FSL) {
1317 u32 brr1, version;
1318 int ret;
1319
1320 /*
1321 * Yes, Freescale really did put global registers in the
1322 * magic per-cpu area -- and they don't even show up in the
1323 * non-magic per-cpu copies that this driver normally uses.
1324 */
1325 mpic_map(mpic, mpic->paddr, &mpic->thiscpuregs,
1326 MPIC_CPU_THISBASE, 0x1000);
1327
1328 brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
1329 MPIC_FSL_BRR1);
1330 version = brr1 & MPIC_FSL_BRR1_VER;
1331
1332 /* Error interrupt mask register (EIMR) is required for
1333 * handling individual device error interrupts. EIMR
1334 * was added in MPIC version 4.1.
1335 *
1336 * Over here we reserve vector number space for error
1337 * interrupt vectors. This space is stolen from the
1338 * global vector number space, as in case of ipis
1339 * and timer interrupts.
1340 *
1341 * Available vector space = intvec_top - 12, where 12
1342 * is the number of vectors which have been consumed by
1343 * ipis and timer interrupts.
1344 */
1345 if (version >= 0x401) {
1346 ret = mpic_setup_error_int(mpic, intvec_top - 12);
1347 if (ret)
1348 return NULL;
1349 }
1350 }
1351
1304 /* Reset */ 1352 /* Reset */
1305 1353
1306 /* When using a device-node, reset requests are only honored if the MPIC 1354 /* When using a device-node, reset requests are only honored if the MPIC
@@ -1440,6 +1488,7 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
1440void __init mpic_init(struct mpic *mpic) 1488void __init mpic_init(struct mpic *mpic)
1441{ 1489{
1442 int i, cpu; 1490 int i, cpu;
1491 int num_timers = 4;
1443 1492
1444 BUG_ON(mpic->num_sources == 0); 1493 BUG_ON(mpic->num_sources == 0);
1445 1494
@@ -1448,15 +1497,34 @@ void __init mpic_init(struct mpic *mpic)
1448 /* Set current processor priority to max */ 1497 /* Set current processor priority to max */
1449 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); 1498 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
1450 1499
1500 if (mpic->flags & MPIC_FSL) {
1501 u32 brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
1502 MPIC_FSL_BRR1);
1503 u32 version = brr1 & MPIC_FSL_BRR1_VER;
1504
1505 /*
1506 * Timer group B is present at the latest in MPIC 3.1 (e.g.
1507 * mpc8536). It is not present in MPIC 2.0 (e.g. mpc8544).
1508 * I don't know about the status of intermediate versions (or
1509 * whether they even exist).
1510 */
1511 if (version >= 0x0301)
1512 num_timers = 8;
1513 }
1514
1515 /* FSL mpic error interrupt intialization */
1516 if (mpic->flags & MPIC_FSL_HAS_EIMR)
1517 mpic_err_int_init(mpic, MPIC_FSL_ERR_INT);
1518
1451 /* Initialize timers to our reserved vectors and mask them for now */ 1519 /* Initialize timers to our reserved vectors and mask them for now */
1452 for (i = 0; i < 4; i++) { 1520 for (i = 0; i < num_timers; i++) {
1521 unsigned int offset = mpic_tm_offset(mpic, i);
1522
1453 mpic_write(mpic->tmregs, 1523 mpic_write(mpic->tmregs,
1454 i * MPIC_INFO(TIMER_STRIDE) + 1524 offset + MPIC_INFO(TIMER_DESTINATION),
1455 MPIC_INFO(TIMER_DESTINATION),
1456 1 << hard_smp_processor_id()); 1525 1 << hard_smp_processor_id());
1457 mpic_write(mpic->tmregs, 1526 mpic_write(mpic->tmregs,
1458 i * MPIC_INFO(TIMER_STRIDE) + 1527 offset + MPIC_INFO(TIMER_VECTOR_PRI),
1459 MPIC_INFO(TIMER_VECTOR_PRI),
1460 MPIC_VECPRI_MASK | 1528 MPIC_VECPRI_MASK |
1461 (9 << MPIC_VECPRI_PRIORITY_SHIFT) | 1529 (9 << MPIC_VECPRI_PRIORITY_SHIFT) |
1462 (mpic->timer_vecs[0] + i)); 1530 (mpic->timer_vecs[0] + i));