blob: 0ace152b98e0b5e6729796ad18625cc3804ac29a [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Marek Vasutae723e12012-08-26 15:19:06 +00002/*
3 * Generic bounce buffer implementation
4 *
5 * Copyright (C) 2012 Marek Vasut <marex@denx.de>
Marek Vasutae723e12012-08-26 15:19:06 +00006 */
7
8#include <common.h>
Simon Glass63334482019-11-14 12:57:39 -07009#include <cpu_func.h>
Marek Vasutae723e12012-08-26 15:19:06 +000010#include <malloc.h>
11#include <errno.h>
12#include <bouncebuf.h>
13
Stephen Warren4a8629e2012-11-06 11:27:29 +000014static int addr_aligned(struct bounce_buffer *state)
Marek Vasutae723e12012-08-26 15:19:06 +000015{
16 const ulong align_mask = ARCH_DMA_MINALIGN - 1;
17
18 /* Check if start is aligned */
Stephen Warren4a8629e2012-11-06 11:27:29 +000019 if ((ulong)state->user_buffer & align_mask) {
20 debug("Unaligned buffer address %p\n", state->user_buffer);
Marek Vasutae723e12012-08-26 15:19:06 +000021 return 0;
22 }
23
Stephen Warren4a8629e2012-11-06 11:27:29 +000024 /* Check if length is aligned */
25 if (state->len != state->len_aligned) {
Vasili Galka38c3fff2014-08-26 13:45:48 +030026 debug("Unaligned buffer length %zu\n", state->len);
Marek Vasutae723e12012-08-26 15:19:06 +000027 return 0;
28 }
29
30 /* Aligned */
31 return 1;
32}
33
Marek Vasut393de782020-04-04 12:45:02 +020034int bounce_buffer_start_extalign(struct bounce_buffer *state, void *data,
35 size_t len, unsigned int flags,
36 size_t alignment,
37 int (*addr_is_aligned)(struct bounce_buffer *state))
Marek Vasutae723e12012-08-26 15:19:06 +000038{
Stephen Warren4a8629e2012-11-06 11:27:29 +000039 state->user_buffer = data;
40 state->bounce_buffer = data;
41 state->len = len;
Marek Vasut393de782020-04-04 12:45:02 +020042 state->len_aligned = roundup(len, alignment);
Stephen Warren4a8629e2012-11-06 11:27:29 +000043 state->flags = flags;
Marek Vasutae723e12012-08-26 15:19:06 +000044
Marek Vasut393de782020-04-04 12:45:02 +020045 if (!addr_is_aligned(state)) {
46 state->bounce_buffer = memalign(alignment,
Stephen Warren4a8629e2012-11-06 11:27:29 +000047 state->len_aligned);
48 if (!state->bounce_buffer)
49 return -ENOMEM;
Marek Vasutae723e12012-08-26 15:19:06 +000050
Stephen Warren4a8629e2012-11-06 11:27:29 +000051 if (state->flags & GEN_BB_READ)
52 memcpy(state->bounce_buffer, state->user_buffer,
53 state->len);
54 }
Marek Vasutae723e12012-08-26 15:19:06 +000055
Stephen Warren4a8629e2012-11-06 11:27:29 +000056 /*
57 * Flush data to RAM so DMA reads can pick it up,
58 * and any CPU writebacks don't race with DMA writes
59 */
60 flush_dcache_range((unsigned long)state->bounce_buffer,
61 (unsigned long)(state->bounce_buffer) +
62 state->len_aligned);
Marek Vasutae723e12012-08-26 15:19:06 +000063
64 return 0;
65}
66
Marek Vasut393de782020-04-04 12:45:02 +020067int bounce_buffer_start(struct bounce_buffer *state, void *data,
68 size_t len, unsigned int flags)
69{
70 return bounce_buffer_start_extalign(state, data, len, flags,
71 ARCH_DMA_MINALIGN,
72 addr_aligned);
73}
74
Stephen Warren4a8629e2012-11-06 11:27:29 +000075int bounce_buffer_stop(struct bounce_buffer *state)
Marek Vasutae723e12012-08-26 15:19:06 +000076{
Stephen Warren4a8629e2012-11-06 11:27:29 +000077 if (state->flags & GEN_BB_WRITE) {
78 /* Invalidate cache so that CPU can see any newly DMA'd data */
79 invalidate_dcache_range((unsigned long)state->bounce_buffer,
80 (unsigned long)(state->bounce_buffer) +
81 state->len_aligned);
82 }
Marek Vasutae723e12012-08-26 15:19:06 +000083
Stephen Warren4a8629e2012-11-06 11:27:29 +000084 if (state->bounce_buffer == state->user_buffer)
Marek Vasutae723e12012-08-26 15:19:06 +000085 return 0;
86
Stephen Warren4a8629e2012-11-06 11:27:29 +000087 if (state->flags & GEN_BB_WRITE)
88 memcpy(state->user_buffer, state->bounce_buffer, state->len);
Marek Vasutae723e12012-08-26 15:19:06 +000089
Stephen Warren4a8629e2012-11-06 11:27:29 +000090 free(state->bounce_buffer);
Marek Vasutae723e12012-08-26 15:19:06 +000091
92 return 0;
93}