-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdma_bram_conf.c
More file actions
76 lines (68 loc) · 3.24 KB
/
dma_bram_conf.c
File metadata and controls
76 lines (68 loc) · 3.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include "dma_bram_conf.h"
#include "dma_register.h"
#include "tests/mockable_functions.h"
#include <linux/io.h>
#include <linux/slab.h>
#include <kunit/static_stub.h>
int fill_descriptors_table(unsigned int num_of_descriptors, volatile void __iomem *mapped_bram, uint32_t bram_phy_ptr, uint32_t target_phy_ptr, uint buffer_size)
{
const uint transfer_len
= (buffer_size > 0) ? (buffer_size + 1)*sizeof(uint32_t) : 0;
struct descriptor_table *descriptors = kzalloc(num_of_descriptors * sizeof(struct descriptor_table), GFP_KERNEL);
if (descriptors == NULL) {
pr_err("DMA: Could not allocate memory for descriptor table struct\n");
return -ENOMEM;
}
// https://docs.amd.com/r/en-US/pg021_axi_dma/Scatter-Gather-Descriptor
for(int i=0; i<num_of_descriptors; i++){
// Linkied list -> pointer to next descriptor shifted to bram address seen from the DMA
// SC_DESCRIPTOR_SIZE have to be aligned to 16 words, but adddress is given in bytes
// so SC_DESCRIPTOR_SIZE given in 32b words have to be multiplied by 4
descriptors[i].next_descriptor_lsb =
bram_phy_ptr + (i+1)*(SC_DESCRIPTOR_SIZE<<2) + SC_NEXTDESC_LSB;
// Upper 32b of pointer to next descriptor
descriptors[i].next_descriptor_msb = 0;
// Pointer to RAM space buffer
// Transfer length is given in 32b words but address is in bytes -> multiply transfer len by 4
descriptors[i].buffer_addr_lsb =
target_phy_ptr + i*(buffer_size<<2);
// Upper 32b of pointer to RAM space buffer
descriptors[i].burrer_addr_msb = 0;
// transaction control register:
descriptors[i].control =
transfer_len | // DMA transfer length in bytes
(1 << 26 ) | // End Of Frame EOF bit
(1 << 27 ); // Start Of Frame SOF bit
// Zero status register (just for sure)
descriptors[i].status = 0;
}
descriptors[num_of_descriptors-1].next_descriptor_lsb =
bram_phy_ptr + 0*(SC_DESCRIPTOR_SIZE<<2) + SC_NEXTDESC_LSB;
uint32_t* bram_words = (uint32_t*)descriptors;
for(int i=0; i<num_of_descriptors * sizeof(struct descriptor_table) / sizeof(uint32_t); i++){
testable_iowrite32(bram_words[i], mapped_bram + i*sizeof(uint32_t));
}
kfree(descriptors);
return 0;
}
uint32_t get_descriptor_status(const volatile void __iomem *mapped_bram, uint descriptor_id)
{
return testable_ioread32(mapped_bram + descriptor_id*SC_DESCRIPTOR_SIZE*sizeof(uint32_t) + SC_STATUS*sizeof(uint32_t));
}
struct transfer_status decode_transfer_status(uint32_t status)
{
struct transfer_status decoded = {
.completed = (status & (1u<<31)) != 0,
.dma_decode_error = (status & (1u<<30)) != 0,
.dma_slave_error = (status & (1u<<29)) != 0,
.dma_internal_error = (status & (1u<<28)) != 0,
.transfer_size = status & 0x3FFFFFF
};
return decoded;
}
void clear_descr_status(volatile void __iomem *mapped_bram, uint descriptor_id)
{
testable_iowrite32(0, mapped_bram + descriptor_id*SC_DESCRIPTOR_SIZE*sizeof(uint32_t) + SC_STATUS*sizeof(uint32_t));
// moved to the end (nonstandard approach) to keep original bahaviour
KUNIT_STATIC_STUB_REDIRECT(clear_descr_status, mapped_bram, descriptor_id);
}