1.1 --- a/conf/landfall-examples/mips-letux400-common.io Wed Jan 06 23:54:45 2021 +0100
1.2 +++ b/conf/landfall-examples/mips-letux400-common.io Sat Jan 16 23:00:45 2021 +0100
1.3 @@ -9,11 +9,23 @@
1.4 CPM = wrap(hw:match("jz4730-cpm"));
1.5 })
1.6
1.7 +Io.add_vbus("dma", Io.Vi.System_bus
1.8 +{
1.9 + CPM = wrap(hw:match("jz4730-cpm"));
1.10 + DMA = wrap(hw:match("jz4730-dma"));
1.11 +})
1.12 +
1.13 Io.add_vbus("gpio", Io.Vi.System_bus
1.14 {
1.15 GPIO = wrap(hw:match("jz4730-gpio"));
1.16 })
1.17
1.18 +Io.add_vbus("i2c", Io.Vi.System_bus
1.19 +{
1.20 + CPM = wrap(hw:match("jz4730-cpm"));
1.21 + I2C = wrap(hw:match("jz4730-i2c"));
1.22 +})
1.23 +
1.24 Io.add_vbus("lcd", Io.Vi.System_bus
1.25 {
1.26 LCD = wrap(hw:match("jz4740-lcd"));
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/conf/landfall-examples/mips-letux400-dma.cfg Sat Jan 16 23:00:45 2021 +0100
2.3 @@ -0,0 +1,136 @@
2.4 +-- vim: ft=lua ts=2 et sw=2
2.5 +
2.6 +-- Start Mag to multiplex the framebuffer showing only a single program.
2.7 +-- This example shows a framebuffer terminal showing the hello example's output.
2.8 +-- The target platform is the Letux 400 notebook computer.
2.9 +
2.10 +local L4 = require("L4");
2.11 +
2.12 +local l = L4.default_loader;
2.13 +
2.14 +-- Define general access to peripherals.
2.15 +
2.16 +local io_buses = {
2.17 + cpm = l:new_channel();
2.18 + dma = l:new_channel();
2.19 + gpio = l:new_channel();
2.20 + lcd = l:new_channel();
2.21 + pwm = l:new_channel(); -- exposes GPIO, PWM
2.22 + };
2.23 +
2.24 +l:start({
2.25 + caps = {
2.26 + cpm = io_buses.cpm:svr(),
2.27 + dma = io_buses.dma:svr(),
2.28 + gpio = io_buses.gpio:svr(),
2.29 + lcd = io_buses.lcd:svr(),
2.30 + pwm = io_buses.pwm:svr(),
2.31 +
2.32 + icu = L4.Env.icu,
2.33 + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0),
2.34 + },
2.35 + },
2.36 + "rom/io rom/hw_devices.io rom/mips-letux400-common.io");
2.37 +
2.38 +-- Expose a PWM peripheral as a device.
2.39 +
2.40 +local pwm = l:new_channel();
2.41 +
2.42 +l:startv({
2.43 + caps = {
2.44 + vbus = io_buses.pwm,
2.45 + pwm = pwm:svr(),
2.46 + },
2.47 + },
2.48 + "rom/dev_pwm_jz4730", "0", "250", "299", "47"); -- specifying peripheral number, parameters
2.49 +
2.50 +-- Expose a PWM backlight device.
2.51 +
2.52 +local backlight = l:new_channel(); -- exposes backlight device
2.53 +
2.54 +l:startv({
2.55 + caps = {
2.56 + pwm = pwm,
2.57 + backlight = backlight:svr(),
2.58 + },
2.59 + },
2.60 + "rom/dev_backlight_pwm", "0", "300"); -- specifying limits
2.61 +
2.62 +-- Expose a display device for the Letux.
2.63 +
2.64 +local display = l:new_channel(); -- exposes display device
2.65 +
2.66 +l:start({
2.67 + caps = {
2.68 + backlight = backlight,
2.69 + display = display:svr(),
2.70 + vbus = io_buses.gpio,
2.71 + },
2.72 + },
2.73 + "rom/dev_display_letux400");
2.74 +
2.75 +-- Expose the CPM peripheral.
2.76 +
2.77 +local cpm = l:new_channel();
2.78 +
2.79 +l:start({
2.80 + caps = {
2.81 + vbus = io_buses.cpm,
2.82 + cpm = cpm:svr(),
2.83 + },
2.84 + },
2.85 + "rom/dev_cpm_jz4730");
2.86 +
2.87 +-- Expose a framebuffer device.
2.88 +
2.89 +local fbdrv_fb = l:new_channel();
2.90 +
2.91 +l:start({
2.92 + caps = {
2.93 + vbus = io_buses.lcd,
2.94 + fb = fbdrv_fb:svr(),
2.95 + cpm = cpm,
2.96 + display = display, -- needed by LCD driver
2.97 + },
2.98 + },
2.99 + "rom/fb-drv");
2.100 +
2.101 +-- Multiplex the framebuffer.
2.102 +
2.103 +local mag_caps = {
2.104 + mag = l:new_channel(),
2.105 + svc = l:new_channel(),
2.106 + };
2.107 +
2.108 +l:start({
2.109 + caps = {
2.110 + vbus = io_buses.gpio, -- needed by input driver
2.111 + fb = fbdrv_fb,
2.112 + mag = mag_caps.mag:svr(),
2.113 + svc = mag_caps.svc:svr(),
2.114 + },
2.115 + },
2.116 + "rom/mag");
2.117 +
2.118 +-- Show the terminal.
2.119 +
2.120 +local term = l:new_channel();
2.121 +
2.122 +l:start({
2.123 + caps = {
2.124 + fb = mag_caps.svc:create(L4.Proto.Goos, "g=800x460+0+0", "barheight=20"),
2.125 + term = term:svr(),
2.126 + },
2.127 + },
2.128 + "rom/fbterminal");
2.129 +
2.130 +-- Show the DMA example.
2.131 +
2.132 +l:start({
2.133 + caps = {
2.134 + icu = L4.Env.icu,
2.135 + vbus = io_buses.dma,
2.136 + },
2.137 + log_cap = term,
2.138 + },
2.139 + "rom/ex_letux400_dma");
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/conf/landfall-examples/mips-letux400-dma.list Sat Jan 16 23:00:45 2021 +0100
3.3 @@ -0,0 +1,47 @@
3.4 +
3.5 +modaddr 0x1100000
3.6 +
3.7 +entry mips-letux400-dma-example
3.8 +bootstrap bootstrap -serial
3.9 +kernel fiasco -serial_esc
3.10 +roottask moe rom/mips-letux400-dma.cfg
3.11 +module mips-letux400-dma.cfg
3.12 +module mips-letux400-common.io
3.13 +module plat-letux400/hw_devices.io
3.14 +module l4re
3.15 +module io
3.16 +module ned
3.17 +module fb-drv
3.18 +module mag
3.19 +module dev_pwm_jz4730
3.20 +module dev_backlight_pwm
3.21 +module dev_display_letux400
3.22 +module dev_cpm_jz4730
3.23 +module fbterminal
3.24 +module ex_letux400_dma
3.25 +module libpanel_letux400.so
3.26 +module mips-jz4740-panel.txt
3.27 +module lib4re-c.so
3.28 +module lib4re-c-util.so
3.29 +module lib4re.so
3.30 +module lib4re-util.so
3.31 +module libc_be_l4refile.so
3.32 +module libc_be_l4re.so
3.33 +module libc_be_socket_noop.so
3.34 +module libcpm.o.so
3.35 +module libc_support_misc.so
3.36 +module libdevice_util.o.so
3.37 +module libdl.so
3.38 +module libgpio.o.so
3.39 +module libio-io.so
3.40 +module libio-vbus.so
3.41 +module libipc.so
3.42 +module libl4sys-direct.so
3.43 +module libl4sys.so
3.44 +module libl4util.so
3.45 +module liblcd_jz4740.o.so
3.46 +module libld-l4.so
3.47 +module libpthread.so
3.48 +module libpwm.o.so
3.49 +module libsupc++.so
3.50 +module libuc_c.so
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/conf/landfall-examples/mips-letux400-i2c.cfg Sat Jan 16 23:00:45 2021 +0100
4.3 @@ -0,0 +1,136 @@
4.4 +-- vim: ft=lua ts=2 et sw=2
4.5 +
4.6 +-- Start Mag to multiplex the framebuffer showing only a single program.
4.7 +-- This example shows a framebuffer terminal showing the hello example's output.
4.8 +-- The target platform is the Letux 400 notebook computer.
4.9 +
4.10 +local L4 = require("L4");
4.11 +
4.12 +local l = L4.default_loader;
4.13 +
4.14 +-- Define general access to peripherals.
4.15 +
4.16 +local io_buses = {
4.17 + cpm = l:new_channel();
4.18 + gpio = l:new_channel();
4.19 + i2c = l:new_channel();
4.20 + lcd = l:new_channel();
4.21 + pwm = l:new_channel(); -- exposes GPIO, PWM
4.22 + };
4.23 +
4.24 +l:start({
4.25 + caps = {
4.26 + cpm = io_buses.cpm:svr(),
4.27 + gpio = io_buses.gpio:svr(),
4.28 + i2c = io_buses.i2c:svr(),
4.29 + lcd = io_buses.lcd:svr(),
4.30 + pwm = io_buses.pwm:svr(),
4.31 +
4.32 + icu = L4.Env.icu,
4.33 + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0),
4.34 + },
4.35 + },
4.36 + "rom/io rom/hw_devices.io rom/mips-letux400-common.io");
4.37 +
4.38 +-- Expose a PWM peripheral as a device.
4.39 +
4.40 +local pwm = l:new_channel();
4.41 +
4.42 +l:startv({
4.43 + caps = {
4.44 + vbus = io_buses.pwm,
4.45 + pwm = pwm:svr(),
4.46 + },
4.47 + },
4.48 + "rom/dev_pwm_jz4730", "0", "250", "299", "47"); -- specifying peripheral number, parameters
4.49 +
4.50 +-- Expose a PWM backlight device.
4.51 +
4.52 +local backlight = l:new_channel(); -- exposes backlight device
4.53 +
4.54 +l:startv({
4.55 + caps = {
4.56 + pwm = pwm,
4.57 + backlight = backlight:svr(),
4.58 + },
4.59 + },
4.60 + "rom/dev_backlight_pwm", "0", "300"); -- specifying limits
4.61 +
4.62 +-- Expose a display device for the Letux.
4.63 +
4.64 +local display = l:new_channel(); -- exposes display device
4.65 +
4.66 +l:start({
4.67 + caps = {
4.68 + backlight = backlight,
4.69 + display = display:svr(),
4.70 + vbus = io_buses.gpio,
4.71 + },
4.72 + },
4.73 + "rom/dev_display_letux400");
4.74 +
4.75 +-- Expose the CPM peripheral.
4.76 +
4.77 +local cpm = l:new_channel();
4.78 +
4.79 +l:start({
4.80 + caps = {
4.81 + vbus = io_buses.cpm,
4.82 + cpm = cpm:svr(),
4.83 + },
4.84 + },
4.85 + "rom/dev_cpm_jz4730");
4.86 +
4.87 +-- Expose a framebuffer device.
4.88 +
4.89 +local fbdrv_fb = l:new_channel();
4.90 +
4.91 +l:start({
4.92 + caps = {
4.93 + vbus = io_buses.lcd,
4.94 + fb = fbdrv_fb:svr(),
4.95 + cpm = cpm,
4.96 + display = display, -- needed by LCD driver
4.97 + },
4.98 + },
4.99 + "rom/fb-drv");
4.100 +
4.101 +-- Multiplex the framebuffer.
4.102 +
4.103 +local mag_caps = {
4.104 + mag = l:new_channel(),
4.105 + svc = l:new_channel(),
4.106 + };
4.107 +
4.108 +l:start({
4.109 + caps = {
4.110 + vbus = io_buses.gpio, -- needed by input driver
4.111 + fb = fbdrv_fb,
4.112 + mag = mag_caps.mag:svr(),
4.113 + svc = mag_caps.svc:svr(),
4.114 + },
4.115 + },
4.116 + "rom/mag");
4.117 +
4.118 +-- Show the terminal.
4.119 +
4.120 +local term = l:new_channel();
4.121 +
4.122 +l:start({
4.123 + caps = {
4.124 + fb = mag_caps.svc:create(L4.Proto.Goos, "g=800x460+0+0", "barheight=20"),
4.125 + term = term:svr(),
4.126 + },
4.127 + },
4.128 + "rom/fbterminal");
4.129 +
4.130 +-- Show the I2C example.
4.131 +
4.132 +l:start({
4.133 + caps = {
4.134 + icu = L4.Env.icu,
4.135 + vbus = io_buses.i2c,
4.136 + },
4.137 + log_cap = term,
4.138 + },
4.139 + "rom/ex_letux400_i2c");
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/conf/landfall-examples/mips-letux400-i2c.list Sat Jan 16 23:00:45 2021 +0100
5.3 @@ -0,0 +1,47 @@
5.4 +
5.5 +modaddr 0x1100000
5.6 +
5.7 +entry mips-letux400-i2c-example
5.8 +bootstrap bootstrap -serial
5.9 +kernel fiasco -serial_esc
5.10 +roottask moe rom/mips-letux400-i2c.cfg
5.11 +module mips-letux400-i2c.cfg
5.12 +module mips-letux400-common.io
5.13 +module plat-letux400/hw_devices.io
5.14 +module l4re
5.15 +module io
5.16 +module ned
5.17 +module fb-drv
5.18 +module mag
5.19 +module dev_pwm_jz4730
5.20 +module dev_backlight_pwm
5.21 +module dev_display_letux400
5.22 +module dev_cpm_jz4730
5.23 +module fbterminal
5.24 +module ex_letux400_i2c
5.25 +module libpanel_letux400.so
5.26 +module mips-jz4740-panel.txt
5.27 +module lib4re-c.so
5.28 +module lib4re-c-util.so
5.29 +module lib4re.so
5.30 +module lib4re-util.so
5.31 +module libc_be_l4refile.so
5.32 +module libc_be_l4re.so
5.33 +module libc_be_socket_noop.so
5.34 +module libcpm.o.so
5.35 +module libc_support_misc.so
5.36 +module libdevice_util.o.so
5.37 +module libdl.so
5.38 +module libgpio.o.so
5.39 +module libio-io.so
5.40 +module libio-vbus.so
5.41 +module libipc.so
5.42 +module libl4sys-direct.so
5.43 +module libl4sys.so
5.44 +module libl4util.so
5.45 +module liblcd_jz4740.o.so
5.46 +module libld-l4.so
5.47 +module libpthread.so
5.48 +module libpwm.o.so
5.49 +module libsupc++.so
5.50 +module libuc_c.so
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/pkg/devices/lib/dma/include/dma-jz4730.h Sat Jan 16 23:00:45 2021 +0100
6.3 @@ -0,0 +1,217 @@
6.4 +/*
6.5 + * DMA support for the JZ4730.
6.6 + *
6.7 + * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
6.8 + *
6.9 + * This program is free software; you can redistribute it and/or
6.10 + * modify it under the terms of the GNU General Public License as
6.11 + * published by the Free Software Foundation; either version 2 of
6.12 + * the License, or (at your option) any later version.
6.13 + *
6.14 + * This program is distributed in the hope that it will be useful,
6.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
6.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6.17 + * GNU General Public License for more details.
6.18 + *
6.19 + * You should have received a copy of the GNU General Public License
6.20 + * along with this program; if not, write to the Free Software
6.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
6.22 + * Boston, MA 02110-1301, USA
6.23 + */
6.24 +
6.25 +#pragma once
6.26 +
6.27 +#include <l4/sys/types.h>
6.28 +#include <stdint.h>
6.29 +
6.30 +
6.31 +
6.32 +/* Enumerated types for various transfer parameters. */
6.33 +
6.34 +enum Dma_jz4730_request_type : unsigned
6.35 +{
6.36 + Dma_request_external = 0,
6.37 + Dma_request_pcmcia_out = 4,
6.38 + Dma_request_pcmcia_in = 5,
6.39 + Dma_request_auto = 8,
6.40 + Dma_request_des_out = 10,
6.41 + Dma_request_des_in = 11,
6.42 + Dma_request_uart3_out = 14,
6.43 + Dma_request_uart3_in = 15,
6.44 + Dma_request_uart2_out = 16,
6.45 + Dma_request_uart2_in = 17,
6.46 + Dma_request_uart1_out = 18,
6.47 + Dma_request_uart1_in = 19,
6.48 + Dma_request_uart0_out = 20,
6.49 + Dma_request_uart0_in = 21,
6.50 + Dma_request_ssi_send_empty = 22,
6.51 + Dma_request_ssi_recv_full = 23,
6.52 + Dma_request_aic_send_empty = 24,
6.53 + Dma_request_aic_recv_full = 25,
6.54 + Dma_request_msc_send_empty = 26,
6.55 + Dma_request_msc_recv_full = 27,
6.56 + Dma_request_ost2_underflow = 28,
6.57 +};
6.58 +
6.59 +enum Dma_jz4730_ext_level : unsigned
6.60 +{
6.61 + Dma_ext_active_high = 0,
6.62 + Dma_ext_active_low = 1,
6.63 +};
6.64 +
6.65 +enum Dma_jz4730_ext_output_mode_cycle : unsigned
6.66 +{
6.67 + Dma_ext_output_mode_read_cycle = 0,
6.68 + Dma_ext_output_mode_write_cycle = 1,
6.69 +};
6.70 +
6.71 +enum Dma_jz4730_ext_req_detect_mode : unsigned
6.72 +{
6.73 + Dma_ext_req_detect_mode_low_level = 0,
6.74 + Dma_ext_req_detect_mode_falling_edge = 1,
6.75 + Dma_ext_req_detect_mode_high_level = 2,
6.76 + Dma_ext_req_detect_mode_rising_edge = 3,
6.77 +};
6.78 +
6.79 +enum Dma_jz4730_trans_unit_size : unsigned
6.80 +{
6.81 + Dma_trans_unit_size_32_bit = 0,
6.82 + Dma_trans_unit_size_8_bit = 1,
6.83 + Dma_trans_unit_size_16_bit = 2,
6.84 + Dma_trans_unit_size_16_byte = 3,
6.85 + Dma_trans_unit_size_32_byte = 4,
6.86 +};
6.87 +
6.88 +
6.89 +
6.90 +#ifdef __cplusplus
6.91 +
6.92 +#include <l4/devices/cpm-jz4730.h>
6.93 +#include <l4/devices/hw_mmio_register_block.h>
6.94 +
6.95 +// Forward declaration.
6.96 +
6.97 +class Dma_jz4730_chip;
6.98 +
6.99 +
6.100 +
6.101 +// DMA channel.
6.102 +
6.103 +class Dma_jz4730_channel
6.104 +{
6.105 +private:
6.106 + Hw::Register_block<32> _regs;
6.107 + Dma_jz4730_chip *_chip;
6.108 + uint8_t _channel;
6.109 + l4_cap_idx_t _irq=L4_INVALID_CAP;
6.110 +
6.111 + // External transfer properties with defaults.
6.112 +
6.113 + enum Dma_jz4730_ext_level _ext_output_polarity = Dma_ext_active_high;
6.114 + enum Dma_jz4730_ext_level _ext_end_of_process_mode = Dma_ext_active_high;
6.115 + enum Dma_jz4730_ext_output_mode_cycle _ext_output_mode_cycle = Dma_ext_output_mode_read_cycle;
6.116 + enum Dma_jz4730_ext_req_detect_mode _ext_req_detect_mode = Dma_ext_req_detect_mode_high_level;
6.117 +
6.118 +public:
6.119 + Dma_jz4730_channel(Dma_jz4730_chip *chip, uint8_t channel, l4_addr_t start, l4_cap_idx_t irq);
6.120 +
6.121 + unsigned int transfer(uint32_t source, uint32_t destination,
6.122 + unsigned int count,
6.123 + enum Dma_jz4730_trans_unit_size size,
6.124 + enum Dma_jz4730_request_type type=Dma_request_auto);
6.125 +
6.126 + // External transfer property configuration.
6.127 +
6.128 + void set_output_polarity(enum Dma_jz4730_ext_level polarity)
6.129 + { _ext_output_polarity = polarity; }
6.130 +
6.131 + void set_end_of_process_mode(enum Dma_jz4730_ext_level mode)
6.132 + { _ext_end_of_process_mode = mode; }
6.133 +
6.134 + void set_output_mode_cycle(enum Dma_jz4730_ext_output_mode_cycle cycle)
6.135 + { _ext_output_mode_cycle = cycle; }
6.136 +
6.137 + void set_req_detect_mode(enum Dma_jz4730_ext_req_detect_mode mode)
6.138 + { _ext_req_detect_mode = mode; }
6.139 +
6.140 +protected:
6.141 + // Transfer property configuration.
6.142 +
6.143 + uint32_t encode_external_transfer(enum Dma_jz4730_request_type type);
6.144 +
6.145 + uint32_t encode_source_address_increment(enum Dma_jz4730_request_type type);
6.146 +
6.147 + uint32_t encode_destination_address_increment(enum Dma_jz4730_request_type type);
6.148 +
6.149 + uint32_t encode_req_detect_int_length(uint8_t units);
6.150 +
6.151 + uint32_t encode_source_port_width(enum Dma_jz4730_request_type type);
6.152 +
6.153 + uint32_t encode_destination_port_width(enum Dma_jz4730_request_type type);
6.154 +
6.155 + // Transaction control.
6.156 +
6.157 + void ack_irq();
6.158 +
6.159 + bool completed();
6.160 +
6.161 + bool error();
6.162 +
6.163 + bool halted();
6.164 +
6.165 + bool wait_for_irq();
6.166 +
6.167 + bool wait_for_irq(unsigned int timeout);
6.168 +};
6.169 +
6.170 +// DMA device control.
6.171 +
6.172 +class Dma_jz4730_chip
6.173 +{
6.174 +private:
6.175 + Hw::Register_block<32> _regs;
6.176 + l4_addr_t _start, _end;
6.177 + Cpm_jz4730_chip *_cpm;
6.178 +
6.179 +public:
6.180 + Dma_jz4730_chip(l4_addr_t start, l4_addr_t end, Cpm_jz4730_chip *cpm);
6.181 +
6.182 + void disable();
6.183 +
6.184 + void enable();
6.185 +
6.186 + Dma_jz4730_channel *get_channel(uint8_t channel, l4_cap_idx_t irq);
6.187 +
6.188 + bool have_interrupt(uint8_t channel);
6.189 +};
6.190 +
6.191 +#endif /* __cplusplus */
6.192 +
6.193 +
6.194 +
6.195 +/* C language interface. */
6.196 +
6.197 +EXTERN_C_BEGIN
6.198 +
6.199 +void *jz4730_dma_init(l4_addr_t start, l4_addr_t end, void *cpm);
6.200 +
6.201 +void jz4730_dma_disable(void *dma_chip);
6.202 +
6.203 +void jz4730_dma_enable(void *dma_chip);
6.204 +
6.205 +void *jz4730_dma_get_channel(void *dma, uint8_t channel, l4_cap_idx_t irq);
6.206 +
6.207 +void jz4730_dma_set_output_polarity(void *dma_channel, enum Dma_jz4730_ext_level polarity);
6.208 +
6.209 +void jz4730_dma_set_end_of_process_mode(void *dma_channel, enum Dma_jz4730_ext_level mode);
6.210 +
6.211 +void jz4730_dma_set_output_mode_cycle(void *dma_channel, enum Dma_jz4730_ext_output_mode_cycle cycle);
6.212 +
6.213 +void jz4730_dma_set_req_detect_mode(void *dma_channel, enum Dma_jz4730_ext_req_detect_mode mode);
6.214 +
6.215 +unsigned int jz4730_dma_transfer(void *dma_channel, uint32_t source,
6.216 + uint32_t destination, unsigned int count,
6.217 + enum Dma_jz4730_trans_unit_size size,
6.218 + enum Dma_jz4730_request_type type);
6.219 +
6.220 +EXTERN_C_END
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/pkg/devices/lib/dma/src/jz4730.cc Sat Jan 16 23:00:45 2021 +0100
7.3 @@ -0,0 +1,496 @@
7.4 +/*
7.5 + * DMA support for the JZ4730.
7.6 + *
7.7 + * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
7.8 + *
7.9 + * This program is free software; you can redistribute it and/or
7.10 + * modify it under the terms of the GNU General Public License as
7.11 + * published by the Free Software Foundation; either version 2 of
7.12 + * the License, or (at your option) any later version.
7.13 + *
7.14 + * This program is distributed in the hope that it will be useful,
7.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
7.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7.17 + * GNU General Public License for more details.
7.18 + *
7.19 + * You should have received a copy of the GNU General Public License
7.20 + * along with this program; if not, write to the Free Software
7.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
7.22 + * Boston, MA 02110-1301, USA
7.23 + */
7.24 +
7.25 +#include <l4/devices/dma-jz4730.h>
7.26 +#include <l4/devices/hw_mmio_register_block.h>
7.27 +
7.28 +#include <l4/sys/icu.h>
7.29 +#include <l4/sys/ipc.h>
7.30 +#include <l4/sys/irq.h>
7.31 +#include <l4/util/util.h>
7.32 +
7.33 +#include <cstdio>
7.34 +
7.35 +enum Global_regs
7.36 +{
7.37 + Dma_irq_pending = 0xf8, // IRQP
7.38 + Dma_control = 0xfc, // DMAC
7.39 +};
7.40 +
7.41 +enum Channel_regs
7.42 +{
7.43 + Dma_source = 0x00, // DSA
7.44 + Dma_destination = 0x04, // DDA
7.45 + Dma_transfer_count = 0x08, // DTC
7.46 + Dma_request_source = 0x0c, // DRT
7.47 + Dma_control_status = 0x10, // DCS
7.48 +};
7.49 +
7.50 +enum Dma_irq_pending_shifts : unsigned
7.51 +{
7.52 + Dma_irq_pending_ch0 = 15,
7.53 + Dma_irq_pending_ch1 = 14,
7.54 + Dma_irq_pending_ch2 = 13,
7.55 + Dma_irq_pending_ch3 = 12,
7.56 + Dma_irq_pending_ch4 = 11,
7.57 + Dma_irq_pending_ch5 = 10,
7.58 +};
7.59 +
7.60 +enum Dma_control_bits : unsigned
7.61 +{
7.62 + Dma_control_priority_mode = 0x100, // PM
7.63 + Dma_control_halt_occurred = 0x008, // HLT
7.64 + Dma_control_address_error = 0x004, // AR
7.65 + Dma_control_enable = 0x001, // DMAE
7.66 +};
7.67 +
7.68 +enum Dma_control_priority_modes : unsigned
7.69 +{
7.70 + Dma_priority_mode_01234567 = 0,
7.71 + Dma_priority_mode_02314675 = 1,
7.72 + Dma_priority_mode_20136457 = 2,
7.73 + Dma_priority_mode_round_robin = 3,
7.74 +};
7.75 +
7.76 +enum Dma_transfer_count_bits : unsigned
7.77 +{
7.78 + Dma_transfer_count_mask = 0x00ffffff,
7.79 +};
7.80 +
7.81 +enum Dma_request_source_bits : unsigned
7.82 +{
7.83 + Dma_request_type_mask = 0x0000001f,
7.84 +};
7.85 +
7.86 +enum Dma_control_status_shifts : unsigned
7.87 +{
7.88 + Dma_ext_output_polarity = 31,
7.89 + Dma_ext_output_mode_cycle = 30,
7.90 + Dma_ext_req_detect_mode = 28,
7.91 + Dma_ext_end_of_process_mode = 27,
7.92 + Dma_req_detect_int_length = 16,
7.93 + Dma_source_port_width = 14,
7.94 + Dma_dest_port_width = 12,
7.95 + Dma_trans_unit_size = 8,
7.96 + Dma_trans_mode = 7,
7.97 +};
7.98 +
7.99 +enum Dma_control_status_bits : unsigned
7.100 +{
7.101 + Dma_source_address_incr = 0x00800000,
7.102 + Dma_dest_address_incr = 0x00400000,
7.103 + Dma_address_error = 0x00000010,
7.104 + Dma_trans_completed = 0x00000008,
7.105 + Dma_trans_halted = 0x00000004,
7.106 + Dma_channel_irq_enable = 0x00000002,
7.107 + Dma_channel_enable = 0x00000001,
7.108 +};
7.109 +
7.110 +enum Dma_port_width_values : unsigned
7.111 +{
7.112 + Dma_port_width_32_bit = 0,
7.113 + Dma_port_width_8_bit = 1,
7.114 + Dma_port_width_16_bit = 2,
7.115 +};
7.116 +
7.117 +enum Dma_trans_mode_values : unsigned
7.118 +{
7.119 + Dma_trans_mode_single = 0,
7.120 + Dma_trans_mode_block = 1,
7.121 +};
7.122 +
7.123 +
7.124 +
7.125 +// Initialise a channel.
7.126 +
7.127 +Dma_jz4730_channel::Dma_jz4730_channel(Dma_jz4730_chip *chip, uint8_t channel,
7.128 + l4_addr_t start, l4_cap_idx_t irq)
7.129 +: _chip(chip), _channel(channel), _irq(irq)
7.130 +{
7.131 + _regs = new Hw::Mmio_register_block<32>(start);
7.132 +}
7.133 +
7.134 +// Encode flags for an external transfer.
7.135 +
7.136 +uint32_t
7.137 +Dma_jz4730_channel::encode_external_transfer(enum Dma_jz4730_request_type type)
7.138 +{
7.139 + int external = (type == Dma_request_external) ? 1 : 0;
7.140 +
7.141 + return
7.142 + ((external ? (int) _ext_output_polarity : 0) << Dma_ext_output_polarity) |
7.143 + ((external ? (int) _ext_output_mode_cycle : 0) << Dma_ext_output_mode_cycle) |
7.144 + ((external ? (int) _ext_req_detect_mode : 0) << Dma_ext_req_detect_mode) |
7.145 + ((external ? (int) _ext_end_of_process_mode : 0) << Dma_ext_end_of_process_mode);
7.146 +}
7.147 +
7.148 +// Encode the appropriate source address increment for the given request type.
7.149 +// Here, memory-to-memory transfers and transfers to peripherals involve an
7.150 +// incrementing source address. Transfers from peripherals involve a static
7.151 +// source address.
7.152 +
7.153 +uint32_t
7.154 +Dma_jz4730_channel::encode_source_address_increment(enum Dma_jz4730_request_type type)
7.155 +{
7.156 + switch (type)
7.157 + {
7.158 + case Dma_request_auto:
7.159 + case Dma_request_pcmcia_out:
7.160 + case Dma_request_des_out:
7.161 + case Dma_request_uart3_out:
7.162 + case Dma_request_uart2_out:
7.163 + case Dma_request_uart1_out:
7.164 + case Dma_request_uart0_out:
7.165 + case Dma_request_ssi_send_empty:
7.166 + case Dma_request_aic_send_empty:
7.167 + case Dma_request_msc_send_empty:
7.168 + case Dma_request_ost2_underflow:
7.169 + return Dma_source_address_incr;
7.170 +
7.171 + default:
7.172 + return 0;
7.173 + }
7.174 +}
7.175 +
7.176 +// Encode the appropriate destination address increment for the given request
7.177 +// type. Here, memory-to-memory transfers and transfers from peripherals involve
7.178 +// an incrementing destination address. Transfers to peripherals involve a static
7.179 +// destination address.
7.180 +
7.181 +uint32_t
7.182 +Dma_jz4730_channel::encode_destination_address_increment(enum Dma_jz4730_request_type type)
7.183 +{
7.184 + switch (type)
7.185 + {
7.186 + case Dma_request_auto:
7.187 + case Dma_request_pcmcia_in:
7.188 + case Dma_request_des_in:
7.189 + case Dma_request_uart3_in:
7.190 + case Dma_request_uart2_in:
7.191 + case Dma_request_uart1_in:
7.192 + case Dma_request_uart0_in:
7.193 + case Dma_request_ssi_recv_full:
7.194 + case Dma_request_aic_recv_full:
7.195 + case Dma_request_msc_recv_full:
7.196 + case Dma_request_ost2_underflow:
7.197 + return Dma_dest_address_incr;
7.198 +
7.199 + default:
7.200 + return 0;
7.201 + }
7.202 +}
7.203 +
7.204 +// Return the closest interval length greater than or equal to the number of
7.205 +// units given encoded in the request detection interval length field of the
7.206 +// control/status register.
7.207 +
7.208 +uint32_t
7.209 +Dma_jz4730_channel::encode_req_detect_int_length(uint8_t units)
7.210 +{
7.211 + static uint8_t lengths[] = {0, 2, 4, 8, 12, 16, 20, 24, 28, 32, 48, 60, 64, 124, 128, 200};
7.212 + int i;
7.213 +
7.214 + if (!units)
7.215 + return 0;
7.216 +
7.217 + for (i = 0; i < 15; i++)
7.218 + {
7.219 + if (lengths[i++] >= units)
7.220 + break;
7.221 + }
7.222 +
7.223 + return lengths[i] << Dma_req_detect_int_length;
7.224 +}
7.225 +
7.226 +// Encode the appropriate source port width for the given request type.
7.227 +
7.228 +uint32_t
7.229 +Dma_jz4730_channel::encode_source_port_width(enum Dma_jz4730_request_type type)
7.230 +{
7.231 + switch (type)
7.232 + {
7.233 + case Dma_request_uart3_in:
7.234 + case Dma_request_uart2_in:
7.235 + case Dma_request_uart1_in:
7.236 + case Dma_request_uart0_in:
7.237 + return Dma_port_width_8_bit << Dma_source_port_width;
7.238 +
7.239 + default:
7.240 + return Dma_port_width_32_bit << Dma_source_port_width;
7.241 + }
7.242 +}
7.243 +
7.244 +// Encode the appropriate destination port width for the given request type.
7.245 +
7.246 +uint32_t
7.247 +Dma_jz4730_channel::encode_destination_port_width(enum Dma_jz4730_request_type type)
7.248 +{
7.249 + switch (type)
7.250 + {
7.251 + case Dma_request_uart3_out:
7.252 + case Dma_request_uart2_out:
7.253 + case Dma_request_uart1_out:
7.254 + case Dma_request_uart0_out:
7.255 + return Dma_port_width_8_bit << Dma_dest_port_width;
7.256 +
7.257 + default:
7.258 + return Dma_port_width_32_bit << Dma_dest_port_width;
7.259 + }
7.260 +}
7.261 +
7.262 +// Transfer data between memory locations.
7.263 +
7.264 +unsigned int
7.265 +Dma_jz4730_channel::transfer(uint32_t source, uint32_t destination,
7.266 + unsigned int count,
7.267 + enum Dma_jz4730_trans_unit_size size,
7.268 + enum Dma_jz4730_request_type type)
7.269 +{
7.270 + // Ensure an absence of address error and halt conditions globally and in this channel.
7.271 +
7.272 + if (error() || halted())
7.273 + return 0;
7.274 +
7.275 + // Ensure an absence of transaction completed and zero transfer count for this channel.
7.276 +
7.277 + if (completed() || _regs[Dma_transfer_count])
7.278 + return 0;
7.279 +
7.280 + // Disable the channel.
7.281 +
7.282 + _regs[Dma_control_status] = _regs[Dma_control_status] & ~Dma_channel_enable;
7.283 +
7.284 + // Set addresses.
7.285 +
7.286 + _regs[Dma_source] = source;
7.287 + _regs[Dma_destination] = destination;
7.288 +
7.289 + // Set transfer count to the number of units.
7.290 +
7.291 + _regs[Dma_transfer_count] = count;
7.292 +
7.293 + // Set auto-request for memory-to-memory transfers. Otherwise, set the
7.294 + // indicated request type.
7.295 +
7.296 + _regs[Dma_request_source] = type;
7.297 +
7.298 + // Set control/status fields.
7.299 + // Enable the channel (and peripheral).
7.300 +
7.301 + /* NOTE: To be considered...
7.302 + * request detection interval length (currently left as 0)
7.303 + * increments and port widths for external transfers
7.304 + * port width overriding (for AIC...)
7.305 + * transfer mode (currently left as single)
7.306 + */
7.307 +
7.308 + _regs[Dma_control_status] = encode_external_transfer(type) |
7.309 + encode_source_address_increment(type) |
7.310 + encode_destination_address_increment(type) |
7.311 + encode_source_port_width(type) |
7.312 + encode_destination_port_width(type) |
7.313 + (size << Dma_trans_unit_size) |
7.314 + (Dma_trans_mode_single << Dma_trans_mode) |
7.315 + Dma_channel_irq_enable |
7.316 + Dma_channel_enable;
7.317 +
7.318 + // An interrupt will occur upon completion, the completion flag will be set
7.319 + // and the transfer count will be zero.
7.320 +
7.321 + unsigned int remaining = count;
7.322 +
7.323 + do
7.324 + {
7.325 + if (!wait_for_irq(1000000))
7.326 + printf("status = %x\n", (uint32_t) _regs[Dma_control_status]);
7.327 +
7.328 + // Clearing the completion flag will clear the interrupt condition.
7.329 + // Any remaining units must be read before clearing the condition.
7.330 +
7.331 + else
7.332 + {
7.333 + remaining = _regs[Dma_transfer_count];
7.334 + ack_irq();
7.335 + break;
7.336 + }
7.337 + }
7.338 + while (!error() && !halted() && !completed());
7.339 +
7.340 + // Return the number of transferred units.
7.341 +
7.342 + return count - remaining;
7.343 +}
7.344 +
7.345 +// Wait indefinitely for an interrupt request, returning true if one was delivered.
7.346 +
7.347 +bool
7.348 +Dma_jz4730_channel::wait_for_irq()
7.349 +{
7.350 + return !l4_error(l4_irq_receive(_irq, L4_IPC_NEVER)) && _chip->have_interrupt(_channel);
7.351 +}
7.352 +
7.353 +// Wait up to the given timeout (in microseconds) for an interrupt request,
7.354 +// returning true if one was delivered.
7.355 +
7.356 +bool
7.357 +Dma_jz4730_channel::wait_for_irq(unsigned int timeout)
7.358 +{
7.359 + return !l4_error(l4_irq_receive(_irq, l4_timeout(L4_IPC_TIMEOUT_NEVER, l4util_micros2l4to(timeout)))) && _chip->have_interrupt(_channel);
7.360 +}
7.361 +
7.362 +// Acknowledge an interrupt condition.
7.363 +
7.364 +void
7.365 +Dma_jz4730_channel::ack_irq()
7.366 +{
7.367 + _regs[Dma_control_status] = _regs[Dma_control_status] & ~Dma_trans_completed;
7.368 +}
7.369 +
7.370 +// Return whether a transfer has completed.
7.371 +
7.372 +bool
7.373 +Dma_jz4730_channel::completed()
7.374 +{
7.375 + return _regs[Dma_control_status] & Dma_trans_completed ? true : false;
7.376 +}
7.377 +
7.378 +// Return whether an address error condition has arisen.
7.379 +
7.380 +bool
7.381 +Dma_jz4730_channel::error()
7.382 +{
7.383 + return _regs[Dma_control_status] & Dma_address_error ? true : false;
7.384 +}
7.385 +
7.386 +// Return whether a transfer has halted.
7.387 +
7.388 +bool
7.389 +Dma_jz4730_channel::halted()
7.390 +{
7.391 + return _regs[Dma_control_status] & Dma_trans_halted ? true : false;
7.392 +}
7.393 +
7.394 +
7.395 +
7.396 +// Initialise the I2C controller.
7.397 +
7.398 +Dma_jz4730_chip::Dma_jz4730_chip(l4_addr_t start, l4_addr_t end,
7.399 + Cpm_jz4730_chip *cpm)
7.400 +: _start(start), _end(end), _cpm(cpm)
7.401 +{
7.402 + _regs = new Hw::Mmio_register_block<32>(start);
7.403 +}
7.404 +
7.405 +// Enable the peripheral.
7.406 +
7.407 +void
7.408 +Dma_jz4730_chip::enable()
7.409 +{
7.410 + // Make sure that the DMA clock is available.
7.411 +
7.412 + _cpm->start_dma();
7.413 +
7.414 + // Enable the channel.
7.415 + // NOTE: No configuration is done for channel priority mode.
7.416 +
7.417 + _regs[Dma_control] = Dma_control_enable;
7.418 + while (!(_regs[Dma_control] & Dma_control_enable));
7.419 +}
7.420 +
7.421 +// Disable the channel.
7.422 +
7.423 +void
7.424 +Dma_jz4730_chip::disable()
7.425 +{
7.426 + _regs[Dma_control] = 0;
7.427 + while (_regs[Dma_control] & Dma_control_enable);
7.428 +}
7.429 +
7.430 +// Obtain a channel object. Only one channel is supported.
7.431 +
7.432 +Dma_jz4730_channel *
7.433 +Dma_jz4730_chip::get_channel(uint8_t channel, l4_cap_idx_t irq)
7.434 +{
7.435 + if (channel < 6)
7.436 + return new Dma_jz4730_channel(this, channel, _start + 0x20 * channel, irq);
7.437 + else
7.438 + throw -L4_EINVAL;
7.439 +}
7.440 +
7.441 +// Return whether an interrupt is pending on the given channel.
7.442 +
7.443 +bool
7.444 +Dma_jz4730_chip::have_interrupt(uint8_t channel)
7.445 +{
7.446 + return _regs[Dma_irq_pending] & (1 << (Dma_irq_pending_ch0 - channel)) ? true : false;
7.447 +}
7.448 +
7.449 +
7.450 +
7.451 +// C language interface functions.
7.452 +
7.453 +void *jz4730_dma_init(l4_addr_t start, l4_addr_t end, void *cpm)
7.454 +{
7.455 + return (void *) new Dma_jz4730_chip(start, end, static_cast<Cpm_jz4730_chip *>(cpm));
7.456 +}
7.457 +
7.458 +void jz4730_dma_disable(void *dma_chip)
7.459 +{
7.460 + static_cast<Dma_jz4730_chip *>(dma_chip)->disable();
7.461 +}
7.462 +
7.463 +void jz4730_dma_enable(void *dma_chip)
7.464 +{
7.465 + static_cast<Dma_jz4730_chip *>(dma_chip)->enable();
7.466 +}
7.467 +
7.468 +void *jz4730_dma_get_channel(void *dma, uint8_t channel, l4_cap_idx_t irq)
7.469 +{
7.470 + return static_cast<Dma_jz4730_chip *>(dma)->get_channel(channel, irq);
7.471 +}
7.472 +
7.473 +void jz4730_dma_set_output_polarity(void *dma_channel, enum Dma_jz4730_ext_level polarity)
7.474 +{
7.475 + static_cast<Dma_jz4730_channel *>(dma_channel)->set_output_polarity(polarity);
7.476 +}
7.477 +
7.478 +void jz4730_dma_set_end_of_process_mode(void *dma_channel, enum Dma_jz4730_ext_level mode)
7.479 +{
7.480 + static_cast<Dma_jz4730_channel *>(dma_channel)->set_end_of_process_mode(mode);
7.481 +}
7.482 +
7.483 +void jz4730_dma_set_output_mode_cycle(void *dma_channel, enum Dma_jz4730_ext_output_mode_cycle cycle)
7.484 +{
7.485 + static_cast<Dma_jz4730_channel *>(dma_channel)->set_output_mode_cycle(cycle);
7.486 +}
7.487 +
7.488 +void jz4730_dma_set_req_detect_mode(void *dma_channel, enum Dma_jz4730_ext_req_detect_mode mode)
7.489 +{
7.490 + static_cast<Dma_jz4730_channel *>(dma_channel)->set_req_detect_mode(mode);
7.491 +}
7.492 +
7.493 +unsigned int jz4730_dma_transfer(void *dma_channel, uint32_t source,
7.494 + uint32_t destination, unsigned int count,
7.495 + enum Dma_jz4730_trans_unit_size size,
7.496 + enum Dma_jz4730_request_type type)
7.497 +{
7.498 + return static_cast<Dma_jz4730_channel *>(dma_channel)->transfer(source, destination, count, size, type);
7.499 +}
8.1 --- a/pkg/devices/lib/i2c/src/jz4730.cc Wed Jan 06 23:54:45 2021 +0100
8.2 +++ b/pkg/devices/lib/i2c/src/jz4730.cc Sat Jan 16 23:00:45 2021 +0100
8.3 @@ -138,6 +138,10 @@
8.4 bool
8.5 I2c_jz4730_channel::set_address(uint8_t address, bool read)
8.6 {
8.7 + // Waiting for long enough may eliminate a busy condition and thus permit a
8.8 + // new transaction. 10ms appears to be long enough, whereas 1ms does not
8.9 + // appear to be. In case this is insufficient, permit failure.
8.10 +
8.11 unsigned int limit = 10;
8.12
8.13 do
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/pkg/landfall-examples/letux400_dma/Makefile Sat Jan 16 23:00:45 2021 +0100
9.3 @@ -0,0 +1,10 @@
9.4 +PKGDIR ?= ..
9.5 +L4DIR ?= $(PKGDIR)/../..
9.6 +
9.7 +TARGET = ex_letux400_dma
9.8 +
9.9 +SRC_CC = letux400_dma.cc
9.10 +
9.11 +REQUIRES_LIBS = l4re_c-util libdrivers-cpm libdrivers-dma libdevice-util
9.12 +
9.13 +include $(L4DIR)/mk/prog.mk
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/pkg/landfall-examples/letux400_dma/letux400_dma.cc Sat Jan 16 23:00:45 2021 +0100
10.3 @@ -0,0 +1,226 @@
10.4 +/*
10.5 + * Test DMA transfers.
10.6 + *
10.7 + * Copyright (C) 2018, 2020, 2021 Paul Boddie <paul@boddie.org.uk>
10.8 + *
10.9 + * This program is free software; you can redistribute it and/or
10.10 + * modify it under the terms of the GNU General Public License as
10.11 + * published by the Free Software Foundation; either version 2 of
10.12 + * the License, or (at your option) any later version.
10.13 + *
10.14 + * This program is distributed in the hope that it will be useful,
10.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
10.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10.17 + * GNU General Public License for more details.
10.18 + *
10.19 + * You should have received a copy of the GNU General Public License
10.20 + * along with this program; if not, write to the Free Software
10.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
10.22 + * Boston, MA 02110-1301, USA
10.23 + */
10.24 +
10.25 +#include <l4/devices/cpm-jz4730.h>
10.26 +#include <l4/devices/dma-jz4730.h>
10.27 +#include <l4/devices/memory.h>
10.28 +
10.29 +#include <l4/re/c/util/cap_alloc.h>
10.30 +#include <l4/re/c/dataspace.h>
10.31 +#include <l4/re/c/mem_alloc.h>
10.32 +#include <l4/re/c/rm.h>
10.33 +
10.34 +#include <l4/sys/factory.h>
10.35 +#include <l4/sys/icu.h>
10.36 +#include <l4/sys/irq.h>
10.37 +#include <l4/sys/rcv_endpoint.h>
10.38 +
10.39 +#include <stdio.h>
10.40 +#include <string.h>
10.41 +#include <unistd.h>
10.42 +
10.43 +
10.44 +
10.45 +/* Device and resource discovery. */
10.46 +
10.47 +static long item_in_range(long start, long end, long index)
10.48 +{
10.49 + if (start < end)
10.50 + return start + index;
10.51 + else
10.52 + return start - index;
10.53 +}
10.54 +
10.55 +
10.56 +
10.57 +int main(void)
10.58 +{
10.59 + void *cpm;
10.60 + void *dma, *dma0;
10.61 +
10.62 + /* Allocate memory to test transfers. */
10.63 +
10.64 + l4_cap_idx_t ds0_mem, ds1_mem;
10.65 + l4_size_t ds0_size = L4_PAGESIZE, ds0_psize, ds1_size = L4_PAGESIZE, ds1_psize;
10.66 + l4_addr_t ds0_addr, ds0_paddr, ds1_addr, ds1_paddr;
10.67 +
10.68 + ds0_mem = l4re_util_cap_alloc();
10.69 + ds1_mem = l4re_util_cap_alloc();
10.70 +
10.71 + if (l4_is_invalid_cap(ds0_mem) || l4_is_invalid_cap(ds1_mem))
10.72 + {
10.73 + printf("Could not allocate memory capabilities.\n");
10.74 + return 1;
10.75 + }
10.76 +
10.77 + if (l4re_ma_alloc_align(ds0_size, ds0_mem, L4RE_MA_CONTINUOUS | L4RE_MA_PINNED, 8) ||
10.78 + l4re_ma_alloc_align(ds1_size, ds1_mem, L4RE_MA_CONTINUOUS | L4RE_MA_PINNED, 8))
10.79 + {
10.80 + printf("Could not allocate memory.\n");
10.81 + return 1;
10.82 + }
10.83 +
10.84 + if (l4re_rm_attach((void **) &ds0_addr, ds0_size,
10.85 + L4RE_RM_SEARCH_ADDR | L4RE_RM_EAGER_MAP,
10.86 + ds0_mem, 0, L4_PAGESHIFT) ||
10.87 + l4re_rm_attach((void **) &ds1_addr, ds1_size,
10.88 + L4RE_RM_SEARCH_ADDR | L4RE_RM_EAGER_MAP,
10.89 + ds1_mem, 0, L4_PAGESHIFT))
10.90 + {
10.91 + printf("Could not map memory.\n");
10.92 + return 1;
10.93 + }
10.94 +
10.95 + if (l4re_ds_phys(ds0_mem, 0, &ds0_paddr, &ds0_psize) ||
10.96 + l4re_ds_phys(ds1_mem, 0, &ds1_paddr, &ds1_psize))
10.97 + {
10.98 + printf("Could not get physical addresses for memory.\n");
10.99 + return 1;
10.100 + }
10.101 +
10.102 + /* Fill the allocated memory. */
10.103 +
10.104 + memset((void *) ds0_addr, 0, ds0_size);
10.105 + memset((void *) ds1_addr, 0, ds1_size);
10.106 +
10.107 + sprintf((char *) ds0_addr, "The quick brown fox jumped over the lazy dog.\n");
10.108 +
10.109 + /* Interrupts. */
10.110 +
10.111 + l4_uint32_t dma_irq_start = 0, dma_irq_end = 0;
10.112 + l4_cap_idx_t icucap, irq0cap;
10.113 +
10.114 + /* Obtain resource details describing the interrupt for DMA channel 0. */
10.115 +
10.116 + printf("Access IRQ...\n");
10.117 +
10.118 + if (get_irq("jz4730-dma", &dma_irq_start, &dma_irq_end) < 0)
10.119 + return 1;
10.120 +
10.121 + printf("IRQ range at %d...%d.\n", dma_irq_start, dma_irq_end);
10.122 +
10.123 + /* Obtain capabilities for the interrupt controller and an interrupt. */
10.124 +
10.125 + irq0cap = l4re_util_cap_alloc();
10.126 + icucap = l4re_env_get_cap("icu");
10.127 +
10.128 + if (l4_is_invalid_cap(icucap))
10.129 + {
10.130 + printf("No 'icu' capability available in the virtual bus.\n");
10.131 + return 1;
10.132 + }
10.133 +
10.134 + if (l4_is_invalid_cap(irq0cap))
10.135 + {
10.136 + printf("Capabilities not available for interrupts.\n");
10.137 + return 1;
10.138 + }
10.139 +
10.140 + /* Create interrupt objects. */
10.141 +
10.142 + long err;
10.143 +
10.144 + err = l4_error(l4_factory_create_irq(l4re_global_env->factory, irq0cap));
10.145 +
10.146 + if (err)
10.147 + {
10.148 + printf("Could not create IRQ object: %lx\n", err);
10.149 + return 1;
10.150 + }
10.151 +
10.152 + /* Bind interrupt objects to IRQ numbers. */
10.153 +
10.154 + err = l4_error(l4_icu_bind(icucap,
10.155 + item_in_range(dma_irq_start, dma_irq_end, 0),
10.156 + irq0cap));
10.157 +
10.158 + if (err)
10.159 + {
10.160 + printf("Could not bind IRQ to the ICU: %ld\n", err);
10.161 + return 1;
10.162 + }
10.163 +
10.164 + /* Attach ourselves to the interrupt handler. */
10.165 +
10.166 + err = l4_error(l4_rcv_ep_bind_thread(irq0cap, l4re_env()->main_thread, 0));
10.167 +
10.168 + if (err)
10.169 + {
10.170 + printf("Could not attach to IRQs: %ld\n", err);
10.171 + return 1;
10.172 + }
10.173 +
10.174 + /* Peripheral memory. */
10.175 +
10.176 + l4_addr_t cpm_base = 0, cpm_base_end = 0;
10.177 + l4_addr_t dma_base = 0, dma_base_end = 0;
10.178 +
10.179 + /* Obtain resource details describing I/O memory. */
10.180 +
10.181 + printf("Access CPM...\n");
10.182 +
10.183 + if (get_memory("jz4730-cpm", &cpm_base, &cpm_base_end) < 0)
10.184 + return 1;
10.185 +
10.186 + printf("CPM at 0x%lx...0x%lx.\n", cpm_base, cpm_base_end);
10.187 +
10.188 + printf("Access DMA...\n");
10.189 +
10.190 + if (get_memory("jz4730-dma", &dma_base, &dma_base_end) < 0)
10.191 + return 1;
10.192 +
10.193 + printf("DMA at 0x%lx...0x%lx.\n", dma_base, dma_base_end);
10.194 +
10.195 + /* Obtain CPM and DMA references. */
10.196 +
10.197 + cpm = jz4730_cpm_init(cpm_base);
10.198 + dma = jz4730_dma_init(dma_base, dma_base_end, cpm);
10.199 + dma0 = jz4730_dma_get_channel(dma, 0, irq0cap);
10.200 +
10.201 + /* Enable DMA. */
10.202 +
10.203 + printf("Enable DMA...\n");
10.204 +
10.205 + jz4730_dma_enable(dma);
10.206 +
10.207 + /* Transfer data between the allocated memory regions. */
10.208 +
10.209 + printf("Transfer from %lx to %lx...\n", ds0_paddr, ds1_paddr);
10.210 +
10.211 + unsigned int ntransferred = jz4730_dma_transfer(dma0, (uint32_t) ds0_paddr,
10.212 + (uint32_t) ds1_paddr,
10.213 + L4_PAGESIZE / 4,
10.214 + Dma_trans_unit_size_32_bit,
10.215 + Dma_request_auto);
10.216 +
10.217 + printf("Transferred: %d\n", ntransferred);
10.218 + printf("Source: %s\n", (char *) ds0_addr);
10.219 + printf("Destination: %s\n", (char *) ds1_addr);
10.220 +
10.221 + /* Detach from the interrupt. */
10.222 +
10.223 + err = l4_error(l4_irq_detach(irq0cap));
10.224 +
10.225 + if (err)
10.226 + printf("Error detaching from IRQ objects: %ld\n", err);
10.227 +
10.228 + return 0;
10.229 +}