aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bus/mvebu-mbus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/bus/mvebu-mbus.c')
-rw-r--r--drivers/bus/mvebu-mbus.c180
1 files changed, 176 insertions, 4 deletions
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
index 26c3779d871d..eb7682dc123b 100644
--- a/drivers/bus/mvebu-mbus.c
+++ b/drivers/bus/mvebu-mbus.c
@@ -57,6 +57,7 @@
57#include <linux/of_address.h> 57#include <linux/of_address.h>
58#include <linux/debugfs.h> 58#include <linux/debugfs.h>
59#include <linux/log2.h> 59#include <linux/log2.h>
60#include <linux/syscore_ops.h>
60 61
61/* 62/*
62 * DDR target is the same on all platforms. 63 * DDR target is the same on all platforms.
@@ -94,20 +95,42 @@
94 95
95#define DOVE_DDR_BASE_CS_OFF(n) ((n) << 4) 96#define DOVE_DDR_BASE_CS_OFF(n) ((n) << 4)
96 97
98/* Relative to mbusbridge_base */
99#define MBUS_BRIDGE_CTRL_OFF 0x0
100#define MBUS_BRIDGE_BASE_OFF 0x4
101
102/* Maximum number of windows, for all known platforms */
103#define MBUS_WINS_MAX 20
104
97struct mvebu_mbus_state; 105struct mvebu_mbus_state;
98 106
99struct mvebu_mbus_soc_data { 107struct mvebu_mbus_soc_data {
100 unsigned int num_wins; 108 unsigned int num_wins;
101 unsigned int num_remappable_wins; 109 unsigned int num_remappable_wins;
110 bool has_mbus_bridge;
102 unsigned int (*win_cfg_offset)(const int win); 111 unsigned int (*win_cfg_offset)(const int win);
103 void (*setup_cpu_target)(struct mvebu_mbus_state *s); 112 void (*setup_cpu_target)(struct mvebu_mbus_state *s);
113 int (*save_cpu_target)(struct mvebu_mbus_state *s,
114 u32 *store_addr);
104 int (*show_cpu_target)(struct mvebu_mbus_state *s, 115 int (*show_cpu_target)(struct mvebu_mbus_state *s,
105 struct seq_file *seq, void *v); 116 struct seq_file *seq, void *v);
106}; 117};
107 118
119/*
120 * Used to store the state of one MBus window accross suspend/resume.
121 */
122struct mvebu_mbus_win_data {
123 u32 ctrl;
124 u32 base;
125 u32 remap_lo;
126 u32 remap_hi;
127};
128
108struct mvebu_mbus_state { 129struct mvebu_mbus_state {
109 void __iomem *mbuswins_base; 130 void __iomem *mbuswins_base;
110 void __iomem *sdramwins_base; 131 void __iomem *sdramwins_base;
132 void __iomem *mbusbridge_base;
133 phys_addr_t sdramwins_phys_base;
111 struct dentry *debugfs_root; 134 struct dentry *debugfs_root;
112 struct dentry *debugfs_sdram; 135 struct dentry *debugfs_sdram;
113 struct dentry *debugfs_devs; 136 struct dentry *debugfs_devs;
@@ -115,6 +138,11 @@ struct mvebu_mbus_state {
115 struct resource pcie_io_aperture; 138 struct resource pcie_io_aperture;
116 const struct mvebu_mbus_soc_data *soc; 139 const struct mvebu_mbus_soc_data *soc;
117 int hw_io_coherency; 140 int hw_io_coherency;
141
142 /* Used during suspend/resume */
143 u32 mbus_bridge_ctrl;
144 u32 mbus_bridge_base;
145 struct mvebu_mbus_win_data wins[MBUS_WINS_MAX];
118}; 146};
119 147
120static struct mvebu_mbus_state mbus_state; 148static struct mvebu_mbus_state mbus_state;
@@ -516,6 +544,28 @@ mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus)
516 mvebu_mbus_dram_info.num_cs = cs; 544 mvebu_mbus_dram_info.num_cs = cs;
517} 545}
518 546
547static int
548mvebu_mbus_default_save_cpu_target(struct mvebu_mbus_state *mbus,
549 u32 *store_addr)
550{
551 int i;
552
553 for (i = 0; i < 4; i++) {
554 u32 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i));
555 u32 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i));
556
557 writel(mbus->sdramwins_phys_base + DDR_BASE_CS_OFF(i),
558 store_addr++);
559 writel(base, store_addr++);
560 writel(mbus->sdramwins_phys_base + DDR_SIZE_CS_OFF(i),
561 store_addr++);
562 writel(size, store_addr++);
563 }
564
565 /* We've written 16 words to the store address */
566 return 16;
567}
568
519static void __init 569static void __init
520mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus) 570mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus)
521{ 571{
@@ -546,10 +596,35 @@ mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus)
546 mvebu_mbus_dram_info.num_cs = cs; 596 mvebu_mbus_dram_info.num_cs = cs;
547} 597}
548 598
599static int
600mvebu_mbus_dove_save_cpu_target(struct mvebu_mbus_state *mbus,
601 u32 *store_addr)
602{
603 int i;
604
605 for (i = 0; i < 2; i++) {
606 u32 map = readl(mbus->sdramwins_base + DOVE_DDR_BASE_CS_OFF(i));
607
608 writel(mbus->sdramwins_phys_base + DOVE_DDR_BASE_CS_OFF(i),
609 store_addr++);
610 writel(map, store_addr++);
611 }
612
613 /* We've written 4 words to the store address */
614 return 4;
615}
616
617int mvebu_mbus_save_cpu_target(u32 *store_addr)
618{
619 return mbus_state.soc->save_cpu_target(&mbus_state, store_addr);
620}
621
549static const struct mvebu_mbus_soc_data armada_370_xp_mbus_data = { 622static const struct mvebu_mbus_soc_data armada_370_xp_mbus_data = {
550 .num_wins = 20, 623 .num_wins = 20,
551 .num_remappable_wins = 8, 624 .num_remappable_wins = 8,
625 .has_mbus_bridge = true,
552 .win_cfg_offset = armada_370_xp_mbus_win_offset, 626 .win_cfg_offset = armada_370_xp_mbus_win_offset,
627 .save_cpu_target = mvebu_mbus_default_save_cpu_target,
553 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, 628 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
554 .show_cpu_target = mvebu_sdram_debug_show_orion, 629 .show_cpu_target = mvebu_sdram_debug_show_orion,
555}; 630};
@@ -558,6 +633,7 @@ static const struct mvebu_mbus_soc_data kirkwood_mbus_data = {
558 .num_wins = 8, 633 .num_wins = 8,
559 .num_remappable_wins = 4, 634 .num_remappable_wins = 4,
560 .win_cfg_offset = orion_mbus_win_offset, 635 .win_cfg_offset = orion_mbus_win_offset,
636 .save_cpu_target = mvebu_mbus_default_save_cpu_target,
561 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, 637 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
562 .show_cpu_target = mvebu_sdram_debug_show_orion, 638 .show_cpu_target = mvebu_sdram_debug_show_orion,
563}; 639};
@@ -566,6 +642,7 @@ static const struct mvebu_mbus_soc_data dove_mbus_data = {
566 .num_wins = 8, 642 .num_wins = 8,
567 .num_remappable_wins = 4, 643 .num_remappable_wins = 4,
568 .win_cfg_offset = orion_mbus_win_offset, 644 .win_cfg_offset = orion_mbus_win_offset,
645 .save_cpu_target = mvebu_mbus_dove_save_cpu_target,
569 .setup_cpu_target = mvebu_mbus_dove_setup_cpu_target, 646 .setup_cpu_target = mvebu_mbus_dove_setup_cpu_target,
570 .show_cpu_target = mvebu_sdram_debug_show_dove, 647 .show_cpu_target = mvebu_sdram_debug_show_dove,
571}; 648};
@@ -578,6 +655,7 @@ static const struct mvebu_mbus_soc_data orion5x_4win_mbus_data = {
578 .num_wins = 8, 655 .num_wins = 8,
579 .num_remappable_wins = 4, 656 .num_remappable_wins = 4,
580 .win_cfg_offset = orion_mbus_win_offset, 657 .win_cfg_offset = orion_mbus_win_offset,
658 .save_cpu_target = mvebu_mbus_default_save_cpu_target,
581 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, 659 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
582 .show_cpu_target = mvebu_sdram_debug_show_orion, 660 .show_cpu_target = mvebu_sdram_debug_show_orion,
583}; 661};
@@ -586,6 +664,7 @@ static const struct mvebu_mbus_soc_data orion5x_2win_mbus_data = {
586 .num_wins = 8, 664 .num_wins = 8,
587 .num_remappable_wins = 2, 665 .num_remappable_wins = 2,
588 .win_cfg_offset = orion_mbus_win_offset, 666 .win_cfg_offset = orion_mbus_win_offset,
667 .save_cpu_target = mvebu_mbus_default_save_cpu_target,
589 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, 668 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
590 .show_cpu_target = mvebu_sdram_debug_show_orion, 669 .show_cpu_target = mvebu_sdram_debug_show_orion,
591}; 670};
@@ -594,6 +673,7 @@ static const struct mvebu_mbus_soc_data mv78xx0_mbus_data = {
594 .num_wins = 14, 673 .num_wins = 14,
595 .num_remappable_wins = 8, 674 .num_remappable_wins = 8,
596 .win_cfg_offset = mv78xx0_mbus_win_offset, 675 .win_cfg_offset = mv78xx0_mbus_win_offset,
676 .save_cpu_target = mvebu_mbus_default_save_cpu_target,
597 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, 677 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
598 .show_cpu_target = mvebu_sdram_debug_show_orion, 678 .show_cpu_target = mvebu_sdram_debug_show_orion,
599}; 679};
@@ -698,11 +778,73 @@ static __init int mvebu_mbus_debugfs_init(void)
698} 778}
699fs_initcall(mvebu_mbus_debugfs_init); 779fs_initcall(mvebu_mbus_debugfs_init);
700 780
781static int mvebu_mbus_suspend(void)
782{
783 struct mvebu_mbus_state *s = &mbus_state;
784 int win;
785
786 if (!s->mbusbridge_base)
787 return -ENODEV;
788
789 for (win = 0; win < s->soc->num_wins; win++) {
790 void __iomem *addr = s->mbuswins_base +
791 s->soc->win_cfg_offset(win);
792
793 s->wins[win].base = readl(addr + WIN_BASE_OFF);
794 s->wins[win].ctrl = readl(addr + WIN_CTRL_OFF);
795
796 if (win >= s->soc->num_remappable_wins)
797 continue;
798
799 s->wins[win].remap_lo = readl(addr + WIN_REMAP_LO_OFF);
800 s->wins[win].remap_hi = readl(addr + WIN_REMAP_HI_OFF);
801 }
802
803 s->mbus_bridge_ctrl = readl(s->mbusbridge_base +
804 MBUS_BRIDGE_CTRL_OFF);
805 s->mbus_bridge_base = readl(s->mbusbridge_base +
806 MBUS_BRIDGE_BASE_OFF);
807
808 return 0;
809}
810
811static void mvebu_mbus_resume(void)
812{
813 struct mvebu_mbus_state *s = &mbus_state;
814 int win;
815
816 writel(s->mbus_bridge_ctrl,
817 s->mbusbridge_base + MBUS_BRIDGE_CTRL_OFF);
818 writel(s->mbus_bridge_base,
819 s->mbusbridge_base + MBUS_BRIDGE_BASE_OFF);
820
821 for (win = 0; win < s->soc->num_wins; win++) {
822 void __iomem *addr = s->mbuswins_base +
823 s->soc->win_cfg_offset(win);
824
825 writel(s->wins[win].base, addr + WIN_BASE_OFF);
826 writel(s->wins[win].ctrl, addr + WIN_CTRL_OFF);
827
828 if (win >= s->soc->num_remappable_wins)
829 continue;
830
831 writel(s->wins[win].remap_lo, addr + WIN_REMAP_LO_OFF);
832 writel(s->wins[win].remap_hi, addr + WIN_REMAP_HI_OFF);
833 }
834}
835
836struct syscore_ops mvebu_mbus_syscore_ops = {
837 .suspend = mvebu_mbus_suspend,
838 .resume = mvebu_mbus_resume,
839};
840
701static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus, 841static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
702 phys_addr_t mbuswins_phys_base, 842 phys_addr_t mbuswins_phys_base,
703 size_t mbuswins_size, 843 size_t mbuswins_size,
704 phys_addr_t sdramwins_phys_base, 844 phys_addr_t sdramwins_phys_base,
705 size_t sdramwins_size) 845 size_t sdramwins_size,
846 phys_addr_t mbusbridge_phys_base,
847 size_t mbusbridge_size)
706{ 848{
707 int win; 849 int win;
708 850
@@ -716,11 +858,26 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
716 return -ENOMEM; 858 return -ENOMEM;
717 } 859 }
718 860
861 mbus->sdramwins_phys_base = sdramwins_phys_base;
862
863 if (mbusbridge_phys_base) {
864 mbus->mbusbridge_base = ioremap(mbusbridge_phys_base,
865 mbusbridge_size);
866 if (!mbus->mbusbridge_base) {
867 iounmap(mbus->sdramwins_base);
868 iounmap(mbus->mbuswins_base);
869 return -ENOMEM;
870 }
871 } else
872 mbus->mbusbridge_base = NULL;
873
719 for (win = 0; win < mbus->soc->num_wins; win++) 874 for (win = 0; win < mbus->soc->num_wins; win++)
720 mvebu_mbus_disable_window(mbus, win); 875 mvebu_mbus_disable_window(mbus, win);
721 876
722 mbus->soc->setup_cpu_target(mbus); 877 mbus->soc->setup_cpu_target(mbus);
723 878
879 register_syscore_ops(&mvebu_mbus_syscore_ops);
880
724 return 0; 881 return 0;
725} 882}
726 883
@@ -746,7 +903,7 @@ int __init mvebu_mbus_init(const char *soc, phys_addr_t mbuswins_phys_base,
746 mbuswins_phys_base, 903 mbuswins_phys_base,
747 mbuswins_size, 904 mbuswins_size,
748 sdramwins_phys_base, 905 sdramwins_phys_base,
749 sdramwins_size); 906 sdramwins_size, 0, 0);
750} 907}
751 908
752#ifdef CONFIG_OF 909#ifdef CONFIG_OF
@@ -887,7 +1044,7 @@ static void __init mvebu_mbus_get_pcie_resources(struct device_node *np,
887 1044
888int __init mvebu_mbus_dt_init(bool is_coherent) 1045int __init mvebu_mbus_dt_init(bool is_coherent)
889{ 1046{
890 struct resource mbuswins_res, sdramwins_res; 1047 struct resource mbuswins_res, sdramwins_res, mbusbridge_res;
891 struct device_node *np, *controller; 1048 struct device_node *np, *controller;
892 const struct of_device_id *of_id; 1049 const struct of_device_id *of_id;
893 const __be32 *prop; 1050 const __be32 *prop;
@@ -923,6 +1080,19 @@ int __init mvebu_mbus_dt_init(bool is_coherent)
923 return -EINVAL; 1080 return -EINVAL;
924 } 1081 }
925 1082
1083 /*
1084 * Set the resource to 0 so that it can be left unmapped by
1085 * mvebu_mbus_common_init() if the DT doesn't carry the
1086 * necessary information. This is needed to preserve backward
1087 * compatibility.
1088 */
1089 memset(&mbusbridge_res, 0, sizeof(mbusbridge_res));
1090
1091 if (mbus_state.soc->has_mbus_bridge) {
1092 if (of_address_to_resource(controller, 2, &mbusbridge_res))
1093 pr_warn(FW_WARN "deprecated mbus-mvebu Device Tree, suspend/resume will not work\n");
1094 }
1095
926 mbus_state.hw_io_coherency = is_coherent; 1096 mbus_state.hw_io_coherency = is_coherent;
927 1097
928 /* Get optional pcie-{mem,io}-aperture properties */ 1098 /* Get optional pcie-{mem,io}-aperture properties */
@@ -933,7 +1103,9 @@ int __init mvebu_mbus_dt_init(bool is_coherent)
933 mbuswins_res.start, 1103 mbuswins_res.start,
934 resource_size(&mbuswins_res), 1104 resource_size(&mbuswins_res),
935 sdramwins_res.start, 1105 sdramwins_res.start,
936 resource_size(&sdramwins_res)); 1106 resource_size(&sdramwins_res),
1107 mbusbridge_res.start,
1108 resource_size(&mbusbridge_res));
937 if (ret) 1109 if (ret)
938 return ret; 1110 return ret;
939 1111