1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 * Generic bounce buffer implementation
6 #include <arch/cache.h>
10 #include <commonlib/stdlib.h>
12 static int addr_aligned(struct bounce_buffer
*state
)
14 const uint32_t align_mask
= ARCH_DMA_MINALIGN
- 1;
16 // Check if start is aligned
17 if ((uintptr_t)state
->user_buffer
& align_mask
) {
18 sdhc_debug("Unaligned buffer address %p\n", state
->user_buffer
);
22 // Check if length is aligned
23 if (state
->len
!= state
->len_aligned
) {
24 sdhc_debug("Unaligned buffer length %zd\n", state
->len
);
32 int bounce_buffer_start(struct bounce_buffer
*state
, void *data
,
33 size_t len
, unsigned int flags
)
35 state
->user_buffer
= data
;
36 state
->bounce_buffer
= data
;
38 state
->len_aligned
= ROUND(len
, ARCH_DMA_MINALIGN
);
41 if (!addr_aligned(state
)) {
42 state
->bounce_buffer
= memalign(ARCH_DMA_MINALIGN
,
44 if (!state
->bounce_buffer
)
47 if (state
->flags
& GEN_BB_READ
)
48 memcpy(state
->bounce_buffer
, state
->user_buffer
,
53 * Flush data to RAM so DMA reads can pick it up,
54 * and any CPU writebacks don't race with DMA writes
56 dcache_clean_invalidate_by_mva(state
->bounce_buffer
,
61 int bounce_buffer_stop(struct bounce_buffer
*state
)
63 if (state
->flags
& GEN_BB_WRITE
) {
64 // Invalidate cache so that CPU can see any newly DMA'd data
65 dcache_invalidate_by_mva(state
->bounce_buffer
,
69 if (state
->bounce_buffer
== state
->user_buffer
)
72 if (state
->flags
& GEN_BB_WRITE
)
73 memcpy(state
->user_buffer
, state
->bounce_buffer
, state
->len
);
75 free(state
->bounce_buffer
);