aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bus
diff options
context:
space:
mode:
authorThomas Petazzoni <thomas.petazzoni@free-electrons.com>2015-05-28 05:40:54 -0400
committerGregory CLEMENT <gregory.clement@free-electrons.com>2015-05-28 06:21:08 -0400
commitbfa1ce5f38938cc9e6c7f2d1011f88eba2b9e2b2 (patch)
treeb4eb98e065a7342c9d02548df3e7ea22a09529b7 /drivers/bus
parent885dbd154b2f2ee305cec6fd0a162e1a77ae2b06 (diff)
bus: mvebu-mbus: add mv_mbus_dram_info_nooverlap()
This commit introduces a variant of the mv_mbus_dram_info() function called mv_mbus_dram_info_nooverlap(). Both functions are used by Marvell drivers supporting devices doing DMA, and provide them a description the DRAM ranges that they need to configure their DRAM windows. The ranges provided by the mv_mbus_dram_info() function may overlap with the I/O windows if there is a lot (>= 4 GB) of RAM installed. This is not a problem for most of the DMA masters, except for the upcoming new CESA crypto driver because it does DMA to the SRAM, which is mapped through an I/O window. For this unit, we need to have DRAM ranges that do not overlap with the I/O windows. A first implementation done in commit 1737cac69369 ("bus: mvebu-mbus: make sure SDRAM CS for DMA don't overlap the MBus bridge window"), changed the information returned by mv_mbus_dram_info() to match this requirement. However, it broke the requirement of the other DMA masters than the DRAM ranges should have power of two sizes. To solve this situation, this commit introduces a new mv_mbus_dram_info_nooverlap() function, which returns the same information as mv_mbus_dram_info(), but guaranteed to not overlap with the I/O windows. In the end, it gives us two variants of the mv_mbus_dram_info*() functions: - The normal one, mv_mbus_dram_info(), which has been around for many years. This function returns the raw DRAM ranges, which are guaranteed to use power of two sizes, but will overlap with I/O windows. This function will therefore be used by all DMA masters (SATA, XOR, Ethernet, etc.) except the CESA crypto driver. - The new 'nooverlap' variant, mv_mbus_dram_info_nooverlap(). This function returns DRAM ranges after they have been "tweaked" to make sure they don't overlap with I/O windows. By doing this tweaking, we remove the power of two size guarantee. This variant will be used by the new CESA crypto driver. Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Diffstat (limited to 'drivers/bus')
-rw-r--r--drivers/bus/mvebu-mbus.c117
1 files changed, 117 insertions, 0 deletions
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
index 6f047dcb94c2..c43c3d2baf73 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/memblock.h>
60#include <linux/syscore_ops.h> 61#include <linux/syscore_ops.h>
61 62
62/* 63/*
@@ -152,13 +153,39 @@ struct mvebu_mbus_state {
152 153
153static struct mvebu_mbus_state mbus_state; 154static struct mvebu_mbus_state mbus_state;
154 155
156/*
157 * We provide two variants of the mv_mbus_dram_info() function:
158 *
159 * - The normal one, where the described DRAM ranges may overlap with
160 * the I/O windows, but for which the DRAM ranges are guaranteed to
161 * have a power of two size. Such ranges are suitable for the DMA
162 * masters that only DMA between the RAM and the device, which is
163 * actually all devices except the crypto engines.
164 *
165 * - The 'nooverlap' one, where the described DRAM ranges are
166 * guaranteed to not overlap with the I/O windows, but for which the
167 * DRAM ranges will not have power of two sizes. They will only be
168 * aligned on a 64 KB boundary, and have a size multiple of 64
169 * KB. Such ranges are suitable for the DMA masters that DMA between
170 * the crypto SRAM (which is mapped through an I/O window) and a
171 * device. This is the case for the crypto engines.
172 */
173
155static struct mbus_dram_target_info mvebu_mbus_dram_info; 174static struct mbus_dram_target_info mvebu_mbus_dram_info;
175static struct mbus_dram_target_info mvebu_mbus_dram_info_nooverlap;
176
156const struct mbus_dram_target_info *mv_mbus_dram_info(void) 177const struct mbus_dram_target_info *mv_mbus_dram_info(void)
157{ 178{
158 return &mvebu_mbus_dram_info; 179 return &mvebu_mbus_dram_info;
159} 180}
160EXPORT_SYMBOL_GPL(mv_mbus_dram_info); 181EXPORT_SYMBOL_GPL(mv_mbus_dram_info);
161 182
183const struct mbus_dram_target_info *mv_mbus_dram_info_nooverlap(void)
184{
185 return &mvebu_mbus_dram_info_nooverlap;
186}
187EXPORT_SYMBOL_GPL(mv_mbus_dram_info_nooverlap);
188
162/* Checks whether the given window has remap capability */ 189/* Checks whether the given window has remap capability */
163static bool mvebu_mbus_window_is_remappable(struct mvebu_mbus_state *mbus, 190static bool mvebu_mbus_window_is_remappable(struct mvebu_mbus_state *mbus,
164 const int win) 191 const int win)
@@ -576,6 +603,95 @@ static unsigned int armada_xp_mbus_win_remap_offset(int win)
576 return MVEBU_MBUS_NO_REMAP; 603 return MVEBU_MBUS_NO_REMAP;
577} 604}
578 605
606/*
607 * Use the memblock information to find the MBus bridge hole in the
608 * physical address space.
609 */
610static void __init
611mvebu_mbus_find_bridge_hole(uint64_t *start, uint64_t *end)
612{
613 struct memblock_region *r;
614 uint64_t s = 0;
615
616 for_each_memblock(memory, r) {
617 /*
618 * This part of the memory is above 4 GB, so we don't
619 * care for the MBus bridge hole.
620 */
621 if (r->base >= 0x100000000ULL)
622 continue;
623
624 /*
625 * The MBus bridge hole is at the end of the RAM under
626 * the 4 GB limit.
627 */
628 if (r->base + r->size > s)
629 s = r->base + r->size;
630 }
631
632 *start = s;
633 *end = 0x100000000ULL;
634}
635
636/*
637 * This function fills in the mvebu_mbus_dram_info_nooverlap data
638 * structure, by looking at the mvebu_mbus_dram_info data, and
639 * removing the parts of it that overlap with I/O windows.
640 */
641static void __init
642mvebu_mbus_setup_cpu_target_nooverlap(struct mvebu_mbus_state *mbus)
643{
644 uint64_t mbus_bridge_base, mbus_bridge_end;
645 int cs_nooverlap = 0;
646 int i;
647
648 mvebu_mbus_find_bridge_hole(&mbus_bridge_base, &mbus_bridge_end);
649
650 for (i = 0; i < mvebu_mbus_dram_info.num_cs; i++) {
651 struct mbus_dram_window *w;
652 u64 base, size, end;
653
654 w = &mvebu_mbus_dram_info.cs[i];
655 base = w->base;
656 size = w->size;
657 end = base + size;
658
659 /*
660 * The CS is fully enclosed inside the MBus bridge
661 * area, so ignore it.
662 */
663 if (base >= mbus_bridge_base && end <= mbus_bridge_end)
664 continue;
665
666 /*
667 * Beginning of CS overlaps with end of MBus, raise CS
668 * base address, and shrink its size.
669 */
670 if (base >= mbus_bridge_base && end > mbus_bridge_end) {
671 size -= mbus_bridge_end - base;
672 base = mbus_bridge_end;
673 }
674
675 /*
676 * End of CS overlaps with beginning of MBus, shrink
677 * CS size.
678 */
679 if (base < mbus_bridge_base && end > mbus_bridge_base)
680 size -= end - mbus_bridge_base;
681
682 w = &mvebu_mbus_dram_info_nooverlap.cs[cs_nooverlap++];
683 w->cs_index = i;
684 w->mbus_attr = 0xf & ~(1 << i);
685 if (mbus->hw_io_coherency)
686 w->mbus_attr |= ATTR_HW_COHERENCY;
687 w->base = base;
688 w->size = size;
689 }
690
691 mvebu_mbus_dram_info_nooverlap.mbus_dram_target_id = TARGET_DDR;
692 mvebu_mbus_dram_info_nooverlap.num_cs = cs_nooverlap;
693}
694
579static void __init 695static void __init
580mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus) 696mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus)
581{ 697{
@@ -964,6 +1080,7 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
964 mvebu_mbus_disable_window(mbus, win); 1080 mvebu_mbus_disable_window(mbus, win);
965 1081
966 mbus->soc->setup_cpu_target(mbus); 1082 mbus->soc->setup_cpu_target(mbus);
1083 mvebu_mbus_setup_cpu_target_nooverlap(mbus);
967 1084
968 if (is_coherent) 1085 if (is_coherent)
969 writel(UNIT_SYNC_BARRIER_ALL, 1086 writel(UNIT_SYNC_BARRIER_ALL,