aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorDavid Daney <david.daney@cavium.com>2012-07-05 12:12:39 -0400
committerRalf Baechle <ralf@linux-mips.org>2012-07-23 08:54:53 -0400
commita0c16582b5b50792b0fd3e07d23c537936fafcb7 (patch)
tree0c063bc5c775115fdd2d6709971d61151b807ace /arch/mips
parent7ed1815296498e9d1bfa1f13e94b743364b14caf (diff)
MIPS: Octeon: Setup irq_domains for interrupts.
Create two domains. One for the GPIO lines, and the other for on-chip sources. Signed-off-by: David Daney <david.daney@cavium.com> Cc: linux-mips@linux-mips.org Cc: devicetree-discuss@lists.ozlabs.org Cc: Grant Likely <grant.likely@secretlab.ca> Cc: Rob Herring <rob.herring@calxeda.com> Cc: linux-kernel@vger.kernel.org Cc: David Daney <david.daney@cavium.com> Patchwork: https://patchwork.linux-mips.org/patch/3936/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/cavium-octeon/octeon-irq.c215
1 files changed, 206 insertions, 9 deletions
diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c
index fac22a89f614..52610ce50dfc 100644
--- a/arch/mips/cavium-octeon/octeon-irq.c
+++ b/arch/mips/cavium-octeon/octeon-irq.c
@@ -3,14 +3,17 @@
3 * License. See the file "COPYING" in the main directory of this archive 3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details. 4 * for more details.
5 * 5 *
6 * Copyright (C) 2004-2008, 2009, 2010, 2011 Cavium Networks 6 * Copyright (C) 2004-2012 Cavium, Inc.
7 */ 7 */
8 8
9#include <linux/interrupt.h> 9#include <linux/interrupt.h>
10#include <linux/irqdomain.h>
10#include <linux/bitops.h> 11#include <linux/bitops.h>
11#include <linux/percpu.h> 12#include <linux/percpu.h>
13#include <linux/slab.h>
12#include <linux/irq.h> 14#include <linux/irq.h>
13#include <linux/smp.h> 15#include <linux/smp.h>
16#include <linux/of.h>
14 17
15#include <asm/octeon/octeon.h> 18#include <asm/octeon/octeon.h>
16 19
@@ -42,9 +45,9 @@ struct octeon_core_chip_data {
42 45
43static struct octeon_core_chip_data octeon_irq_core_chip_data[MIPS_CORE_IRQ_LINES]; 46static struct octeon_core_chip_data octeon_irq_core_chip_data[MIPS_CORE_IRQ_LINES];
44 47
45static void __init octeon_irq_set_ciu_mapping(int irq, int line, int bit, 48static void octeon_irq_set_ciu_mapping(int irq, int line, int bit,
46 struct irq_chip *chip, 49 struct irq_chip *chip,
47 irq_flow_handler_t handler) 50 irq_flow_handler_t handler)
48{ 51{
49 union octeon_ciu_chip_data cd; 52 union octeon_ciu_chip_data cd;
50 53
@@ -847,6 +850,178 @@ static struct irq_chip octeon_irq_chip_ciu_wd = {
847 .irq_mask = octeon_irq_dummy_mask, 850 .irq_mask = octeon_irq_dummy_mask,
848}; 851};
849 852
853static bool octeon_irq_ciu_is_edge(unsigned int line, unsigned int bit)
854{
855 bool edge = false;
856
857 if (line == 0)
858 switch (bit) {
859 case 48 ... 49: /* GMX DRP */
860 case 50: /* IPD_DRP */
861 case 52 ... 55: /* Timers */
862 case 58: /* MPI */
863 edge = true;
864 break;
865 default:
866 break;
867 }
868 else /* line == 1 */
869 switch (bit) {
870 case 47: /* PTP */
871 edge = true;
872 break;
873 default:
874 break;
875 }
876 return edge;
877}
878
879struct octeon_irq_gpio_domain_data {
880 unsigned int base_hwirq;
881};
882
883static int octeon_irq_gpio_xlat(struct irq_domain *d,
884 struct device_node *node,
885 const u32 *intspec,
886 unsigned int intsize,
887 unsigned long *out_hwirq,
888 unsigned int *out_type)
889{
890 unsigned int type;
891 unsigned int pin;
892 unsigned int trigger;
893 struct octeon_irq_gpio_domain_data *gpiod;
894
895 if (d->of_node != node)
896 return -EINVAL;
897
898 if (intsize < 2)
899 return -EINVAL;
900
901 pin = intspec[0];
902 if (pin >= 16)
903 return -EINVAL;
904
905 trigger = intspec[1];
906
907 switch (trigger) {
908 case 1:
909 type = IRQ_TYPE_EDGE_RISING;
910 break;
911 case 2:
912 type = IRQ_TYPE_EDGE_FALLING;
913 break;
914 case 4:
915 type = IRQ_TYPE_LEVEL_HIGH;
916 break;
917 case 8:
918 type = IRQ_TYPE_LEVEL_LOW;
919 break;
920 default:
921 pr_err("Error: (%s) Invalid irq trigger specification: %x\n",
922 node->name,
923 trigger);
924 type = IRQ_TYPE_LEVEL_LOW;
925 break;
926 }
927 *out_type = type;
928 gpiod = d->host_data;
929 *out_hwirq = gpiod->base_hwirq + pin;
930
931 return 0;
932}
933
934static int octeon_irq_ciu_xlat(struct irq_domain *d,
935 struct device_node *node,
936 const u32 *intspec,
937 unsigned int intsize,
938 unsigned long *out_hwirq,
939 unsigned int *out_type)
940{
941 unsigned int ciu, bit;
942
943 ciu = intspec[0];
944 bit = intspec[1];
945
946 if (ciu > 1 || bit > 63)
947 return -EINVAL;
948
949 /* These are the GPIO lines */
950 if (ciu == 0 && bit >= 16 && bit < 32)
951 return -EINVAL;
952
953 *out_hwirq = (ciu << 6) | bit;
954 *out_type = 0;
955
956 return 0;
957}
958
959static struct irq_chip *octeon_irq_ciu_chip;
960static struct irq_chip *octeon_irq_gpio_chip;
961
962static bool octeon_irq_virq_in_range(unsigned int virq)
963{
964 /* We cannot let it overflow the mapping array. */
965 if (virq < (1ul << 8 * sizeof(octeon_irq_ciu_to_irq[0][0])))
966 return true;
967
968 WARN_ONCE(true, "virq out of range %u.\n", virq);
969 return false;
970}
971
972static int octeon_irq_ciu_map(struct irq_domain *d,
973 unsigned int virq, irq_hw_number_t hw)
974{
975 unsigned int line = hw >> 6;
976 unsigned int bit = hw & 63;
977
978 if (!octeon_irq_virq_in_range(virq))
979 return -EINVAL;
980
981 if (line > 1 || octeon_irq_ciu_to_irq[line][bit] != 0)
982 return -EINVAL;
983
984 if (octeon_irq_ciu_is_edge(line, bit))
985 octeon_irq_set_ciu_mapping(virq, line, bit,
986 octeon_irq_ciu_chip,
987 handle_edge_irq);
988 else
989 octeon_irq_set_ciu_mapping(virq, line, bit,
990 octeon_irq_ciu_chip,
991 handle_level_irq);
992
993 return 0;
994}
995
996static int octeon_irq_gpio_map(struct irq_domain *d,
997 unsigned int virq, irq_hw_number_t hw)
998{
999 unsigned int line = hw >> 6;
1000 unsigned int bit = hw & 63;
1001
1002 if (!octeon_irq_virq_in_range(virq))
1003 return -EINVAL;
1004
1005 if (line > 1 || octeon_irq_ciu_to_irq[line][bit] != 0)
1006 return -EINVAL;
1007
1008 octeon_irq_set_ciu_mapping(virq, line, bit,
1009 octeon_irq_gpio_chip,
1010 octeon_irq_handle_gpio);
1011
1012 return 0;
1013}
1014
1015static struct irq_domain_ops octeon_irq_domain_ciu_ops = {
1016 .map = octeon_irq_ciu_map,
1017 .xlate = octeon_irq_ciu_xlat,
1018};
1019
1020static struct irq_domain_ops octeon_irq_domain_gpio_ops = {
1021 .map = octeon_irq_gpio_map,
1022 .xlate = octeon_irq_gpio_xlat,
1023};
1024
850static void octeon_irq_ip2_v1(void) 1025static void octeon_irq_ip2_v1(void)
851{ 1026{
852 const unsigned long core_id = cvmx_get_core_num(); 1027 const unsigned long core_id = cvmx_get_core_num();
@@ -972,7 +1147,8 @@ static void __init octeon_irq_init_ciu(void)
972 struct irq_chip *chip; 1147 struct irq_chip *chip;
973 struct irq_chip *chip_mbox; 1148 struct irq_chip *chip_mbox;
974 struct irq_chip *chip_wd; 1149 struct irq_chip *chip_wd;
975 struct irq_chip *chip_gpio; 1150 struct device_node *gpio_node;
1151 struct device_node *ciu_node;
976 1152
977 octeon_irq_init_ciu_percpu(); 1153 octeon_irq_init_ciu_percpu();
978 octeon_irq_setup_secondary = octeon_irq_setup_secondary_ciu; 1154 octeon_irq_setup_secondary = octeon_irq_setup_secondary_ciu;
@@ -986,15 +1162,16 @@ static void __init octeon_irq_init_ciu(void)
986 chip = &octeon_irq_chip_ciu_v2; 1162 chip = &octeon_irq_chip_ciu_v2;
987 chip_mbox = &octeon_irq_chip_ciu_mbox_v2; 1163 chip_mbox = &octeon_irq_chip_ciu_mbox_v2;
988 chip_wd = &octeon_irq_chip_ciu_wd_v2; 1164 chip_wd = &octeon_irq_chip_ciu_wd_v2;
989 chip_gpio = &octeon_irq_chip_ciu_gpio_v2; 1165 octeon_irq_gpio_chip = &octeon_irq_chip_ciu_gpio_v2;
990 } else { 1166 } else {
991 octeon_irq_ip2 = octeon_irq_ip2_v1; 1167 octeon_irq_ip2 = octeon_irq_ip2_v1;
992 octeon_irq_ip3 = octeon_irq_ip3_v1; 1168 octeon_irq_ip3 = octeon_irq_ip3_v1;
993 chip = &octeon_irq_chip_ciu; 1169 chip = &octeon_irq_chip_ciu;
994 chip_mbox = &octeon_irq_chip_ciu_mbox; 1170 chip_mbox = &octeon_irq_chip_ciu_mbox;
995 chip_wd = &octeon_irq_chip_ciu_wd; 1171 chip_wd = &octeon_irq_chip_ciu_wd;
996 chip_gpio = &octeon_irq_chip_ciu_gpio; 1172 octeon_irq_gpio_chip = &octeon_irq_chip_ciu_gpio;
997 } 1173 }
1174 octeon_irq_ciu_chip = chip;
998 octeon_irq_ip4 = octeon_irq_ip4_mask; 1175 octeon_irq_ip4 = octeon_irq_ip4_mask;
999 1176
1000 /* Mips internal */ 1177 /* Mips internal */
@@ -1003,8 +1180,6 @@ static void __init octeon_irq_init_ciu(void)
1003 /* CIU_0 */ 1180 /* CIU_0 */
1004 for (i = 0; i < 16; i++) 1181 for (i = 0; i < 16; i++)
1005 octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WORKQ0, 0, i + 0, chip, handle_level_irq); 1182 octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WORKQ0, 0, i + 0, chip, handle_level_irq);
1006 for (i = 0; i < 16; i++)
1007 octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_GPIO0, 0, i + 16, chip_gpio, octeon_irq_handle_gpio);
1008 1183
1009 octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX0, 0, 32, chip_mbox, handle_percpu_irq); 1184 octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX0, 0, 32, chip_mbox, handle_percpu_irq);
1010 octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX1, 0, 33, chip_mbox, handle_percpu_irq); 1185 octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX1, 0, 33, chip_mbox, handle_percpu_irq);
@@ -1035,6 +1210,28 @@ static void __init octeon_irq_init_ciu(void)
1035 octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB1, 1, 17, chip, handle_level_irq); 1210 octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB1, 1, 17, chip, handle_level_irq);
1036 octeon_irq_set_ciu_mapping(OCTEON_IRQ_MII1, 1, 18, chip, handle_level_irq); 1211 octeon_irq_set_ciu_mapping(OCTEON_IRQ_MII1, 1, 18, chip, handle_level_irq);
1037 1212
1213 gpio_node = of_find_compatible_node(NULL, NULL, "cavium,octeon-3860-gpio");
1214 if (gpio_node) {
1215 struct octeon_irq_gpio_domain_data *gpiod;
1216
1217 gpiod = kzalloc(sizeof(*gpiod), GFP_KERNEL);
1218 if (gpiod) {
1219 /* gpio domain host_data is the base hwirq number. */
1220 gpiod->base_hwirq = 16;
1221 irq_domain_add_linear(gpio_node, 16, &octeon_irq_domain_gpio_ops, gpiod);
1222 of_node_put(gpio_node);
1223 } else
1224 pr_warn("Cannot allocate memory for GPIO irq_domain.\n");
1225 } else
1226 pr_warn("Cannot find device node for cavium,octeon-3860-gpio.\n");
1227
1228 ciu_node = of_find_compatible_node(NULL, NULL, "cavium,octeon-3860-ciu");
1229 if (ciu_node) {
1230 irq_domain_add_tree(ciu_node, &octeon_irq_domain_ciu_ops, NULL);
1231 of_node_put(ciu_node);
1232 } else
1233 pr_warn("Cannot find device node for cavium,octeon-3860-ciu.\n");
1234
1038 /* Enable the CIU lines */ 1235 /* Enable the CIU lines */
1039 set_c0_status(STATUSF_IP3 | STATUSF_IP2); 1236 set_c0_status(STATUSF_IP3 | STATUSF_IP2);
1040 clear_c0_status(STATUSF_IP4); 1237 clear_c0_status(STATUSF_IP4);