forked from jbentham/rpi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rpi_dma_utils.h
202 lines (185 loc) · 7.4 KB
/
rpi_dma_utils.h
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// Raspberry Pi DMA utility definitions; see https://iosoft.blog for details
//
// Copyright (c) 2020 Jeremy P Bentham
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Location of peripheral registers in physical memory
#define PHYS_REG_BASE PI_01_REG_BASE
#define PI_01_REG_BASE 0x20000000 // Pi Zero or 1
#define PI_23_REG_BASE 0x3F000000 // Pi 2 or 3
#define PI_4_REG_BASE 0xFE000000 // Pi 4
//#define CLOCK_HZ 250000000 // Pi 2 - 4
#define CLOCK_HZ 400000000 // Pi Zero
// Location of peripheral registers in bus memory
#define BUS_REG_BASE 0x7E000000
// If non-zero, print debug information
#define DEBUG 0
// If non-zero, set PWM clock using VideoCore mailbox
#define USE_VC_CLOCK_SET 0
// Size of memory page
#define PAGE_SIZE 0x1000
// Round up to nearest page
#define PAGE_ROUNDUP(n) ((n)%PAGE_SIZE==0 ? (n) : ((n)+PAGE_SIZE)&~(PAGE_SIZE-1))
// Structure for mapped peripheral or memory
typedef struct {
int fd, // File descriptor
h, // Memory handle
size; // Memory size
void *bus, // Bus address
*virt, // Virtual address
*phys; // Physical address
} MEM_MAP;
// Get virtual 8 and 32-bit pointers to register
#define REG8(m, x) ((volatile uint8_t *) ((uint32_t)(m.virt)+(uint32_t)(x)))
#define REG32(m, x) ((volatile uint32_t *)((uint32_t)(m.virt)+(uint32_t)(x)))
// Get bus address of register
#define REG_BUS_ADDR(m, x) ((uint32_t)(m.bus) + (uint32_t)(x))
// Convert uncached memory virtual address to bus address
#define MEM_BUS_ADDR(mp, a) ((uint32_t)a-(uint32_t)mp->virt+(uint32_t)mp->bus)
// Convert bus address to physical address (for mmap)
#define BUS_PHYS_ADDR(a) ((void *)((uint32_t)(a)&~0xC0000000))
// GPIO register definitions
#define GPIO_BASE (PHYS_REG_BASE + 0x200000)
#define GPIO_MODE0 0x00
#define GPIO_SET0 0x1c
#define GPIO_CLR0 0x28
#define GPIO_LEV0 0x34
#define GPIO_GPPUD 0x94
#define GPIO_GPPUDCLK0 0x98
// GPIO I/O definitions
#define GPIO_IN 0
#define GPIO_OUT 1
#define GPIO_ALT0 4
#define GPIO_ALT1 5
#define GPIO_ALT2 6
#define GPIO_ALT3 7
#define GPIO_ALT4 3
#define GPIO_ALT5 2
#define GPIO_MODE_STRS "IN","OUT","ALT5","ALT4","ALT0","ALT1","ALT2","ALT3"
#define GPIO_NOPULL 0
#define GPIO_PULLDN 1
#define GPIO_PULLUP 2
// Videocore mailbox memory allocation flags, see:
// https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
typedef enum {
MEM_FLAG_DISCARDABLE = 1<<0, // can be resized to 0 at any time. Use for cached data
MEM_FLAG_NORMAL = 0<<2, // normal allocating alias. Don't use from ARM
MEM_FLAG_DIRECT = 1<<2, // 0xC alias uncached
MEM_FLAG_COHERENT = 2<<2, // 0x8 alias. Non-allocating in L2 but coherent
MEM_FLAG_ZERO = 1<<4, // initialise buffer to all zeros
MEM_FLAG_NO_INIT = 1<<5, // don't initialise (default is initialise to all ones)
MEM_FLAG_HINT_PERMALOCK = 1<<6, // Likely to be locked for long periods of time
MEM_FLAG_L1_NONALLOCATING=(MEM_FLAG_DIRECT | MEM_FLAG_COHERENT) // Allocating in L2
} VC_ALLOC_FLAGS;
// VC flags for unchached DMA memory
#define DMA_MEM_FLAGS (MEM_FLAG_DIRECT|MEM_FLAG_ZERO)
// Mailbox command/response structure
typedef struct {
uint32_t len, // Overall length (bytes)
req, // Zero for request, 1<<31 for response
tag, // Command number
blen, // Buffer length (bytes)
dlen; // Data length (bytes)
uint32_t uints[32-5]; // Data (108 bytes maximum)
} VC_MSG __attribute__ ((aligned (16)));
// DMA channels and data requests
#define DMA_CHAN_A 10
#define DMA_CHAN_B 11
#define DMA_PWM_DREQ 5
#define DMA_SPI_TX_DREQ 6
#define DMA_SPI_RX_DREQ 7
#define DMA_BASE (PHYS_REG_BASE + 0x007000)
// DMA register addresses offset by 0x100 * chan_num
#define DMA_CS 0x00
#define DMA_CONBLK_AD 0x04
#define DMA_TI 0x08
#define DMA_SRCE_AD 0x0c
#define DMA_DEST_AD 0x10
#define DMA_TXFR_LEN 0x14
#define DMA_STRIDE 0x18
#define DMA_NEXTCONBK 0x1c
#define DMA_DEBUG 0x20
#define DMA_REG(ch, r) ((r)==DMA_ENABLE ? DMA_ENABLE : (ch)*0x100+(r))
#define DMA_ENABLE 0xff0
// DMA register values
#define DMA_WAIT_RESP (1 << 3)
#define DMA_CB_DEST_INC (1 << 4)
#define DMA_DEST_DREQ (1 << 6)
#define DMA_CB_SRCE_INC (1 << 8)
#define DMA_SRCE_DREQ (1 << 10)
#define DMA_PRIORITY(n) ((n) << 16)
// DMA control block (must be 32-byte aligned)
typedef struct {
uint32_t ti, // Transfer info
srce_ad, // Source address
dest_ad, // Destination address
tfr_len, // Transfer length
stride, // Transfer stride
next_cb, // Next control block
debug, // Debug register, zero in control block
unused;
} DMA_CB __attribute__ ((aligned(32)));
// PWM controller registers
#define PWM_BASE (PHYS_REG_BASE + 0x20C000)
#define PWM_CTL 0x00 // Control
#define PWM_STA 0x04 // Status
#define PWM_DMAC 0x08 // DMA control
#define PWM_RNG1 0x10 // Channel 1 range
#define PWM_DAT1 0x14 // Channel 1 data
#define PWM_FIF1 0x18 // Channel 1 fifo
#define PWM_RNG2 0x20 // Channel 2 range
#define PWM_DAT2 0x24 // Channel 2 data
// PWM register values
#define PWM_CTL_RPTL1 (1<<2) // Chan 1: repeat last data when FIFO empty
#define PWM_CTL_USEF1 (1<<5) // Chan 1: use FIFO
#define PWM_DMAC_ENAB (1<<31) // Start PWM DMA
#define PWM_ENAB 1 // Enable PWM
#define PWM_PIN 12 // GPIO pin for PWM output, 12 or 18
// Clock registers and values
#define CLK_BASE (PHYS_REG_BASE + 0x101000)
#define CLK_PWM_CTL 0xa0
#define CLK_PWM_DIV 0xa4
#define CLK_PASSWD 0x5a000000
#define PWM_CLOCK_ID 0xa
void fail(char *s);
void *map_periph(MEM_MAP *mp, void *phys, int size);
void *map_uncached_mem(MEM_MAP *mp, int size);
void unmap_periph_mem(MEM_MAP *mp);
void gpio_set(int pin, int mode, int pull);
void gpio_pull(int pin, int pull);
void gpio_mode(int pin, int mode);
void gpio_out(int pin, int val);
uint8_t gpio_in(int pin);
void disp_mode_vals(uint32_t mode);
int open_mbox(void);
void close_mbox(int fd);
uint32_t msg_mbox(int fd, VC_MSG *msgp);
void *map_segment(void *addr, int size);
void unmap_segment(void *addr, int size);
uint32_t alloc_vc_mem(int fd, uint32_t size, VC_ALLOC_FLAGS flags);
void *lock_vc_mem(int fd, int h);
uint32_t unlock_vc_mem(int fd, int h);
uint32_t free_vc_mem(int fd, int h);
uint32_t set_vc_clock(int fd, int id, uint32_t freq);
void disp_vc_msg(VC_MSG *msgp);
void enable_dma(int chan);
void start_dma(MEM_MAP *mp, int chan, DMA_CB *cbp, uint32_t csval);
uint32_t dma_transfer_len(int chan);
uint32_t dma_active(int chan);
void stop_dma(int chan);
void disp_dma(int chan);
void init_pwm(int freq, int range, int val);
void start_pwm(void);
void stop_pwm(void);
// EOF