blob: 6bb8b53902b74c49d380655720619263c96698b8 [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>
Simon Glass274e0b02020-05-10 11:39:56 -060013#include <asm/cache.h>
Marek Vasutae723e12012-08-26 15:19:06 +000014
Stephen Warren4a8629e2012-11-06 11:27:29 +000015static int addr_aligned(struct bounce_buffer *state)
Marek Vasutae723e12012-08-26 15:19:06 +000016{
17 const ulong align_mask = ARCH_DMA_MINALIGN - 1;
18
19 /* Check if start is aligned */
Stephen Warren4a8629e2012-11-06 11:27:29 +000020 if ((ulong)state->user_buffer & align_mask) {
21 debug("Unaligned buffer address %p\n", state->user_buffer);
Marek Vasutae723e12012-08-26 15:19:06 +000022 return 0;
23 }
24
Stephen Warren4a8629e2012-11-06 11:27:29 +000025 /* Check if length is aligned */
26 if (state->len != state->len_aligned) {
Vasili Galka38c3fff2014-08-26 13:45:48 +030027 debug("Unaligned buffer length %zu\n", state->len);
Marek Vasutae723e12012-08-26 15:19:06 +000028 return 0;
29 }
30
31 /* Aligned */
32 return 1;
33}
34
Marek Vasut393de782020-04-04 12:45:02 +020035int bounce_buffer_start_extalign(struct bounce_buffer *state, void *data,
36 size_t len, unsigned int flags,
37 size_t alignment,
38 int (*addr_is_aligned)(struct bounce_buffer *state))
Marek Vasutae723e12012-08-26 15:19:06 +000039{
Stephen Warren4a8629e2012-11-06 11:27:29 +000040 state->user_buffer = data;
41 state->bounce_buffer = data;
42 state->len = len;
Marek Vasut393de782020-04-04 12:45:02 +020043 state->len_aligned = roundup(len, alignment);
Stephen Warren4a8629e2012-11-06 11:27:29 +000044 state->flags = flags;
Marek Vasutae723e12012-08-26 15:19:06 +000045
Marek Vasut393de782020-04-04 12:45:02 +020046 if (!addr_is_aligned(state)) {
47 state->bounce_buffer = memalign(alignment,
Stephen Warren4a8629e2012-11-06 11:27:29 +000048 state->len_aligned);
49 if (!state->bounce_buffer)
50 return -ENOMEM;
Marek Vasutae723e12012-08-26 15:19:06 +000051
Stephen Warren4a8629e2012-11-06 11:27:29 +000052 if (state->flags & GEN_BB_READ)
53 memcpy(state->bounce_buffer, state->user_buffer,
54 state->len);
55 }
Marek Vasutae723e12012-08-26 15:19:06 +000056
Stephen Warren4a8629e2012-11-06 11:27:29 +000057 /*
58 * Flush data to RAM so DMA reads can pick it up,
59 * and any CPU writebacks don't race with DMA writes
60 */
61 flush_dcache_range((unsigned long)state->bounce_buffer,
62 (unsigned long)(state->bounce_buffer) +
63 state->len_aligned);
Marek Vasutae723e12012-08-26 15:19:06 +000064
65 return 0;
66}
67
Marek Vasut393de782020-04-04 12:45:02 +020068int bounce_buffer_start(struct bounce_buffer *state, void *data,
69 size_t len, unsigned int flags)
70{
71 return bounce_buffer_start_extalign(state, data, len, flags,
72 ARCH_DMA_MINALIGN,
73 addr_aligned);
74}
75
Stephen Warren4a8629e2012-11-06 11:27:29 +000076int bounce_buffer_stop(struct bounce_buffer *state)
Marek Vasutae723e12012-08-26 15:19:06 +000077{
Stephen Warren4a8629e2012-11-06 11:27:29 +000078 if (state->flags & GEN_BB_WRITE) {
79 /* Invalidate cache so that CPU can see any newly DMA'd data */
80 invalidate_dcache_range((unsigned long)state->bounce_buffer,
81 (unsigned long)(state->bounce_buffer) +
82 state->len_aligned);
83 }
Marek Vasutae723e12012-08-26 15:19:06 +000084
Stephen Warren4a8629e2012-11-06 11:27:29 +000085 if (state->bounce_buffer == state->user_buffer)
Marek Vasutae723e12012-08-26 15:19:06 +000086 return 0;
87
Stephen Warren4a8629e2012-11-06 11:27:29 +000088 if (state->flags & GEN_BB_WRITE)
89 memcpy(state->user_buffer, state->bounce_buffer, state->len);
Marek Vasutae723e12012-08-26 15:19:06 +000090
Stephen Warren4a8629e2012-11-06 11:27:29 +000091 free(state->bounce_buffer);
Marek Vasutae723e12012-08-26 15:19:06 +000092
93 return 0;
94}