diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2006-11-11 01:24:56 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-12-04 00:08:41 -0500 |
commit | a959ff56bbf07954ea4fa1cf72f99a38795eadb3 (patch) | |
tree | 85bd54ccfe77a9508a6cf2763d296ff988b9764f /arch | |
parent | fbf0274e43b7e17ee740fee2d693932be093d56d (diff) |
[POWERPC] Improve MPIC driver auto-configuration from DT
This patch applies on top of the MPIC DCR support. It makes the MPIC
driver capable of a lot more auto-configuration based on the device-tree,
for example, it can retreive it's own physical address if not passed as
an argument, find out if it's DCR or MMIO mapped, and set the BIG_ENDIAN
flag automatically in the presence of a "big-endian" property in the
device-tree node.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 50 |
1 files changed, 37 insertions, 13 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 909306ca04f4..411480d5c626 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -894,7 +894,7 @@ static struct irq_host_ops mpic_host_ops = { | |||
894 | */ | 894 | */ |
895 | 895 | ||
896 | struct mpic * __init mpic_alloc(struct device_node *node, | 896 | struct mpic * __init mpic_alloc(struct device_node *node, |
897 | unsigned long phys_addr, | 897 | phys_addr_t phys_addr, |
898 | unsigned int flags, | 898 | unsigned int flags, |
899 | unsigned int isu_size, | 899 | unsigned int isu_size, |
900 | unsigned int irq_count, | 900 | unsigned int irq_count, |
@@ -904,6 +904,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
904 | u32 reg; | 904 | u32 reg; |
905 | const char *vers; | 905 | const char *vers; |
906 | int i; | 906 | int i; |
907 | u64 paddr = phys_addr; | ||
907 | 908 | ||
908 | mpic = alloc_bootmem(sizeof(struct mpic)); | 909 | mpic = alloc_bootmem(sizeof(struct mpic)); |
909 | if (mpic == NULL) | 910 | if (mpic == NULL) |
@@ -943,6 +944,11 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
943 | mpic->irq_count = irq_count; | 944 | mpic->irq_count = irq_count; |
944 | mpic->num_sources = 0; /* so far */ | 945 | mpic->num_sources = 0; /* so far */ |
945 | 946 | ||
947 | /* Check for "big-endian" in device-tree */ | ||
948 | if (node && get_property(node, "big-endian", NULL) != NULL) | ||
949 | mpic->flags |= MPIC_BIG_ENDIAN; | ||
950 | |||
951 | |||
946 | #ifdef CONFIG_MPIC_WEIRD | 952 | #ifdef CONFIG_MPIC_WEIRD |
947 | mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)]; | 953 | mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)]; |
948 | #endif | 954 | #endif |
@@ -951,11 +957,17 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
951 | mpic->reg_type = (flags & MPIC_BIG_ENDIAN) ? | 957 | mpic->reg_type = (flags & MPIC_BIG_ENDIAN) ? |
952 | mpic_access_mmio_be : mpic_access_mmio_le; | 958 | mpic_access_mmio_be : mpic_access_mmio_le; |
953 | 959 | ||
960 | /* If no physical address is passed in, a device-node is mandatory */ | ||
961 | BUG_ON(paddr == 0 && node == NULL); | ||
962 | |||
963 | /* If no physical address passed in, check if it's dcr based */ | ||
964 | if (paddr == 0 && get_property(node, "dcr-reg", NULL) != NULL) | ||
965 | mpic->flags |= MPIC_USES_DCR; | ||
966 | |||
954 | #ifdef CONFIG_PPC_DCR | 967 | #ifdef CONFIG_PPC_DCR |
955 | if (mpic->flags & MPIC_USES_DCR) { | 968 | if (mpic->flags & MPIC_USES_DCR) { |
956 | const u32 *dbasep; | 969 | const u32 *dbasep; |
957 | BUG_ON(mpic->of_node == NULL); | 970 | dbasep = get_property(node, "dcr-reg", NULL); |
958 | dbasep = get_property(mpic->of_node, "dcr-reg", NULL); | ||
959 | BUG_ON(dbasep == NULL); | 971 | BUG_ON(dbasep == NULL); |
960 | mpic->dcr_base = *dbasep; | 972 | mpic->dcr_base = *dbasep; |
961 | mpic->reg_type = mpic_access_dcr; | 973 | mpic->reg_type = mpic_access_dcr; |
@@ -964,9 +976,20 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
964 | BUG_ON (mpic->flags & MPIC_USES_DCR); | 976 | BUG_ON (mpic->flags & MPIC_USES_DCR); |
965 | #endif /* CONFIG_PPC_DCR */ | 977 | #endif /* CONFIG_PPC_DCR */ |
966 | 978 | ||
979 | /* If the MPIC is not DCR based, and no physical address was passed | ||
980 | * in, try to obtain one | ||
981 | */ | ||
982 | if (paddr == 0 && !(mpic->flags & MPIC_USES_DCR)) { | ||
983 | const u32 *reg; | ||
984 | reg = get_property(node, "reg", NULL); | ||
985 | BUG_ON(reg == NULL); | ||
986 | paddr = of_translate_address(node, reg); | ||
987 | BUG_ON(paddr == OF_BAD_ADDR); | ||
988 | } | ||
989 | |||
967 | /* Map the global registers */ | 990 | /* Map the global registers */ |
968 | mpic_map(mpic, phys_addr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); | 991 | mpic_map(mpic, paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); |
969 | mpic_map(mpic, phys_addr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); | 992 | mpic_map(mpic, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); |
970 | 993 | ||
971 | /* Reset */ | 994 | /* Reset */ |
972 | if (flags & MPIC_WANTS_RESET) { | 995 | if (flags & MPIC_WANTS_RESET) { |
@@ -991,7 +1014,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
991 | 1014 | ||
992 | /* Map the per-CPU registers */ | 1015 | /* Map the per-CPU registers */ |
993 | for (i = 0; i < mpic->num_cpus; i++) { | 1016 | for (i = 0; i < mpic->num_cpus; i++) { |
994 | mpic_map(mpic, phys_addr, &mpic->cpuregs[i], | 1017 | mpic_map(mpic, paddr, &mpic->cpuregs[i], |
995 | MPIC_INFO(CPU_BASE) + i * MPIC_INFO(CPU_STRIDE), | 1018 | MPIC_INFO(CPU_BASE) + i * MPIC_INFO(CPU_STRIDE), |
996 | 0x1000); | 1019 | 0x1000); |
997 | } | 1020 | } |
@@ -999,7 +1022,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
999 | /* Initialize main ISU if none provided */ | 1022 | /* Initialize main ISU if none provided */ |
1000 | if (mpic->isu_size == 0) { | 1023 | if (mpic->isu_size == 0) { |
1001 | mpic->isu_size = mpic->num_sources; | 1024 | mpic->isu_size = mpic->num_sources; |
1002 | mpic_map(mpic, phys_addr, &mpic->isus[0], | 1025 | mpic_map(mpic, paddr, &mpic->isus[0], |
1003 | MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); | 1026 | MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); |
1004 | } | 1027 | } |
1005 | mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); | 1028 | mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); |
@@ -1020,10 +1043,11 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1020 | vers = "<unknown>"; | 1043 | vers = "<unknown>"; |
1021 | break; | 1044 | break; |
1022 | } | 1045 | } |
1023 | printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %lx, max %d CPUs\n", | 1046 | printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %llx," |
1024 | name, vers, phys_addr, mpic->num_cpus); | 1047 | " max %d CPUs\n", |
1025 | printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", mpic->isu_size, | 1048 | name, vers, (unsigned long long)paddr, mpic->num_cpus); |
1026 | mpic->isu_shift, mpic->isu_mask); | 1049 | printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", |
1050 | mpic->isu_size, mpic->isu_shift, mpic->isu_mask); | ||
1027 | 1051 | ||
1028 | mpic->next = mpics; | 1052 | mpic->next = mpics; |
1029 | mpics = mpic; | 1053 | mpics = mpic; |
@@ -1037,13 +1061,13 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1037 | } | 1061 | } |
1038 | 1062 | ||
1039 | void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, | 1063 | void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, |
1040 | unsigned long phys_addr) | 1064 | phys_addr_t paddr) |
1041 | { | 1065 | { |
1042 | unsigned int isu_first = isu_num * mpic->isu_size; | 1066 | unsigned int isu_first = isu_num * mpic->isu_size; |
1043 | 1067 | ||
1044 | BUG_ON(isu_num >= MPIC_MAX_ISU); | 1068 | BUG_ON(isu_num >= MPIC_MAX_ISU); |
1045 | 1069 | ||
1046 | mpic_map(mpic, phys_addr, &mpic->isus[isu_num], 0, | 1070 | mpic_map(mpic, paddr, &mpic->isus[isu_num], 0, |
1047 | MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); | 1071 | MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); |
1048 | if ((isu_first + mpic->isu_size) > mpic->num_sources) | 1072 | if ((isu_first + mpic->isu_size) > mpic->num_sources) |
1049 | mpic->num_sources = isu_first + mpic->isu_size; | 1073 | mpic->num_sources = isu_first + mpic->isu_size; |