diff options
author | Thomas Petazzoni <thomas.petazzoni@free-electrons.com> | 2014-11-21 11:00:04 -0500 |
---|---|---|
committer | Jason Cooper <jason@lakedaemon.net> | 2014-11-30 11:40:11 -0500 |
commit | 4749c02b8da6d8dbc29218652985bda844017e95 (patch) | |
tree | 992fd5ce8e264a02637ec8be69a828b16807c75f /drivers/bus/mvebu-mbus.c | |
parent | a0e89c02da974838053a3604025e43600dc6ac45 (diff) |
bus: mvebu-mbus: provide a mechanism to save SDRAM window configuration
On Marvell EBU platforms, when doing suspend/resume, the SDRAM window
configuration must be saved on suspend, and restored on
resume. However, it needs to be restored on resume *before*
re-entering the kernel, because the SDRAM window configuration defines
the layout of the memory. For this reason, it cannot simply be done in
the ->suspend() and ->resume() hooks of the mvebu-mbus driver.
Instead, it needs to be restored by the bootloader "boot info"
mechanism used when resuming. This mechanism allows the kernel to
define a list of (address, value) pairs when suspending, that the
bootloader will restore on resume before jumping back into the kernel.
This commit therefore adds a new function to the mvebu-mbus driver,
called mvebu_mbus_save_cpu_target(), which will be called by the
platform code to make the mvebu-mbus driver save the SDRAM window
configuration in a way that can be understood by the bootloader "boot
info" mechanism.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Reviewed-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Link: https://lkml.kernel.org/r/1416585613-2113-8-git-send-email-thomas.petazzoni@free-electrons.com
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
Diffstat (limited to 'drivers/bus/mvebu-mbus.c')
-rw-r--r-- | drivers/bus/mvebu-mbus.c | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c index e8c159399c82..eb7682dc123b 100644 --- a/drivers/bus/mvebu-mbus.c +++ b/drivers/bus/mvebu-mbus.c | |||
@@ -110,6 +110,8 @@ struct mvebu_mbus_soc_data { | |||
110 | bool has_mbus_bridge; | 110 | bool has_mbus_bridge; |
111 | unsigned int (*win_cfg_offset)(const int win); | 111 | unsigned int (*win_cfg_offset)(const int win); |
112 | 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); | ||
113 | int (*show_cpu_target)(struct mvebu_mbus_state *s, | 115 | int (*show_cpu_target)(struct mvebu_mbus_state *s, |
114 | struct seq_file *seq, void *v); | 116 | struct seq_file *seq, void *v); |
115 | }; | 117 | }; |
@@ -128,6 +130,7 @@ struct mvebu_mbus_state { | |||
128 | void __iomem *mbuswins_base; | 130 | void __iomem *mbuswins_base; |
129 | void __iomem *sdramwins_base; | 131 | void __iomem *sdramwins_base; |
130 | void __iomem *mbusbridge_base; | 132 | void __iomem *mbusbridge_base; |
133 | phys_addr_t sdramwins_phys_base; | ||
131 | struct dentry *debugfs_root; | 134 | struct dentry *debugfs_root; |
132 | struct dentry *debugfs_sdram; | 135 | struct dentry *debugfs_sdram; |
133 | struct dentry *debugfs_devs; | 136 | struct dentry *debugfs_devs; |
@@ -541,6 +544,28 @@ mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus) | |||
541 | mvebu_mbus_dram_info.num_cs = cs; | 544 | mvebu_mbus_dram_info.num_cs = cs; |
542 | } | 545 | } |
543 | 546 | ||
547 | static int | ||
548 | mvebu_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 | |||
544 | static void __init | 569 | static void __init |
545 | mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus) | 570 | mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus) |
546 | { | 571 | { |
@@ -571,11 +596,35 @@ mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus) | |||
571 | mvebu_mbus_dram_info.num_cs = cs; | 596 | mvebu_mbus_dram_info.num_cs = cs; |
572 | } | 597 | } |
573 | 598 | ||
599 | static int | ||
600 | mvebu_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 | |||
617 | int mvebu_mbus_save_cpu_target(u32 *store_addr) | ||
618 | { | ||
619 | return mbus_state.soc->save_cpu_target(&mbus_state, store_addr); | ||
620 | } | ||
621 | |||
574 | static const struct mvebu_mbus_soc_data armada_370_xp_mbus_data = { | 622 | static const struct mvebu_mbus_soc_data armada_370_xp_mbus_data = { |
575 | .num_wins = 20, | 623 | .num_wins = 20, |
576 | .num_remappable_wins = 8, | 624 | .num_remappable_wins = 8, |
577 | .has_mbus_bridge = true, | 625 | .has_mbus_bridge = true, |
578 | .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, | ||
579 | .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, | 628 | .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, |
580 | .show_cpu_target = mvebu_sdram_debug_show_orion, | 629 | .show_cpu_target = mvebu_sdram_debug_show_orion, |
581 | }; | 630 | }; |
@@ -584,6 +633,7 @@ static const struct mvebu_mbus_soc_data kirkwood_mbus_data = { | |||
584 | .num_wins = 8, | 633 | .num_wins = 8, |
585 | .num_remappable_wins = 4, | 634 | .num_remappable_wins = 4, |
586 | .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, | ||
587 | .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, | 637 | .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, |
588 | .show_cpu_target = mvebu_sdram_debug_show_orion, | 638 | .show_cpu_target = mvebu_sdram_debug_show_orion, |
589 | }; | 639 | }; |
@@ -592,6 +642,7 @@ static const struct mvebu_mbus_soc_data dove_mbus_data = { | |||
592 | .num_wins = 8, | 642 | .num_wins = 8, |
593 | .num_remappable_wins = 4, | 643 | .num_remappable_wins = 4, |
594 | .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, | ||
595 | .setup_cpu_target = mvebu_mbus_dove_setup_cpu_target, | 646 | .setup_cpu_target = mvebu_mbus_dove_setup_cpu_target, |
596 | .show_cpu_target = mvebu_sdram_debug_show_dove, | 647 | .show_cpu_target = mvebu_sdram_debug_show_dove, |
597 | }; | 648 | }; |
@@ -604,6 +655,7 @@ static const struct mvebu_mbus_soc_data orion5x_4win_mbus_data = { | |||
604 | .num_wins = 8, | 655 | .num_wins = 8, |
605 | .num_remappable_wins = 4, | 656 | .num_remappable_wins = 4, |
606 | .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, | ||
607 | .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, | 659 | .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, |
608 | .show_cpu_target = mvebu_sdram_debug_show_orion, | 660 | .show_cpu_target = mvebu_sdram_debug_show_orion, |
609 | }; | 661 | }; |
@@ -612,6 +664,7 @@ static const struct mvebu_mbus_soc_data orion5x_2win_mbus_data = { | |||
612 | .num_wins = 8, | 664 | .num_wins = 8, |
613 | .num_remappable_wins = 2, | 665 | .num_remappable_wins = 2, |
614 | .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, | ||
615 | .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, | 668 | .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, |
616 | .show_cpu_target = mvebu_sdram_debug_show_orion, | 669 | .show_cpu_target = mvebu_sdram_debug_show_orion, |
617 | }; | 670 | }; |
@@ -620,6 +673,7 @@ static const struct mvebu_mbus_soc_data mv78xx0_mbus_data = { | |||
620 | .num_wins = 14, | 673 | .num_wins = 14, |
621 | .num_remappable_wins = 8, | 674 | .num_remappable_wins = 8, |
622 | .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, | ||
623 | .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, | 677 | .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, |
624 | .show_cpu_target = mvebu_sdram_debug_show_orion, | 678 | .show_cpu_target = mvebu_sdram_debug_show_orion, |
625 | }; | 679 | }; |
@@ -804,6 +858,8 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus, | |||
804 | return -ENOMEM; | 858 | return -ENOMEM; |
805 | } | 859 | } |
806 | 860 | ||
861 | mbus->sdramwins_phys_base = sdramwins_phys_base; | ||
862 | |||
807 | if (mbusbridge_phys_base) { | 863 | if (mbusbridge_phys_base) { |
808 | mbus->mbusbridge_base = ioremap(mbusbridge_phys_base, | 864 | mbus->mbusbridge_base = ioremap(mbusbridge_phys_base, |
809 | mbusbridge_size); | 865 | mbusbridge_size); |