Landfall

Annotated pkg/landfall-examples/letux400_dma/letux400_dma.cc

254:a437381bd5f4
9 months ago Paul Boddie Employed get_channel to eliminate redundant code. cpm-library-improvements
paul@123 1
/*
paul@123 2
 * Test DMA transfers.
paul@123 3
 *
paul@143 4
 * Copyright (C) 2018, 2020, 2021, 2023 Paul Boddie <paul@boddie.org.uk>
paul@123 5
 *
paul@123 6
 * This program is free software; you can redistribute it and/or
paul@123 7
 * modify it under the terms of the GNU General Public License as
paul@123 8
 * published by the Free Software Foundation; either version 2 of
paul@123 9
 * the License, or (at your option) any later version.
paul@123 10
 *
paul@123 11
 * This program is distributed in the hope that it will be useful,
paul@123 12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@123 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@123 14
 * GNU General Public License for more details.
paul@123 15
 *
paul@123 16
 * You should have received a copy of the GNU General Public License
paul@123 17
 * along with this program; if not, write to the Free Software
paul@123 18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@123 19
 * Boston, MA  02110-1301, USA
paul@123 20
 */
paul@123 21
paul@209 22
#include <l4/devices/dma.h>
paul@123 23
#include <l4/devices/cpm-jz4730.h>
paul@123 24
#include <l4/devices/dma-jz4730.h>
paul@123 25
#include <l4/devices/memory.h>
paul@123 26
paul@123 27
#include <l4/re/c/util/cap_alloc.h>
paul@123 28
#include <l4/re/c/dataspace.h>
paul@123 29
#include <l4/re/c/rm.h>
paul@123 30
paul@143 31
#include <l4/sys/err.h>
paul@123 32
#include <l4/sys/factory.h>
paul@123 33
#include <l4/sys/icu.h>
paul@123 34
#include <l4/sys/irq.h>
paul@123 35
#include <l4/sys/rcv_endpoint.h>
paul@123 36
paul@123 37
#include <stdio.h>
paul@123 38
#include <string.h>
paul@123 39
#include <unistd.h>
paul@123 40
paul@123 41
paul@123 42
paul@123 43
/* Device and resource discovery. */
paul@123 44
paul@123 45
static long item_in_range(long start, long end, long index)
paul@123 46
{
paul@123 47
  if (start < end)
paul@123 48
    return start + index;
paul@123 49
  else
paul@123 50
    return start - index;
paul@123 51
}
paul@123 52
paul@123 53
paul@123 54
paul@123 55
int main(void)
paul@123 56
{
paul@143 57
  long err;
paul@123 58
  void *cpm;
paul@143 59
  void *dmac, *dma0;
paul@123 60
paul@123 61
  /* Allocate memory to test transfers. */
paul@123 62
paul@123 63
  l4_cap_idx_t ds0_mem, ds1_mem;
paul@209 64
  l4_size_t ds0_size = L4_PAGESIZE, ds1_size = L4_PAGESIZE;
paul@143 65
  l4_addr_t ds0_addr, ds1_addr;
paul@143 66
  l4re_dma_space_dma_addr_t ds0_paddr, ds1_paddr;
paul@123 67
paul@209 68
  err = get_dma_region(ds0_size, 8, &ds0_addr, &ds0_paddr, &ds0_mem);
paul@123 69
paul@209 70
  if (err)
paul@123 71
  {
paul@209 72
    printf("Could not allocate region #0.\n");
paul@123 73
    return 1;
paul@123 74
  }
paul@123 75
paul@209 76
  err = get_dma_region(ds1_size, 8, &ds1_addr, &ds1_paddr, &ds1_mem);
paul@143 77
paul@143 78
  if (err)
paul@123 79
  {
paul@209 80
    printf("Could not allocate region #1.\n");
paul@123 81
    return 1;
paul@123 82
  }
paul@123 83
paul@123 84
  /* Fill the allocated memory. */
paul@123 85
paul@123 86
  memset((void *) ds0_addr, 0, ds0_size);
paul@123 87
  memset((void *) ds1_addr, 0, ds1_size);
paul@123 88
paul@123 89
  sprintf((char *) ds0_addr, "The quick brown fox jumped over the lazy dog.\n");
paul@123 90
paul@123 91
  /* Interrupts. */
paul@123 92
paul@123 93
  l4_uint32_t dma_irq_start = 0, dma_irq_end = 0;
paul@123 94
  l4_cap_idx_t icucap, irq0cap;
paul@123 95
paul@123 96
  /* Obtain resource details describing the interrupt for DMA channel 0. */
paul@123 97
paul@123 98
  printf("Access IRQ...\n");
paul@123 99
paul@123 100
  if (get_irq("jz4730-dma", &dma_irq_start, &dma_irq_end) < 0)
paul@123 101
    return 1;
paul@123 102
paul@123 103
  printf("IRQ range at %d...%d.\n", dma_irq_start, dma_irq_end);
paul@123 104
paul@123 105
  /* Obtain capabilities for the interrupt controller and an interrupt. */
paul@123 106
paul@123 107
  irq0cap = l4re_util_cap_alloc();
paul@123 108
  icucap = l4re_env_get_cap("icu");
paul@123 109
paul@123 110
  if (l4_is_invalid_cap(icucap))
paul@123 111
  { 
paul@123 112
    printf("No 'icu' capability available in the virtual bus.\n");
paul@123 113
    return 1;
paul@123 114
  }
paul@123 115
paul@123 116
  if (l4_is_invalid_cap(irq0cap))
paul@123 117
  {
paul@123 118
    printf("Capabilities not available for interrupts.\n");
paul@123 119
    return 1;
paul@123 120
  }
paul@123 121
paul@123 122
  /* Create interrupt objects. */
paul@123 123
paul@123 124
  err = l4_error(l4_factory_create_irq(l4re_global_env->factory, irq0cap));
paul@123 125
paul@123 126
  if (err)
paul@123 127
  {
paul@123 128
    printf("Could not create IRQ object: %lx\n", err);
paul@123 129
    return 1;
paul@123 130
  }
paul@123 131
paul@123 132
  /* Bind interrupt objects to IRQ numbers. */
paul@123 133
paul@123 134
  err = l4_error(l4_icu_bind(icucap,
paul@123 135
                             item_in_range(dma_irq_start, dma_irq_end, 0),
paul@123 136
                             irq0cap));
paul@123 137
paul@123 138
  if (err)
paul@123 139
  {
paul@123 140
    printf("Could not bind IRQ to the ICU: %ld\n", err);
paul@123 141
    return 1;
paul@123 142
  }
paul@123 143
paul@123 144
  /* Attach ourselves to the interrupt handler. */
paul@123 145
paul@123 146
  err = l4_error(l4_rcv_ep_bind_thread(irq0cap, l4re_env()->main_thread, 0));
paul@123 147
paul@123 148
  if (err)
paul@123 149
  {
paul@123 150
    printf("Could not attach to IRQs: %ld\n", err);
paul@123 151
    return 1;
paul@123 152
  }
paul@123 153
paul@123 154
  /* Peripheral memory. */
paul@123 155
paul@123 156
  l4_addr_t cpm_base = 0, cpm_base_end = 0;
paul@123 157
  l4_addr_t dma_base = 0, dma_base_end = 0;
paul@123 158
paul@123 159
  /* Obtain resource details describing I/O memory. */
paul@123 160
paul@123 161
  printf("Access CPM...\n");
paul@123 162
paul@123 163
  if (get_memory("jz4730-cpm", &cpm_base, &cpm_base_end) < 0)
paul@123 164
    return 1;
paul@123 165
paul@123 166
  printf("CPM at 0x%lx...0x%lx.\n", cpm_base, cpm_base_end);
paul@123 167
paul@123 168
  printf("Access DMA...\n");
paul@123 169
paul@123 170
  if (get_memory("jz4730-dma", &dma_base, &dma_base_end) < 0)
paul@123 171
    return 1;
paul@123 172
paul@123 173
  printf("DMA at 0x%lx...0x%lx.\n", dma_base, dma_base_end);
paul@123 174
paul@123 175
  /* Obtain CPM and DMA references. */
paul@123 176
paul@123 177
  cpm = jz4730_cpm_init(cpm_base);
paul@143 178
  dmac = jz4730_dma_init(dma_base, dma_base_end, cpm);
paul@143 179
  dma0 = jz4730_dma_get_channel(dmac, 0, irq0cap);
paul@123 180
paul@123 181
  /* Enable DMA. */
paul@123 182
paul@123 183
  printf("Enable DMA...\n");
paul@123 184
paul@143 185
  jz4730_dma_enable(dmac);
paul@123 186
paul@123 187
  /* Transfer data between the allocated memory regions. */
paul@123 188
paul@143 189
  printf("Transfer from %llx to %llx...\n", ds0_paddr, ds1_paddr);
paul@123 190
paul@209 191
  unsigned int count = L4_PAGESIZE / 4;
paul@123 192
paul@209 193
  unsigned int to_transfer = jz4730_dma_transfer(dma0, (uint32_t) ds0_paddr,
paul@209 194
                                                 (uint32_t) ds1_paddr,
paul@209 195
                                                 count,
paul@209 196
                                                 1, 1,
paul@209 197
                                                 4, 4,
paul@209 198
                                                 4,
paul@209 199
                                                 Dma_request_auto);
paul@209 200
paul@209 201
  unsigned int transferred = to_transfer ? count - jz4730_dma_wait(dma0) : 0;
paul@209 202
paul@209 203
  printf("Transferred: %d\n", transferred);
paul@123 204
  printf("Source: %s\n", (char *) ds0_addr);
paul@123 205
  printf("Destination: %s\n", (char *) ds1_addr);
paul@123 206
paul@123 207
  /* Detach from the interrupt. */
paul@123 208
paul@123 209
  err = l4_error(l4_irq_detach(irq0cap));
paul@123 210
paul@123 211
  if (err)
paul@123 212
    printf("Error detaching from IRQ objects: %ld\n", err);
paul@123 213
paul@123 214
  return 0;
paul@123 215
}