diff options
author | Magnus Damm <damm@opensource.se> | 2010-03-19 03:48:01 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2010-03-19 03:48:01 -0400 |
commit | dec710b77c2cf04bf512acada3c14a16f11708d9 (patch) | |
tree | e2e25d5afa00df0eccb7c2881b29167ad4ff3b63 /drivers/sh | |
parent | 01e9651a21bc0e6731da733593e4aaf4cf46b5e5 (diff) |
sh: INTC ioremap support
Extend the INTC code with ioremap() support V2.
Support INTC controllers that are not accessible through
a 1:1 virt:phys window. Needed by SH-Mobile ARM INTCS.
The INTC code behaves as usual if the io window resource
is omitted. The slow phys->virt lookup only happens during
setup. The fast path code operates on virtual addresses.
Signed-off-by: Magnus Damm <damm@opensource.se>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/sh')
-rw-r--r-- | drivers/sh/intc.c | 84 |
1 files changed, 74 insertions, 10 deletions
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index d4aa4d1e8dce..a700dfec8dc3 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c | |||
@@ -43,6 +43,12 @@ struct intc_handle_int { | |||
43 | unsigned long handle; | 43 | unsigned long handle; |
44 | }; | 44 | }; |
45 | 45 | ||
46 | struct intc_window { | ||
47 | phys_addr_t phys; | ||
48 | void __iomem *virt; | ||
49 | unsigned long size; | ||
50 | }; | ||
51 | |||
46 | struct intc_desc_int { | 52 | struct intc_desc_int { |
47 | struct list_head list; | 53 | struct list_head list; |
48 | struct sys_device sysdev; | 54 | struct sys_device sysdev; |
@@ -56,6 +62,8 @@ struct intc_desc_int { | |||
56 | unsigned int nr_prio; | 62 | unsigned int nr_prio; |
57 | struct intc_handle_int *sense; | 63 | struct intc_handle_int *sense; |
58 | unsigned int nr_sense; | 64 | unsigned int nr_sense; |
65 | struct intc_window *window; | ||
66 | unsigned int nr_windows; | ||
59 | struct irq_chip chip; | 67 | struct irq_chip chip; |
60 | }; | 68 | }; |
61 | 69 | ||
@@ -420,11 +428,39 @@ static int intc_set_sense(unsigned int irq, unsigned int type) | |||
420 | return 0; | 428 | return 0; |
421 | } | 429 | } |
422 | 430 | ||
431 | static unsigned long intc_phys_to_virt(struct intc_desc_int *d, | ||
432 | unsigned long address) | ||
433 | { | ||
434 | struct intc_window *window; | ||
435 | int k; | ||
436 | |||
437 | /* scan through physical windows and convert address */ | ||
438 | for (k = 0; k < d->nr_windows; k++) { | ||
439 | window = d->window + k; | ||
440 | |||
441 | if (address < window->phys) | ||
442 | continue; | ||
443 | |||
444 | if (address >= (window->phys + window->size)) | ||
445 | continue; | ||
446 | |||
447 | address -= window->phys; | ||
448 | address += (unsigned long)window->virt; | ||
449 | |||
450 | return address; | ||
451 | } | ||
452 | |||
453 | /* no windows defined, register must be 1:1 mapped virt:phys */ | ||
454 | return address; | ||
455 | } | ||
456 | |||
423 | static unsigned int __init intc_get_reg(struct intc_desc_int *d, | 457 | static unsigned int __init intc_get_reg(struct intc_desc_int *d, |
424 | unsigned long address) | 458 | unsigned long address) |
425 | { | 459 | { |
426 | unsigned int k; | 460 | unsigned int k; |
427 | 461 | ||
462 | address = intc_phys_to_virt(d, address); | ||
463 | |||
428 | for (k = 0; k < d->nr_reg; k++) { | 464 | for (k = 0; k < d->nr_reg; k++) { |
429 | if (d->reg[k] == address) | 465 | if (d->reg[k] == address) |
430 | return k; | 466 | return k; |
@@ -774,6 +810,8 @@ static unsigned int __init save_reg(struct intc_desc_int *d, | |||
774 | unsigned int smp) | 810 | unsigned int smp) |
775 | { | 811 | { |
776 | if (value) { | 812 | if (value) { |
813 | value = intc_phys_to_virt(d, value); | ||
814 | |||
777 | d->reg[cnt] = value; | 815 | d->reg[cnt] = value; |
778 | #ifdef CONFIG_SMP | 816 | #ifdef CONFIG_SMP |
779 | d->smp[cnt] = smp; | 817 | d->smp[cnt] = smp; |
@@ -794,6 +832,7 @@ int __init register_intc_controller(struct intc_desc *desc) | |||
794 | unsigned int i, k, smp; | 832 | unsigned int i, k, smp; |
795 | struct intc_hw_desc *hw = &desc->hw; | 833 | struct intc_hw_desc *hw = &desc->hw; |
796 | struct intc_desc_int *d; | 834 | struct intc_desc_int *d; |
835 | struct resource *res; | ||
797 | 836 | ||
798 | d = kzalloc(sizeof(*d), GFP_NOWAIT); | 837 | d = kzalloc(sizeof(*d), GFP_NOWAIT); |
799 | if (!d) | 838 | if (!d) |
@@ -802,6 +841,25 @@ int __init register_intc_controller(struct intc_desc *desc) | |||
802 | INIT_LIST_HEAD(&d->list); | 841 | INIT_LIST_HEAD(&d->list); |
803 | list_add(&d->list, &intc_list); | 842 | list_add(&d->list, &intc_list); |
804 | 843 | ||
844 | if (desc->num_resources) { | ||
845 | d->nr_windows = desc->num_resources; | ||
846 | d->window = kzalloc(d->nr_windows * sizeof(*d->window), | ||
847 | GFP_NOWAIT); | ||
848 | if (!d->window) | ||
849 | goto err1; | ||
850 | |||
851 | for (k = 0; k < d->nr_windows; k++) { | ||
852 | res = desc->resource + k; | ||
853 | WARN_ON(resource_type(res) != IORESOURCE_MEM); | ||
854 | d->window[k].phys = res->start; | ||
855 | d->window[k].size = resource_size(res); | ||
856 | d->window[k].virt = ioremap_nocache(res->start, | ||
857 | resource_size(res)); | ||
858 | if (!d->window[k].virt) | ||
859 | goto err2; | ||
860 | } | ||
861 | } | ||
862 | |||
805 | d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0; | 863 | d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0; |
806 | d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0; | 864 | d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0; |
807 | d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0; | 865 | d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0; |
@@ -809,12 +867,12 @@ int __init register_intc_controller(struct intc_desc *desc) | |||
809 | 867 | ||
810 | d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT); | 868 | d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT); |
811 | if (!d->reg) | 869 | if (!d->reg) |
812 | goto err1; | 870 | goto err2; |
813 | 871 | ||
814 | #ifdef CONFIG_SMP | 872 | #ifdef CONFIG_SMP |
815 | d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT); | 873 | d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT); |
816 | if (!d->smp) | 874 | if (!d->smp) |
817 | goto err2; | 875 | goto err3; |
818 | #endif | 876 | #endif |
819 | k = 0; | 877 | k = 0; |
820 | 878 | ||
@@ -830,7 +888,7 @@ int __init register_intc_controller(struct intc_desc *desc) | |||
830 | d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio), | 888 | d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio), |
831 | GFP_NOWAIT); | 889 | GFP_NOWAIT); |
832 | if (!d->prio) | 890 | if (!d->prio) |
833 | goto err3; | 891 | goto err4; |
834 | 892 | ||
835 | for (i = 0; i < hw->nr_prio_regs; i++) { | 893 | for (i = 0; i < hw->nr_prio_regs; i++) { |
836 | smp = IS_SMP(hw->prio_regs[i]); | 894 | smp = IS_SMP(hw->prio_regs[i]); |
@@ -843,7 +901,7 @@ int __init register_intc_controller(struct intc_desc *desc) | |||
843 | d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense), | 901 | d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense), |
844 | GFP_NOWAIT); | 902 | GFP_NOWAIT); |
845 | if (!d->sense) | 903 | if (!d->sense) |
846 | goto err4; | 904 | goto err5; |
847 | 905 | ||
848 | for (i = 0; i < hw->nr_sense_regs; i++) | 906 | for (i = 0; i < hw->nr_sense_regs; i++) |
849 | k += save_reg(d, k, hw->sense_regs[i].reg, 0); | 907 | k += save_reg(d, k, hw->sense_regs[i].reg, 0); |
@@ -925,17 +983,23 @@ int __init register_intc_controller(struct intc_desc *desc) | |||
925 | intc_enable_disable_enum(desc, d, desc->force_enable, 1); | 983 | intc_enable_disable_enum(desc, d, desc->force_enable, 1); |
926 | 984 | ||
927 | return 0; | 985 | return 0; |
928 | err4: | 986 | err5: |
929 | kfree(d->prio); | 987 | kfree(d->prio); |
930 | err3: | 988 | err4: |
931 | #ifdef CONFIG_SMP | 989 | #ifdef CONFIG_SMP |
932 | kfree(d->smp); | 990 | kfree(d->smp); |
933 | err2: | 991 | err3: |
934 | #endif | 992 | #endif |
935 | kfree(d->reg); | 993 | kfree(d->reg); |
936 | err1: | 994 | err2: |
995 | for (k = 0; k < d->nr_windows; k++) | ||
996 | if (d->window[k].virt) | ||
997 | iounmap(d->window[k].virt); | ||
998 | |||
999 | kfree(d->window); | ||
1000 | err1: | ||
937 | kfree(d); | 1001 | kfree(d); |
938 | err0: | 1002 | err0: |
939 | pr_err("unable to allocate INTC memory\n"); | 1003 | pr_err("unable to allocate INTC memory\n"); |
940 | 1004 | ||
941 | return -ENOMEM; | 1005 | return -ENOMEM; |