1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/pkg/landfall-examples/letux400_dma/letux400_dma.cc Sun Jan 10 22:21:57 2021 +0100
1.3 @@ -0,0 +1,226 @@
1.4 +/*
1.5 + * Test DMA transfers.
1.6 + *
1.7 + * Copyright (C) 2018, 2020, 2021 Paul Boddie <paul@boddie.org.uk>
1.8 + *
1.9 + * This program is free software; you can redistribute it and/or
1.10 + * modify it under the terms of the GNU General Public License as
1.11 + * published by the Free Software Foundation; either version 2 of
1.12 + * the License, or (at your option) any later version.
1.13 + *
1.14 + * This program is distributed in the hope that it will be useful,
1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.17 + * GNU General Public License for more details.
1.18 + *
1.19 + * You should have received a copy of the GNU General Public License
1.20 + * along with this program; if not, write to the Free Software
1.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
1.22 + * Boston, MA 02110-1301, USA
1.23 + */
1.24 +
1.25 +#include <l4/devices/cpm-jz4730.h>
1.26 +#include <l4/devices/dma-jz4730.h>
1.27 +#include <l4/devices/memory.h>
1.28 +
1.29 +#include <l4/re/c/util/cap_alloc.h>
1.30 +#include <l4/re/c/dataspace.h>
1.31 +#include <l4/re/c/mem_alloc.h>
1.32 +#include <l4/re/c/rm.h>
1.33 +
1.34 +#include <l4/sys/factory.h>
1.35 +#include <l4/sys/icu.h>
1.36 +#include <l4/sys/irq.h>
1.37 +#include <l4/sys/rcv_endpoint.h>
1.38 +
1.39 +#include <stdio.h>
1.40 +#include <string.h>
1.41 +#include <unistd.h>
1.42 +
1.43 +
1.44 +
1.45 +/* Device and resource discovery. */
1.46 +
1.47 +static long item_in_range(long start, long end, long index)
1.48 +{
1.49 + if (start < end)
1.50 + return start + index;
1.51 + else
1.52 + return start - index;
1.53 +}
1.54 +
1.55 +
1.56 +
1.57 +int main(void)
1.58 +{
1.59 + void *cpm;
1.60 + void *dma, *dma0;
1.61 +
1.62 + /* Allocate memory to test transfers. */
1.63 +
1.64 + l4_cap_idx_t ds0_mem, ds1_mem;
1.65 + l4_size_t ds0_size = L4_PAGESIZE, ds0_psize, ds1_size = L4_PAGESIZE, ds1_psize;
1.66 + l4_addr_t ds0_addr, ds0_paddr, ds1_addr, ds1_paddr;
1.67 +
1.68 + ds0_mem = l4re_util_cap_alloc();
1.69 + ds1_mem = l4re_util_cap_alloc();
1.70 +
1.71 + if (l4_is_invalid_cap(ds0_mem) || l4_is_invalid_cap(ds1_mem))
1.72 + {
1.73 + printf("Could not allocate memory capabilities.\n");
1.74 + return 1;
1.75 + }
1.76 +
1.77 + if (l4re_ma_alloc_align(ds0_size, ds0_mem, L4RE_MA_CONTINUOUS | L4RE_MA_PINNED, 8) ||
1.78 + l4re_ma_alloc_align(ds1_size, ds1_mem, L4RE_MA_CONTINUOUS | L4RE_MA_PINNED, 8))
1.79 + {
1.80 + printf("Could not allocate memory.\n");
1.81 + return 1;
1.82 + }
1.83 +
1.84 + if (l4re_rm_attach((void **) &ds0_addr, ds0_size,
1.85 + L4RE_RM_SEARCH_ADDR | L4RE_RM_EAGER_MAP,
1.86 + ds0_mem, 0, L4_PAGESHIFT) ||
1.87 + l4re_rm_attach((void **) &ds1_addr, ds1_size,
1.88 + L4RE_RM_SEARCH_ADDR | L4RE_RM_EAGER_MAP,
1.89 + ds1_mem, 0, L4_PAGESHIFT))
1.90 + {
1.91 + printf("Could not map memory.\n");
1.92 + return 1;
1.93 + }
1.94 +
1.95 + if (l4re_ds_phys(ds0_mem, 0, &ds0_paddr, &ds0_psize) ||
1.96 + l4re_ds_phys(ds1_mem, 0, &ds1_paddr, &ds1_psize))
1.97 + {
1.98 + printf("Could not get physical addresses for memory.\n");
1.99 + return 1;
1.100 + }
1.101 +
1.102 + /* Fill the allocated memory. */
1.103 +
1.104 + memset((void *) ds0_addr, 0, ds0_size);
1.105 + memset((void *) ds1_addr, 0, ds1_size);
1.106 +
1.107 + sprintf((char *) ds0_addr, "The quick brown fox jumped over the lazy dog.\n");
1.108 +
1.109 + /* Interrupts. */
1.110 +
1.111 + l4_uint32_t dma_irq_start = 0, dma_irq_end = 0;
1.112 + l4_cap_idx_t icucap, irq0cap;
1.113 +
1.114 + /* Obtain resource details describing the interrupt for DMA channel 0. */
1.115 +
1.116 + printf("Access IRQ...\n");
1.117 +
1.118 + if (get_irq("jz4730-dma", &dma_irq_start, &dma_irq_end) < 0)
1.119 + return 1;
1.120 +
1.121 + printf("IRQ range at %d...%d.\n", dma_irq_start, dma_irq_end);
1.122 +
1.123 + /* Obtain capabilities for the interrupt controller and an interrupt. */
1.124 +
1.125 + irq0cap = l4re_util_cap_alloc();
1.126 + icucap = l4re_env_get_cap("icu");
1.127 +
1.128 + if (l4_is_invalid_cap(icucap))
1.129 + {
1.130 + printf("No 'icu' capability available in the virtual bus.\n");
1.131 + return 1;
1.132 + }
1.133 +
1.134 + if (l4_is_invalid_cap(irq0cap))
1.135 + {
1.136 + printf("Capabilities not available for interrupts.\n");
1.137 + return 1;
1.138 + }
1.139 +
1.140 + /* Create interrupt objects. */
1.141 +
1.142 + long err;
1.143 +
1.144 + err = l4_error(l4_factory_create_irq(l4re_global_env->factory, irq0cap));
1.145 +
1.146 + if (err)
1.147 + {
1.148 + printf("Could not create IRQ object: %lx\n", err);
1.149 + return 1;
1.150 + }
1.151 +
1.152 + /* Bind interrupt objects to IRQ numbers. */
1.153 +
1.154 + err = l4_error(l4_icu_bind(icucap,
1.155 + item_in_range(dma_irq_start, dma_irq_end, 0),
1.156 + irq0cap));
1.157 +
1.158 + if (err)
1.159 + {
1.160 + printf("Could not bind IRQ to the ICU: %ld\n", err);
1.161 + return 1;
1.162 + }
1.163 +
1.164 + /* Attach ourselves to the interrupt handler. */
1.165 +
1.166 + err = l4_error(l4_rcv_ep_bind_thread(irq0cap, l4re_env()->main_thread, 0));
1.167 +
1.168 + if (err)
1.169 + {
1.170 + printf("Could not attach to IRQs: %ld\n", err);
1.171 + return 1;
1.172 + }
1.173 +
1.174 + /* Peripheral memory. */
1.175 +
1.176 + l4_addr_t cpm_base = 0, cpm_base_end = 0;
1.177 + l4_addr_t dma_base = 0, dma_base_end = 0;
1.178 +
1.179 + /* Obtain resource details describing I/O memory. */
1.180 +
1.181 + printf("Access CPM...\n");
1.182 +
1.183 + if (get_memory("jz4730-cpm", &cpm_base, &cpm_base_end) < 0)
1.184 + return 1;
1.185 +
1.186 + printf("CPM at 0x%lx...0x%lx.\n", cpm_base, cpm_base_end);
1.187 +
1.188 + printf("Access DMA...\n");
1.189 +
1.190 + if (get_memory("jz4730-dma", &dma_base, &dma_base_end) < 0)
1.191 + return 1;
1.192 +
1.193 + printf("DMA at 0x%lx...0x%lx.\n", dma_base, dma_base_end);
1.194 +
1.195 + /* Obtain CPM and DMA references. */
1.196 +
1.197 + cpm = jz4730_cpm_init(cpm_base);
1.198 + dma = jz4730_dma_init(dma_base, dma_base_end, cpm);
1.199 + dma0 = jz4730_dma_get_channel(dma, 0, irq0cap);
1.200 +
1.201 + /* Enable DMA. */
1.202 +
1.203 + printf("Enable DMA...\n");
1.204 +
1.205 + jz4730_dma_enable(dma);
1.206 +
1.207 + /* Transfer data between the allocated memory regions. */
1.208 +
1.209 + printf("Transfer from %lx to %lx...\n", ds0_paddr, ds1_paddr);
1.210 +
1.211 + unsigned int ntransferred = jz4730_dma_transfer(dma0, (uint32_t) ds0_paddr,
1.212 + (uint32_t) ds1_paddr,
1.213 + L4_PAGESIZE / 4,
1.214 + Dma_trans_unit_size_32_bit,
1.215 + Dma_request_auto);
1.216 +
1.217 + printf("Transferred: %d\n", ntransferred);
1.218 + printf("Source: %s\n", (char *) ds0_addr);
1.219 + printf("Destination: %s\n", (char *) ds1_addr);
1.220 +
1.221 + /* Detach from the interrupt. */
1.222 +
1.223 + err = l4_error(l4_irq_detach(irq0cap));
1.224 +
1.225 + if (err)
1.226 + printf("Error detaching from IRQ objects: %ld\n", err);
1.227 +
1.228 + return 0;
1.229 +}