1.1 --- a/pkg/devices/Control Fri Sep 22 21:56:34 2023 +0200
1.2 +++ b/pkg/devices/Control Tue Oct 24 18:52:06 2023 +0200
1.3 @@ -21,6 +21,7 @@
1.4 provides: libdevice-lcd
1.5 provides: libdevice-lcd-jz4740
1.6 provides: libdevice-util
1.7 +provides: libdrivers-aic
1.8 provides: libdrivers-common
1.9 provides: libdrivers-cpm
1.10 provides: libdrivers-dma
1.11 @@ -39,5 +40,6 @@
1.12 provides: libdrivers-panel-loader
1.13 provides: libdrivers-panel-qi_lb60
1.14 provides: libdrivers-pwm
1.15 +provides: libdrivers-spi
1.16 requires: libc libc_be_l4re libdl l4re_c libio libipc
1.17 Maintainer: paul@boddie.org.uk
2.1 --- a/pkg/devices/include/clocks.h Fri Sep 22 21:56:34 2023 +0200
2.2 +++ b/pkg/devices/include/clocks.h Tue Oct 24 18:52:06 2023 +0200
2.3 @@ -27,6 +27,7 @@
2.4
2.5 enum Clock_identifiers
2.6 {
2.7 + Clock_audio,
2.8 Clock_aic_bitclk,
2.9 Clock_aic_pclk,
2.10 Clock_can0,
2.11 @@ -44,9 +45,12 @@
2.12 Clock_i2c,
2.13 Clock_i2c0,
2.14 Clock_i2c1,
2.15 - Clock_i2s,
2.16 + Clock_i2s0,
2.17 Clock_i2s0_rx,
2.18 Clock_i2s0_tx,
2.19 + Clock_i2s1,
2.20 + Clock_i2s1_rx,
2.21 + Clock_i2s1_tx,
2.22 Clock_kbc,
2.23 Clock_lcd,
2.24 Clock_lcd_pixel,
3.1 --- a/pkg/devices/lcd/src/jz4740/lcd-jz4740-device.cc Fri Sep 22 21:56:34 2023 +0200
3.2 +++ b/pkg/devices/lcd/src/jz4740/lcd-jz4740-device.cc Tue Oct 24 18:52:06 2023 +0200
3.3 @@ -19,6 +19,7 @@
3.4 * Boston, MA 02110-1301, USA
3.5 */
3.6
3.7 +#include <l4/devices/dma.h>
3.8 #include <l4/devices/lcd-jz4740.h>
3.9 #include <l4/devices/lcd-jz4780.h>
3.10 #include <l4/devices/panel-loader.h>
3.11 @@ -26,13 +27,8 @@
3.12 #include "lcd-jz4740-device.h"
3.13
3.14 #include <l4/re/c/dataspace.h>
3.15 -#include <l4/re/c/dma_space.h>
3.16 -#include <l4/re/c/mem_alloc.h>
3.17 #include <l4/re/env.h>
3.18 -#include <l4/re/protocols.h>
3.19 -#include <l4/sys/factory.h>
3.20 #include <l4/sys/types.h>
3.21 -#include <l4/vbus/vbus.h>
3.22
3.23 #include <ipc/cap_alloc.h>
3.24 #include <ipc/mem_ipc.h>
3.25 @@ -124,100 +120,35 @@
3.26 int
3.27 Lcd_jz4740_device::_setup_memory()
3.28 {
3.29 - // Framebuffer and descriptor sizes.
3.30 -
3.31 - unsigned long fb_size, desc_size;
3.32 -
3.33 - // Size of physically contiguous regions to be allocated.
3.34 -
3.35 - l4_size_t fb_size_out, desc_size_out;
3.36 -
3.37 - // Memory allocation capabilities.
3.38 -
3.39 - l4_cap_idx_t descmem, dma, vbus;
3.40 -
3.41 // Test for existing setup.
3.42
3.43 if (fb_vaddr)
3.44 return 0;
3.45
3.46 - // Create the DMA space.
3.47 -
3.48 - dma = ipc_cap_alloc();
3.49 -
3.50 - if (l4_is_invalid_cap(dma))
3.51 - return 1;
3.52 -
3.53 - vbus = l4re_env_get_cap("vbus");
3.54 -
3.55 - if (l4_is_invalid_cap(vbus))
3.56 - return 1;
3.57 -
3.58 - if (l4_error(l4_factory_create(l4re_env()->mem_alloc, L4RE_PROTO_DMA_SPACE, dma)))
3.59 - return 1;
3.60 -
3.61 - l4vbus_device_handle_t device = L4VBUS_NULL;
3.62 - l4vbus_resource_t dma_resource;
3.63 -
3.64 - if (!find_resource(&device, &dma_resource, L4VBUS_RESOURCE_DMA_DOMAIN))
3.65 - return 1;
3.66 -
3.67 - if (l4vbus_assign_dma_domain(vbus, dma_resource.start,
3.68 - L4VBUS_DMAD_BIND | L4VBUS_DMAD_L4RE_DMA_SPACE,
3.69 - dma))
3.70 - return 1;
3.71 -
3.72 // Obtain the memory requirements.
3.73
3.74 Lcd_jz4740_chip *chip = static_cast<Lcd_jz4740_chip *>(_chip);
3.75
3.76 - fb_size = chip->get_screen_size();
3.77 - desc_size = chip->get_descriptors_size();
3.78 + // Framebuffer and descriptor sizes.
3.79 +
3.80 + unsigned long fb_size = chip->get_screen_size(),
3.81 + desc_size = chip->get_descriptors_size();
3.82
3.83 // Allocate memory for the framebuffer at 2**6 == 64 byte == 16 word alignment,
3.84 // also for the descriptors.
3.85 // NOTE: A 64 word burst mode is available on the JZ4780 that would
3.86 // NOTE: necessitate 64 word alignment for the framebuffer.
3.87
3.88 - const l4_size_t alloc_flags = L4RE_MA_CONTINUOUS | L4RE_MA_PINNED;
3.89 - const l4re_rm_flags_t attach_flags = L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_RW;
3.90 -
3.91 - // Map the allocated memory, obtaining virtual addresses.
3.92 -
3.93 - fb_vaddr = 0;
3.94 - desc_vaddr = 0;
3.95 + long err = get_dma_region(fb_size, 8, &fb_vaddr, &fb_paddr, &_fbmem);
3.96
3.97 - if (ipc_new_dataspace(fb_size, alloc_flags, 8, &_fbmem))
3.98 - return 1;
3.99 -
3.100 - if (ipc_new_dataspace(desc_size, alloc_flags, 6, &descmem))
3.101 - return 1;
3.102 -
3.103 - if (ipc_attach_dataspace_align(_fbmem, fb_size, attach_flags, 8, (void **) &fb_vaddr))
3.104 - return 1;
3.105 -
3.106 - if (ipc_attach_dataspace_align(descmem, desc_size, attach_flags, 6, (void **) &desc_vaddr))
3.107 + if (err)
3.108 return 1;
3.109
3.110 - // Obtain physical addresses for the framebuffer and descriptors.
3.111 -
3.112 - fb_paddr = 0;
3.113 - desc_paddr = 0;
3.114 -
3.115 - fb_size_out = fb_size;
3.116 - desc_size_out = desc_size;
3.117 + l4_cap_idx_t descmem;
3.118
3.119 - if (l4re_dma_space_map(dma, _fbmem | L4_CAP_FPAGE_RW, 0, &fb_size_out, 0,
3.120 - L4RE_DMA_SPACE_TO_DEVICE, &fb_paddr))
3.121 - return 1;
3.122 + err = get_dma_region(desc_size, 6, &desc_vaddr, &desc_paddr, &descmem);
3.123
3.124 - if (l4re_dma_space_map(dma, descmem | L4_CAP_FPAGE_RW, 0, &desc_size_out, 0,
3.125 - L4RE_DMA_SPACE_TO_DEVICE, &desc_paddr))
3.126 - return 1;
3.127 -
3.128 - // Test the mapped region sizes.
3.129 -
3.130 - if ((fb_size_out != fb_size) || (desc_size_out != desc_size))
3.131 + if (err)
3.132 return 1;
3.133
3.134 return 0;
4.1 --- a/pkg/devices/lib/Makefile Fri Sep 22 21:56:34 2023 +0200
4.2 +++ b/pkg/devices/lib/Makefile Tue Oct 24 18:52:06 2023 +0200
4.3 @@ -1,10 +1,11 @@
4.4 PKGDIR ?= ..
4.5 L4DIR ?= $(PKGDIR)/../..
4.6
4.7 -TARGET := common cpm dma gpio hdmi i2c keypad lcd panel pwm
4.8 +TARGET := aic common cpm dma gpio hdmi i2c keypad lcd panel pwm spi
4.9
4.10 include $(L4DIR)/mk/subdir.mk
4.11
4.12 +aic: common
4.13 cpm: common
4.14 dma: common
4.15 gpio: common
4.16 @@ -14,3 +15,4 @@
4.17 lcd: common
4.18 panel: lcd
4.19 pwm: common
4.20 +spi: common
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/pkg/devices/lib/aic/Makefile Tue Oct 24 18:52:06 2023 +0200
5.3 @@ -0,0 +1,8 @@
5.4 +PKGDIR ?= ../..
5.5 +L4DIR ?= $(PKGDIR)/../..
5.6 +
5.7 +TARGET := include src
5.8 +
5.9 +include $(L4DIR)/mk/subdir.mk
5.10 +
5.11 +src: include
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/pkg/devices/lib/aic/include/Makefile Tue Oct 24 18:52:06 2023 +0200
6.3 @@ -0,0 +1,4 @@
6.4 +PKGDIR = ../../..
6.5 +L4DIR ?= $(PKGDIR)/../..
6.6 +
6.7 +include $(L4DIR)/mk/include.mk
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/pkg/devices/lib/aic/include/aic-x1600.h Tue Oct 24 18:52:06 2023 +0200
7.3 @@ -0,0 +1,106 @@
7.4 +/*
7.5 + * AIC support for the X1600.
7.6 + *
7.7 + * Copyright (C) 2023 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 +#pragma once
7.26 +
7.27 +#include <l4/re/c/dma_space.h>
7.28 +#include <l4/sys/types.h>
7.29 +#include <stdint.h>
7.30 +
7.31 +
7.32 +
7.33 +#ifdef __cplusplus
7.34 +
7.35 +#include <l4/devices/cpm-x1600.h>
7.36 +#include <l4/devices/dma-x1600.h>
7.37 +#include <l4/devices/hw_mmio_register_block.h>
7.38 +
7.39 +// AIC channel.
7.40 +
7.41 +class Aic_x1600_channel
7.42 +{
7.43 +private:
7.44 + l4_addr_t _aic_start;
7.45 + Hw::Register_block<32> _regs;
7.46 + enum Clock_identifiers _clock_rx, _clock_tx;
7.47 + Cpm_x1600_chip *_cpm;
7.48 + Dma_x1600_channel *_dma;
7.49 +
7.50 + // Buffer management.
7.51 +
7.52 + unsigned int _size = 0;
7.53 + l4_addr_t _vaddr = 0;
7.54 + l4re_dma_space_dma_addr_t _paddr = 0;
7.55 + l4_cap_idx_t _mem = L4_INVALID_CAP;
7.56 +
7.57 +public:
7.58 + Aic_x1600_channel(l4_addr_t aic_start, l4_addr_t start,
7.59 + enum Clock_identifiers clock_rx,
7.60 + enum Clock_identifiers clock_tx,
7.61 + Cpm_x1600_chip *cpm,
7.62 + Dma_x1600_channel *dma);
7.63 +
7.64 + long get_buffer(uint32_t count, l4_addr_t *addr);
7.65 + unsigned int transfer(uint32_t count, uint32_t sample_rate, uint8_t sample_size);
7.66 +
7.67 +private:
7.68 + void disable();
7.69 + void enable();
7.70 +
7.71 + void config();
7.72 + uint32_t encode_input_size(uint8_t sample_size);
7.73 + uint32_t encode_output_size(uint8_t sample_size);
7.74 + void set_divider(uint32_t divider, uint32_t mask, uint32_t limit, int bit);
7.75 + void set_recv_frequency(uint32_t sample_rate);
7.76 + void set_trans_frequency(uint32_t sample_rate);
7.77 +};
7.78 +
7.79 +// AIC device control.
7.80 +
7.81 +class Aic_x1600_chip
7.82 +{
7.83 +private:
7.84 + l4_addr_t _aic_start, _start, _end;
7.85 + Cpm_x1600_chip *_cpm;
7.86 +
7.87 +public:
7.88 + Aic_x1600_chip(l4_addr_t aic_start, l4_addr_t start, l4_addr_t end, Cpm_x1600_chip *cpm);
7.89 +
7.90 + Aic_x1600_channel *get_channel(uint8_t channel, Dma_x1600_channel *dma);
7.91 +};
7.92 +
7.93 +#endif /* __cplusplus */
7.94 +
7.95 +
7.96 +
7.97 +/* C language interface. */
7.98 +
7.99 +EXTERN_C_BEGIN
7.100 +
7.101 +void *x1600_aic_init(l4_addr_t aic_start, l4_addr_t start, l4_addr_t end, void *cpm);
7.102 +
7.103 +void *x1600_aic_get_channel(void *aic, uint8_t channel, void *dma);
7.104 +
7.105 +long x1600_aic_get_buffer(void *channel, uint32_t count, l4_addr_t *addr);
7.106 +
7.107 +unsigned int x1600_aic_transfer(void *channel, uint32_t count, uint32_t sample_rate, uint8_t sample_size);
7.108 +
7.109 +EXTERN_C_END
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/pkg/devices/lib/aic/src/Makefile Tue Oct 24 18:52:06 2023 +0200
8.3 @@ -0,0 +1,13 @@
8.4 +PKGDIR ?= ../../..
8.5 +L4DIR ?= $(PKGDIR)/../..
8.6 +
8.7 +TARGET = libaic.o.a libaic.o.so
8.8 +PC_FILENAME := libdrivers-aic
8.9 +
8.10 +SRC_CC := x1600.cc
8.11 +
8.12 +PRIVATE_INCDIR += $(PKGDIR)/lib/aic/include
8.13 +
8.14 +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-common libdrivers-cpm libdrivers-gpio
8.15 +
8.16 +include $(L4DIR)/mk/lib.mk
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/pkg/devices/lib/aic/src/x1600.cc Tue Oct 24 18:52:06 2023 +0200
9.3 @@ -0,0 +1,466 @@
9.4 +/*
9.5 + * AIC support for the X1600.
9.6 + *
9.7 + * Copyright (C) 2023 Paul Boddie <paul@boddie.org.uk>
9.8 + *
9.9 + * This program is free software; you can redistribute it and/or
9.10 + * modify it under the terms of the GNU General Public License as
9.11 + * published by the Free Software Foundation; either version 2 of
9.12 + * the License, or (at your option) any later version.
9.13 + *
9.14 + * This program is distributed in the hope that it will be useful,
9.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
9.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9.17 + * GNU General Public License for more details.
9.18 + *
9.19 + * You should have received a copy of the GNU General Public License
9.20 + * along with this program; if not, write to the Free Software
9.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
9.22 + * Boston, MA 02110-1301, USA
9.23 + */
9.24 +
9.25 +#include <l4/devices/aic-x1600.h>
9.26 +#include <l4/devices/dma.h>
9.27 +#include <l4/devices/hw_mmio_register_block.h>
9.28 +
9.29 +#include <l4/sys/icu.h>
9.30 +#include <l4/util/util.h>
9.31 +
9.32 +#include <stdio.h>
9.33 +
9.34 +enum Regs
9.35 +{
9.36 + Aic_config = 0x000, // AICFR
9.37 + Aic_control = 0x004, // AICCR
9.38 + Aic_i2s_msb_control = 0x010, // I2SCR
9.39 + Aic_fifo_status = 0x014, // AICSR
9.40 + Aic_i2s_msb_status = 0x01c, // I2SSR
9.41 + Aic_i2s_msb_divider = 0x030, // I2SDIV
9.42 + Aic_fifo_data = 0x034, // AICDR
9.43 + Aic_loop_data = 0x038, // AICLR
9.44 + Aic_tfifo_loop = 0x03c, // AICTFLR
9.45 +};
9.46 +
9.47 +enum Aic_config_bits : unsigned
9.48 +{
9.49 + Aic_enable_big_endian = 0x1000, // MSB
9.50 + Aic_independent_clock = 0x0100, // DMODE
9.51 + Aic_shared_clock = 0x0000, // DMODE
9.52 + Aic_last_sample_uflow = 0x0040, // LSMP
9.53 + Aic_select_i2s_msb = 0x0010, // AUSEL
9.54 + Aic_reset = 0x0008, // RST
9.55 + Aic_tmaster = 0x0004, // TMASTER
9.56 + Aic_rmaster = 0x0002, // RMASTER
9.57 + Aic_enable = 0x0001, // ENB
9.58 +
9.59 + Aic_rfifo_thold_bit = 24, // RFTH
9.60 + Aic_tfifo_thold_bit = 16, // TFTH
9.61 +};
9.62 +
9.63 +enum Aic_fifo_limits : unsigned
9.64 +{
9.65 + Aic_rfifo_max = 15,
9.66 + Aic_tfifo_max = 31,
9.67 +};
9.68 +
9.69 +enum Aic_control_bits : unsigned
9.70 +{
9.71 + Aic_enable_tfifo_loop_overrun = 0x80000000, // ETFLOR
9.72 + Aic_enable_tfifo_loop_request = 0x40000000, // ETFLS
9.73 + Aic_packed_data = 0x10000000, // PACK16
9.74 +
9.75 + Aic_channel_number_mask = 0x07000000, // CHANNEL
9.76 + Aic_channel_mono = 0x00000000,
9.77 + Aic_channel_stereo = 0x01000000,
9.78 +
9.79 + Aic_enable_tfifo_loop = 0x00800000, // ETFL
9.80 + Aic_enable_tfifo_loop_dma = 0x00400000, // TLDMS
9.81 +
9.82 + Aic_output_size_mask = 0x00380000, // OSS
9.83 + Aic_output_size_8bit = 0x00000000, // 0
9.84 + Aic_output_size_16bit = 0x00080000, // 1
9.85 + Aic_output_size_18bit = 0x00100000, // 2
9.86 + Aic_output_size_20bit = 0x00180000, // 3
9.87 + Aic_output_size_24bit = 0x00200000, // 4
9.88 +
9.89 + Aic_input_size_mask = 0x00070000, // ISS
9.90 + Aic_input_size_8bit = 0x00000000, // 0
9.91 + Aic_input_size_16bit = 0x00010000, // 1
9.92 + Aic_input_size_18bit = 0x00020000, // 2
9.93 + Aic_input_size_20bit = 0x00030000, // 3
9.94 + Aic_input_size_24bit = 0x00040000, // 4
9.95 +
9.96 + Aic_enable_recv_dma = 0x00008000, // RDMS
9.97 + Aic_enable_trans_dma = 0x00004000, // TDMS
9.98 +
9.99 + Aic_mono_control_mask = 0x00003000, // MONOCTR
9.100 + Aic_mono_control_both = 0x00000000, // 0
9.101 + Aic_mono_control_right = 0x00001000, // 1
9.102 + Aic_mono_control_left = 0x00002000, // 2
9.103 +
9.104 + Aic_trans_byte_swap = 0x00000400, // ENDSW
9.105 + Aic_tfifo_flush = 0x00000100, // TFLUSH
9.106 + Aic_rfifo_flush = 0x00000080, // RFLUSH
9.107 + Aic_enable_rfifo_overrun = 0x00000040, // EROR
9.108 + Aic_enable_tfifo_underrun = 0x00000020, // ETUR
9.109 + Aic_enable_rfifo_request = 0x00000010, // ERFS
9.110 + Aic_enable_tfifo_request = 0x00000008, // ETFS
9.111 + Aic_enable_loopback = 0x00000004, // ENLBF
9.112 + Aic_enable_playback = 0x00000002, // ERPL
9.113 + Aic_enable_record = 0x00000001, // EREC
9.114 +};
9.115 +
9.116 +enum Aic_i2s_msb_control_bits : unsigned
9.117 +{
9.118 + Aic_i2s_msb_right_first = 0x20000, // RFIRST
9.119 + Aic_i2s_msb_switch_lr = 0x10000, // SWLH
9.120 + Aic_select_msb_justified = 0x00001, // AMSL
9.121 + Aic_select_i2s = 0x00000, // AMSL
9.122 +};
9.123 +
9.124 +enum Aic_fifo_status_bits : unsigned
9.125 +{
9.126 + Aic_rfifo_overrun = 0x40, // ROR
9.127 + Aic_tfifo_underrun = 0x20, // TUR
9.128 + Aic_rfifo_request = 0x10, // RFS
9.129 + Aic_tfifo_request = 0x08, // TFS
9.130 + Aic_tfifo_loop_overrun = 0x04, // TFLOR
9.131 + Aic_tfifo_loop_request = 0x02, // TFLS
9.132 +
9.133 + Aic_rfifo_level_bit = 24, // RFL
9.134 + Aic_tfifo_loop_level_bit = 15, // TFLL
9.135 + Aic_tfifo_level_bit = 8, // TFL
9.136 +};
9.137 +
9.138 +enum Aic_i2s_msb_status_bits : unsigned
9.139 +{
9.140 + Aic_trans_channel_busy = 0x20, // CHBSY
9.141 + Aic_trans_busy = 0x10, // TBSY
9.142 + Aic_recv_busy = 0x08, // RBSY
9.143 + Aic_busy = 0x04, // BSY
9.144 +};
9.145 +
9.146 +enum Aic_i2s_msb_divider_bits : unsigned
9.147 +{
9.148 + Aic_recv_divider_mask = 0x1ff0000, // RDIV
9.149 + Aic_trans_divider_mask = 0x00001ff, // TDIV
9.150 +
9.151 + Aic_recv_divider_bit = 16, // RDIV
9.152 + Aic_trans_divider_bit = 0, // TDIV
9.153 +};
9.154 +
9.155 +enum Aic_i2s_msb_divider_limits : unsigned
9.156 +{
9.157 + Aic_recv_divider_limit = 0x1ff, // RDIV
9.158 + Aic_trans_divider_limit = 0x1ff, // TDIV
9.159 +};
9.160 +
9.161 +enum Aic_fifo_data_limits : unsigned
9.162 +{
9.163 + Aic_fifo_data_limit = 0xffffff, // DATA
9.164 +};
9.165 +
9.166 +enum Aic_loop_data_limits : unsigned
9.167 +{
9.168 + Aic_loop_data_limit = 0xffffff, // DATALP
9.169 +};
9.170 +
9.171 +enum Aic_tfifo_loop_limits : unsigned
9.172 +{
9.173 + Aic_tfifo_loop_limit = 0xf, // TFLTH
9.174 +};
9.175 +
9.176 +
9.177 +
9.178 +// Initialise a channel.
9.179 +
9.180 +Aic_x1600_channel::Aic_x1600_channel(l4_addr_t aic_start, l4_addr_t start,
9.181 + enum Clock_identifiers clock_rx,
9.182 + enum Clock_identifiers clock_tx,
9.183 + Cpm_x1600_chip *cpm,
9.184 + Dma_x1600_channel *dma)
9.185 +: _aic_start(aic_start), _clock_rx(clock_rx), _clock_tx(clock_tx), _cpm(cpm), _dma(dma)
9.186 +{
9.187 + _regs = new Hw::Mmio_register_block<32>(start);
9.188 + _cpm->start_clock(clock_rx);
9.189 + _cpm->start_clock(clock_tx);
9.190 + config();
9.191 +}
9.192 +
9.193 +/*
9.194 +I2S configuration.
9.195 +
9.196 +The system clock (SYS_CLK) for I2S in the X1600 is issued by the X1600 as the
9.197 +master/system clock (MCLK) externally to the DAC/codec.
9.198 +
9.199 +SYS_CLK is divided to obtain BIT_CLK which is issued by the X1600 as BCLK.
9.200 +This is dependent on the actual sample rate.
9.201 +
9.202 +LRCLK indicates the left/right channel for the issued data.
9.203 +
9.204 +Where clocks (MCLK, BCLK, LRCLK) are issued only by the X1600, share mode
9.205 +is used. Otherwise, independent (6-line) mode is used.
9.206 +
9.207 +To drive the MAX9835A, no MCLK is needed.
9.208 +
9.209 +Initialisation involves the following:
9.210 +
9.211 +- Configure MCLK, BCLK, LRCLK as outputs
9.212 +- Select I2S in Aic_i2s_msb_control (deselecting Aic_select_msb_justified)
9.213 +- Set master mode in Aic_config (Aic_tmaster, also Aic_rmaster if independent
9.214 + mode is used)
9.215 +- Set the dividers in Aic_i2s_msb_divider for BCLK using the configured I2S
9.216 + clock frequency
9.217 +- Perform a reset by writing to Aic_reset in Aic_config, if necessary
9.218 +- The MAX9835A may not need any configuration using I2C or some other bus
9.219 +*/
9.220 +
9.221 +void
9.222 +Aic_x1600_channel::config()
9.223 +{
9.224 + // NOTE: Setting transmit request threshold to 31 (15 * 2 + 1).
9.225 +
9.226 + printf("config = %08x\n", (uint32_t) _regs[Aic_config]);
9.227 +
9.228 + _regs[Aic_config] = Aic_shared_clock | Aic_select_i2s_msb | Aic_reset |
9.229 + Aic_tmaster | Aic_enable | (15 << Aic_tfifo_thold_bit);
9.230 +
9.231 + _regs[Aic_i2s_msb_control] = Aic_select_i2s;
9.232 +
9.233 + printf("config = %08x\n", (uint32_t) _regs[Aic_config]);
9.234 +}
9.235 +
9.236 +/*
9.237 +Clock configuration:
9.238 +
9.239 +- SYS_CLK (MCLK) is Clock_i2s0_tx (or Clock_i2s0_rx)
9.240 +- BIT_CLK (BCLK) is MCLK divided by the appropriate AIC/I2S divider
9.241 +- BCLK should be 64 times the sample rate according to the manual
9.242 +
9.243 +This suggests that the X1600 always produces data for two 32-bit channels
9.244 +regardless of the input data characteristics.
9.245 +*/
9.246 +
9.247 +void
9.248 +Aic_x1600_channel::set_divider(uint32_t divider, uint32_t mask, uint32_t limit,
9.249 + int bit)
9.250 +{
9.251 + if (divider <= limit)
9.252 + _regs[Aic_i2s_msb_divider] = (_regs[Aic_i2s_msb_divider] & ~mask) |
9.253 + (divider << bit);
9.254 +}
9.255 +
9.256 +void
9.257 +Aic_x1600_channel::set_recv_frequency(uint32_t sample_rate)
9.258 +{
9.259 + set_divider(_cpm->get_frequency(_clock_rx) / (sample_rate * 32 * 2),
9.260 + Aic_recv_divider_mask, Aic_recv_divider_limit, Aic_recv_divider_bit);
9.261 +}
9.262 +
9.263 +void
9.264 +Aic_x1600_channel::set_trans_frequency(uint32_t sample_rate)
9.265 +{
9.266 + printf("tx %d / (freq %d * %d * 2) = %d vs. %d\n", _cpm->get_frequency(_clock_tx),
9.267 + sample_rate, 32,
9.268 + _cpm->get_frequency(_clock_tx) / (sample_rate * 32 * 2),
9.269 + Aic_trans_divider_limit);
9.270 +
9.271 + set_divider(_cpm->get_frequency(_clock_tx) / (sample_rate * 32 * 2),
9.272 + Aic_trans_divider_mask, Aic_trans_divider_limit, Aic_trans_divider_bit);
9.273 +}
9.274 +
9.275 +uint32_t
9.276 +Aic_x1600_channel::encode_input_size(uint8_t sample_size)
9.277 +{
9.278 + switch (sample_size)
9.279 + {
9.280 + case 16:
9.281 + return Aic_input_size_16bit;
9.282 +
9.283 + case 18:
9.284 + return Aic_input_size_18bit;
9.285 +
9.286 + case 20:
9.287 + return Aic_input_size_20bit;
9.288 +
9.289 + case 24:
9.290 + return Aic_input_size_24bit;
9.291 +
9.292 + default:
9.293 + return Aic_input_size_8bit;
9.294 + }
9.295 +}
9.296 +
9.297 +uint32_t
9.298 +Aic_x1600_channel::encode_output_size(uint8_t sample_size)
9.299 +{
9.300 + switch (sample_size)
9.301 + {
9.302 + case 16:
9.303 + return Aic_output_size_16bit;
9.304 +
9.305 + case 18:
9.306 + return Aic_output_size_18bit;
9.307 +
9.308 + case 20:
9.309 + return Aic_output_size_20bit;
9.310 +
9.311 + case 24:
9.312 + return Aic_output_size_24bit;
9.313 +
9.314 + default:
9.315 + return Aic_output_size_8bit;
9.316 + }
9.317 +}
9.318 +
9.319 +// Obtain a DMA-accessible buffer for sample transfers.
9.320 +
9.321 +long
9.322 +Aic_x1600_channel::get_buffer(uint32_t count, l4_addr_t *addr)
9.323 +{
9.324 + printf("get_buffer(%d)\n", count);
9.325 + long err = get_dma_region(count, 8, &_vaddr, &_paddr, &_mem);
9.326 +
9.327 + if (err)
9.328 + return err;
9.329 +
9.330 + // Set the region size as the requested size, not any allocated size.
9.331 +
9.332 + _size = count;
9.333 + *addr = _vaddr;
9.334 + printf("size = %d\n", _size);
9.335 + return L4_EOK;
9.336 +}
9.337 +
9.338 +// Transfer a sample using the given byte count (total sample size), sample rate
9.339 +// (or frequency), sample unit size (or resolution, width).
9.340 +
9.341 +unsigned int
9.342 +Aic_x1600_channel::transfer(uint32_t count, uint32_t sample_rate, uint8_t sample_size)
9.343 +{
9.344 + printf("transfer(%d, %d, %d)\n", count, sample_rate, sample_size);
9.345 +
9.346 + if (count > _size)
9.347 + return 0;
9.348 +
9.349 + /* To play a sample:
9.350 +
9.351 + - Configure the sample size using the Aic_output_size settings in Aic_control
9.352 + - The sample size will be 16- or 24-bit for the MAX9835A, with the X1600 not
9.353 + supporting 32-bit samples
9.354 + - Configure the number of channels in Aic_control (Aic_channel_mono or
9.355 + Aic_channel_stereo)
9.356 + - For 16-bit samples, select Aic_packed_data in Aic_control if appropriate,
9.357 + possibly not for the MAX983A
9.358 + - If two channels are used, select Aic_i2s_msb_right_first in
9.359 + Aic_i2s_msb_control if appropriate, as well as Aic_i2s_msb_switch_lr if
9.360 + switching the channels
9.361 + - Reconfigure the dividers if appropriate
9.362 + - For DMA, set Aic_enable_trans_dma in Aic_control and the transmit FIFO
9.363 + threshold value
9.364 + */
9.365 +
9.366 + // NOTE: Introduce sample size.
9.367 +
9.368 + set_trans_frequency(sample_rate);
9.369 +
9.370 + /* NOTE: The MAX98357A might require stereo input data, but perhaps the
9.371 + peripheral can generate the appropriate LRCLK to make it accept mono
9.372 + data. */
9.373 +
9.374 + _regs[Aic_control] = encode_output_size(sample_size) |
9.375 + Aic_channel_mono |
9.376 + Aic_enable_trans_dma |
9.377 + Aic_enable_playback;
9.378 +
9.379 + printf("control = %08x\n", (uint32_t) _regs[Aic_control]);
9.380 + printf("config = %08x\n", (uint32_t) _regs[Aic_config]);
9.381 + printf("divider = %d\n", (uint32_t) _regs[Aic_i2s_msb_divider]);
9.382 + printf("status = %08x\n", (uint32_t) _regs[Aic_i2s_msb_status]);
9.383 + printf("fifo = %08x\n", (uint32_t) _regs[Aic_fifo_status]);
9.384 +
9.385 + // Transfer from the allocated region to the FIFO. Use an incrementing source
9.386 + // address with source width, destination width and transfer unit reflecting
9.387 + // the sample size, and with transfers initiated by an empty AIC transmit
9.388 + // FIFO.
9.389 +
9.390 + printf("transfer from %llx to %lx\n", _paddr, _aic_start + Aic_fifo_data);
9.391 +
9.392 + unsigned int sample_unit = (sample_size == 8) ? 1 :
9.393 + (sample_size == 16) ? 2 :
9.394 + 4;
9.395 + unsigned int unit_count = count / sample_unit;
9.396 +
9.397 + unsigned int to_transfer = _dma->transfer(_paddr,
9.398 + _aic_start + Aic_fifo_data,
9.399 + unit_count,
9.400 + true,
9.401 + false,
9.402 + sample_unit,
9.403 + sample_unit,
9.404 + sample_unit,
9.405 + Dma_request_aic_out);
9.406 +
9.407 + printf("status = %08x\n", (uint32_t) _regs[Aic_i2s_msb_status]);
9.408 + printf("fifo = %08x\n", (uint32_t) _regs[Aic_fifo_status]);
9.409 +
9.410 + unsigned int transferred = 0;
9.411 +
9.412 + if (to_transfer)
9.413 + transferred = to_transfer ? (unit_count - _dma->wait()) * sample_unit : 0;
9.414 +
9.415 +#if 0
9.416 + if (transferred)
9.417 + while (_regs[Aic_fifo_status]);
9.418 +
9.419 + _regs[Aic_control] = _regs[Aic_control] & ~Aic_enable_playback;
9.420 +#endif
9.421 +
9.422 + return transferred;
9.423 +}
9.424 +
9.425 +
9.426 +
9.427 +// Initialise the AIC/I2S controller.
9.428 +
9.429 +Aic_x1600_chip::Aic_x1600_chip(l4_addr_t aic_start, l4_addr_t start, l4_addr_t end,
9.430 + Cpm_x1600_chip *cpm)
9.431 +: _aic_start(aic_start), _start(start), _end(end), _cpm(cpm)
9.432 +{
9.433 +}
9.434 +
9.435 +// Obtain a channel object.
9.436 +
9.437 +Aic_x1600_channel *
9.438 +Aic_x1600_chip::get_channel(uint8_t channel, Dma_x1600_channel *dma)
9.439 +{
9.440 + if (channel < 1)
9.441 + return new Aic_x1600_channel(_aic_start, _start, Clock_i2s0_rx, Clock_i2s0_tx, _cpm, dma);
9.442 + else
9.443 + throw -L4_EINVAL;
9.444 +}
9.445 +
9.446 +
9.447 +
9.448 +// C language interface functions.
9.449 +
9.450 +void *x1600_aic_init(l4_addr_t aic_start, l4_addr_t start, l4_addr_t end, void *cpm)
9.451 +{
9.452 + return (void *) new Aic_x1600_chip(aic_start, start, end, static_cast<Cpm_x1600_chip *>(cpm));
9.453 +}
9.454 +
9.455 +void *x1600_aic_get_channel(void *aic, uint8_t channel, void *dma)
9.456 +{
9.457 + return static_cast<Aic_x1600_chip *>(aic)->get_channel(channel,
9.458 + static_cast<Dma_x1600_channel *>(dma));
9.459 +}
9.460 +
9.461 +long x1600_aic_get_buffer(void *channel, uint32_t count, l4_addr_t *addr)
9.462 +{
9.463 + return static_cast<Aic_x1600_channel *>(channel)->get_buffer(count, addr);
9.464 +}
9.465 +
9.466 +unsigned int x1600_aic_transfer(void *channel, uint32_t count, uint32_t sample_rate, uint8_t sample_size)
9.467 +{
9.468 + return static_cast<Aic_x1600_channel *>(channel)->transfer(count, sample_rate, sample_size);
9.469 +}
10.1 --- a/pkg/devices/lib/cpm/include/cpm-common.h Fri Sep 22 21:56:34 2023 +0200
10.2 +++ b/pkg/devices/lib/cpm/include/cpm-common.h Tue Oct 24 18:52:06 2023 +0200
10.3 @@ -67,6 +67,7 @@
10.4 uint32_t mask;
10.5 uint8_t bit;
10.6 bool defined;
10.7 + uint32_t _asserted = 0, _deasserted = 0;
10.8
10.9 public:
10.10 explicit Field()
10.11 @@ -74,14 +75,22 @@
10.12 {
10.13 }
10.14
10.15 - explicit Field(uint32_t reg, uint32_t mask, uint32_t bit)
10.16 + explicit Field(uint32_t reg, uint32_t mask, uint32_t bit,
10.17 + bool inverted = false)
10.18 : reg(reg), mask(mask), bit(bit), defined(true)
10.19 {
10.20 + if (inverted)
10.21 + _deasserted = mask;
10.22 + else
10.23 + _asserted = mask;
10.24 }
10.25
10.26 uint32_t get_field(Cpm_regs ®s);
10.27 void set_field(Cpm_regs ®s, uint32_t value);
10.28
10.29 + uint32_t get_asserted() { return _asserted; }
10.30 + uint32_t get_deasserted() { return _deasserted; }
10.31 +
10.32 bool is_defined() { return defined; }
10.33 uint32_t get_limit() { return mask; }
10.34
11.1 --- a/pkg/devices/lib/cpm/src/common.cc Fri Sep 22 21:56:34 2023 +0200
11.2 +++ b/pkg/devices/lib/cpm/src/common.cc Tue Oct 24 18:52:06 2023 +0200
11.3 @@ -164,7 +164,7 @@
11.4 Control::have_clock(Cpm_regs ®s)
11.5 {
11.6 if (_gate.is_defined())
11.7 - return !_gate.get_field(regs);
11.8 + return _gate.get_field(regs) == _gate.get_asserted();
11.9 else
11.10 return true;
11.11 }
11.12 @@ -173,14 +173,14 @@
11.13 Control::start_clock(Cpm_regs ®s)
11.14 {
11.15 if (_gate.is_defined())
11.16 - _gate.set_field(regs, 0);
11.17 + _gate.set_field(regs, _gate.get_asserted());
11.18 }
11.19
11.20 void
11.21 Control::stop_clock(Cpm_regs ®s)
11.22 {
11.23 if (_gate.is_defined())
11.24 - _gate.set_field(regs, 1);
11.25 + _gate.set_field(regs, _gate.get_deasserted());
11.26 }
11.27
11.28 void
12.1 --- a/pkg/devices/lib/cpm/src/x1600.cc Fri Sep 22 21:56:34 2023 +0200
12.2 +++ b/pkg/devices/lib/cpm/src/x1600.cc Tue Oct 24 18:52:06 2023 +0200
12.3 @@ -98,7 +98,8 @@
12.4 Clock_source_cdbus (Divider_cdbus, 3, 30), // CDCS
12.5 Clock_source_cim (Divider_cim, 3, 30), // CIMPCS
12.6 Clock_source_ddr (Divider_ddr, 3, 30), // DCS
12.7 - Clock_source_i2s (Divider0_i2s0, 1, 30), // I2PCS
12.8 + Clock_source_i2s0 (Divider0_i2s0, 1, 30), // I2PCS
12.9 + Clock_source_i2s1 (Divider0_i2s1, 1, 30), // I2PCS
12.10 Clock_source_lcd (Divider_lcd, 3, 30), // LPCS
12.11 Clock_source_mac (Divider_mac, 3, 30), // MACPCS
12.12 Clock_source_msc0 (Divider_msc0, 3, 30), // MPCS
12.13 @@ -126,7 +127,8 @@
12.14 Clock_change_enable_ahb2 (Clock_control, 1, 20),
12.15 Clock_change_enable_ddr (Divider_ddr, 1, 29),
12.16 Clock_change_enable_mac (Divider_mac, 1, 29),
12.17 - // Clock_change_enable_i2s (Divider0_i2s0, 1, 29), // CE_I2S may not be change enable
12.18 + Clock_gate_i2s0 (Divider0_i2s0, 1, 29), // CE_I2S is gate, not change enable
12.19 + Clock_gate_i2s1 (Divider0_i2s1, 1, 29), // CE_I2S is gate, not change enable
12.20 Clock_change_enable_lcd (Divider_lcd, 1, 29),
12.21 Clock_change_enable_msc0 (Divider_msc0, 1, 29),
12.22 Clock_change_enable_msc1 (Divider_msc1, 1, 29),
12.23 @@ -167,45 +169,45 @@
12.24 Clock_divider_i2s1_n_auto (Divider1_i2s1, 1, 31), // I2S_NEN
12.25 Clock_divider_i2s1_d_auto (Divider1_i2s1, 1, 30), // I2S_DEN
12.26
12.27 - Clock_gate_main (Clock_control, 1, 23), // GATE_SCLKA
12.28 - Clock_gate_ddr (Clock_gate0, 1, 31), // DDR
12.29 - Clock_gate_ahb0 (Clock_gate0, 1, 29), // AHB0
12.30 - Clock_gate_apb0 (Clock_gate0, 1, 28), // APB0
12.31 - Clock_gate_rtc (Clock_gate0, 1, 27), // RTC
12.32 - Clock_gate_aes (Clock_gate0, 1, 24), // AES
12.33 - Clock_gate_lcd_pixel (Clock_gate0, 1, 23), // LCD
12.34 - Clock_gate_cim (Clock_gate0, 1, 22), // CIM
12.35 - Clock_gate_dma (Clock_gate0, 1, 21), // PDMA
12.36 - Clock_gate_ost (Clock_gate0, 1, 20), // OST
12.37 - Clock_gate_ssi0 (Clock_gate0, 1, 19), // SSI0
12.38 - Clock_gate_timer (Clock_gate0, 1, 18), // TCU
12.39 - Clock_gate_dtrng (Clock_gate0, 1, 17), // DTRNG
12.40 - Clock_gate_uart2 (Clock_gate0, 1, 16), // UART2
12.41 - Clock_gate_uart1 (Clock_gate0, 1, 15), // UART1
12.42 - Clock_gate_uart0 (Clock_gate0, 1, 14), // UART0
12.43 - Clock_gate_sadc (Clock_gate0, 1, 13), // SADC
12.44 - Clock_gate_audio (Clock_gate0, 1, 11), // AUDIO
12.45 - Clock_gate_ssi_slv (Clock_gate0, 1, 10), // SSI_SLV
12.46 - Clock_gate_i2c1 (Clock_gate0, 1, 8), // I2C1
12.47 - Clock_gate_i2c0 (Clock_gate0, 1, 7), // I2C0
12.48 - Clock_gate_msc1 (Clock_gate0, 1, 5), // MSC1
12.49 - Clock_gate_msc0 (Clock_gate0, 1, 4), // MSC0
12.50 - Clock_gate_otg (Clock_gate0, 1, 3), // OTG
12.51 - Clock_gate_sfc (Clock_gate0, 1, 2), // SFC
12.52 - Clock_gate_efuse (Clock_gate0, 1, 1), // EFUSE
12.53 - Clock_gate_nemc (Clock_gate0, 1, 0), // NEMC
12.54 - Clock_gate_arb (Clock_gate1, 1, 30), // ARB
12.55 - Clock_gate_mipi_csi (Clock_gate1, 1, 28), // MIPI_CSI
12.56 - Clock_gate_intc (Clock_gate1, 1, 26), // INTC
12.57 - Clock_gate_gmac0 (Clock_gate1, 1, 23), // GMAC0
12.58 - Clock_gate_uart3 (Clock_gate1, 1, 16), // UART3
12.59 - Clock_gate_i2s0_tx (Clock_gate1, 1, 9), // I2S0_dev_tclk
12.60 - Clock_gate_i2s0_rx (Clock_gate1, 1, 8), // I2S0_dev_rclk
12.61 - Clock_gate_hash (Clock_gate1, 1, 6), // HASH
12.62 - Clock_gate_pwm (Clock_gate1, 1, 5), // PWM
12.63 - Clock_gate_cdbus (Clock_gate1, 1, 2), // CDBUS
12.64 - Clock_gate_can1 (Clock_gate1, 1, 1), // CAN1
12.65 - Clock_gate_can0 (Clock_gate1, 1, 0), // CAN0
12.66 + Clock_gate_main (Clock_control, 1, 23, true), // GATE_SCLKA
12.67 + Clock_gate_ddr (Clock_gate0, 1, 31, true), // DDR
12.68 + Clock_gate_ahb0 (Clock_gate0, 1, 29, true), // AHB0
12.69 + Clock_gate_apb0 (Clock_gate0, 1, 28, true), // APB0
12.70 + Clock_gate_rtc (Clock_gate0, 1, 27, true), // RTC
12.71 + Clock_gate_aes (Clock_gate0, 1, 24, true), // AES
12.72 + Clock_gate_lcd_pixel (Clock_gate0, 1, 23, true), // LCD
12.73 + Clock_gate_cim (Clock_gate0, 1, 22, true), // CIM
12.74 + Clock_gate_dma (Clock_gate0, 1, 21, true), // PDMA
12.75 + Clock_gate_ost (Clock_gate0, 1, 20, true), // OST
12.76 + Clock_gate_ssi0 (Clock_gate0, 1, 19, true), // SSI0
12.77 + Clock_gate_timer (Clock_gate0, 1, 18, true), // TCU
12.78 + Clock_gate_dtrng (Clock_gate0, 1, 17, true), // DTRNG
12.79 + Clock_gate_uart2 (Clock_gate0, 1, 16, true), // UART2
12.80 + Clock_gate_uart1 (Clock_gate0, 1, 15, true), // UART1
12.81 + Clock_gate_uart0 (Clock_gate0, 1, 14, true), // UART0
12.82 + Clock_gate_sadc (Clock_gate0, 1, 13, true), // SADC
12.83 + Clock_gate_audio (Clock_gate0, 1, 11, true), // AUDIO
12.84 + Clock_gate_ssi_slv (Clock_gate0, 1, 10, true), // SSI_SLV
12.85 + Clock_gate_i2c1 (Clock_gate0, 1, 8, true), // I2C1
12.86 + Clock_gate_i2c0 (Clock_gate0, 1, 7, true), // I2C0
12.87 + Clock_gate_msc1 (Clock_gate0, 1, 5, true), // MSC1
12.88 + Clock_gate_msc0 (Clock_gate0, 1, 4, true), // MSC0
12.89 + Clock_gate_otg (Clock_gate0, 1, 3, true), // OTG
12.90 + Clock_gate_sfc (Clock_gate0, 1, 2, true), // SFC
12.91 + Clock_gate_efuse (Clock_gate0, 1, 1, true), // EFUSE
12.92 + Clock_gate_nemc (Clock_gate0, 1, 0, true), // NEMC
12.93 + Clock_gate_arb (Clock_gate1, 1, 30, true), // ARB
12.94 + Clock_gate_mipi_csi (Clock_gate1, 1, 28, true), // MIPI_CSI
12.95 + Clock_gate_intc (Clock_gate1, 1, 26, true), // INTC
12.96 + Clock_gate_gmac0 (Clock_gate1, 1, 23, true), // GMAC0
12.97 + Clock_gate_uart3 (Clock_gate1, 1, 16, true), // UART3
12.98 + Clock_gate_i2s0_tx (Clock_gate1, 1, 9, true), // I2S0_dev_tclk
12.99 + Clock_gate_i2s0_rx (Clock_gate1, 1, 8, true), // I2S0_dev_rclk
12.100 + Clock_gate_hash (Clock_gate1, 1, 6, true), // HASH
12.101 + Clock_gate_pwm (Clock_gate1, 1, 5, true), // PWM
12.102 + Clock_gate_cdbus (Clock_gate1, 1, 2, true), // CDBUS
12.103 + Clock_gate_can1 (Clock_gate1, 1, 1, true), // CAN1
12.104 + Clock_gate_can0 (Clock_gate1, 1, 0, true), // CAN0
12.105
12.106 Pll_enable_A (Pll_control_A, 1, 0), // APLLEN
12.107 Pll_enable_E (Pll_control_E, 1, 0), // EPLLEN
12.108 @@ -245,10 +247,13 @@
12.109 mux_hclock0 (Clock_hclock0),
12.110 mux_hclock2 (Clock_hclock2),
12.111 mux_pclock (Clock_pclock),
12.112 + mux_main (3, Clocks(Clock_none, Clock_external, Clock_pll_A)),
12.113 mux_core (3, Clocks(Clock_none, Clock_main, Clock_pll_M)),
12.114 mux_bus (4, Clocks(Clock_main, Clock_pll_M, Clock_pll_E, Clock_external)),
12.115 mux_dev (3, Clocks(Clock_main, Clock_pll_M, Clock_pll_E)),
12.116 - mux_i2s (2, Clocks(Clock_main, Clock_pll_E));
12.117 + mux_i2s (2, Clocks(Clock_main, Clock_pll_E)),
12.118 + mux_i2s0_rx (Clock_i2s0),
12.119 + mux_i2s0_tx (Clock_i2s1);
12.120
12.121
12.122
12.123 @@ -261,7 +266,9 @@
12.124 // Note the use of extra parentheses due to the annoying C++ "most vexing parse"
12.125 // problem. See: https://en.wikipedia.org/wiki/Most_vexing_parse
12.126
12.127 -static Clock clock_dma((Source(mux_hclock2)), (Control(Clock_gate_dma))),
12.128 +static Clock clock_audio((Source(mux_hclock2)), (Control(Clock_gate_audio))),
12.129 +
12.130 + clock_dma((Source(mux_hclock2)), (Control(Clock_gate_dma))),
12.131
12.132 clock_i2c((Source(mux_pclock)), (Control(Clock_gate_i2c0))),
12.133
12.134 @@ -269,7 +276,11 @@
12.135
12.136 clock_i2c1((Source(mux_pclock)), (Control(Clock_gate_i2c1))),
12.137
12.138 - clock_main(Source(mux_core, Clock_source_main), Control(Clock_gate_main)),
12.139 + clock_i2s0(Source(mux_i2s, Clock_source_i2s0), Control(Clock_gate_i2s0)),
12.140 +
12.141 + clock_i2s1(Source(mux_i2s, Clock_source_i2s1), Control(Clock_gate_i2s1)),
12.142 +
12.143 + clock_main(Source(mux_main, Clock_source_main), Control(Clock_gate_main)),
12.144
12.145 clock_mipi_csi((Source(mux_hclock0)), Control(Clock_gate_mipi_csi)),
12.146
12.147 @@ -359,13 +370,13 @@
12.148 Divider(Clock_divider_ssi));
12.149
12.150 static Clock_divided_i2s
12.151 - clock_i2s0_rx(Source(mux_i2s, Clock_source_i2s),
12.152 + clock_i2s0_rx(Source(mux_i2s0_rx),
12.153 Control(Clock_gate_i2s0_rx),
12.154 Divider_i2s(Clock_divider_i2s0_m, Clock_divider_i2s0_n,
12.155 Clock_divider_i2s0_d, Clock_divider_i2s0_n_auto,
12.156 Clock_divider_i2s0_d_auto)),
12.157
12.158 - clock_i2s0_tx(Source(mux_i2s, Clock_source_i2s),
12.159 + clock_i2s0_tx(Source(mux_i2s0_tx),
12.160 Control(Clock_gate_i2s0_tx),
12.161 Divider_i2s(Clock_divider_i2s1_m, Clock_divider_i2s1_n,
12.162 Clock_divider_i2s1_d, Clock_divider_i2s1_n_auto,
12.163 @@ -391,6 +402,7 @@
12.164 // Clock register.
12.165
12.166 static Clock_base *clocks[Clock_identifier_count] = {
12.167 + &clock_audio,
12.168 &clock_none, // Clock_aic_bitclk
12.169 &clock_none, // Clock_aic_pclk
12.170 &clock_can0,
12.171 @@ -408,9 +420,12 @@
12.172 &clock_i2c,
12.173 &clock_i2c0,
12.174 &clock_i2c1,
12.175 - &clock_none, // Clock_i2s
12.176 + &clock_i2s0, // supplies i2s0_rx
12.177 &clock_i2s0_rx,
12.178 &clock_i2s0_tx,
12.179 + &clock_i2s1, // supplies i2s0_tx
12.180 + &clock_none, // Clock_i2s1_rx
12.181 + &clock_none, // Clock_i2s1_tx
12.182 &clock_none, // Clock_kbc
12.183 &clock_none, // Clock_lcd
12.184 &clock_lcd_pixel,
13.1 --- a/pkg/devices/lib/dma/include/dma-jz4730.h Fri Sep 22 21:56:34 2023 +0200
13.2 +++ b/pkg/devices/lib/dma/include/dma-jz4730.h Tue Oct 24 18:52:06 2023 +0200
13.3 @@ -1,7 +1,7 @@
13.4 /*
13.5 * DMA support for the JZ4730.
13.6 *
13.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
13.8 + * Copyright (C) 2021, 2023 Paul Boddie <paul@boddie.org.uk>
13.9 *
13.10 * This program is free software; you can redistribute it and/or
13.11 * modify it under the terms of the GNU General Public License as
13.12 @@ -28,7 +28,7 @@
13.13
13.14 /* Enumerated types for various transfer parameters. */
13.15
13.16 -enum Dma_jz4730_request_type : unsigned
13.17 +enum Dma_jz4730_request_type
13.18 {
13.19 Dma_request_external = 0,
13.20 Dma_request_pcmcia_out = 4,
13.21 @@ -53,19 +53,19 @@
13.22 Dma_request_ost2_underflow = 28,
13.23 };
13.24
13.25 -enum Dma_jz4730_ext_level : unsigned
13.26 +enum Dma_jz4730_ext_level
13.27 {
13.28 Dma_ext_active_high = 0,
13.29 Dma_ext_active_low = 1,
13.30 };
13.31
13.32 -enum Dma_jz4730_ext_output_mode_cycle : unsigned
13.33 +enum Dma_jz4730_ext_output_mode_cycle
13.34 {
13.35 Dma_ext_output_mode_read_cycle = 0,
13.36 Dma_ext_output_mode_write_cycle = 1,
13.37 };
13.38
13.39 -enum Dma_jz4730_ext_req_detect_mode : unsigned
13.40 +enum Dma_jz4730_ext_req_detect_mode
13.41 {
13.42 Dma_ext_req_detect_mode_low_level = 0,
13.43 Dma_ext_req_detect_mode_falling_edge = 1,
13.44 @@ -73,15 +73,6 @@
13.45 Dma_ext_req_detect_mode_rising_edge = 3,
13.46 };
13.47
13.48 -enum Dma_jz4730_trans_unit_size : unsigned
13.49 -{
13.50 - Dma_trans_unit_size_32_bit = 0,
13.51 - Dma_trans_unit_size_8_bit = 1,
13.52 - Dma_trans_unit_size_16_bit = 2,
13.53 - Dma_trans_unit_size_16_byte = 3,
13.54 - Dma_trans_unit_size_32_byte = 4,
13.55 -};
13.56 -
13.57
13.58
13.59 #ifdef __cplusplus
13.60 @@ -103,7 +94,7 @@
13.61 Hw::Register_block<32> _regs;
13.62 Dma_jz4730_chip *_chip;
13.63 uint8_t _channel;
13.64 - l4_cap_idx_t _irq=L4_INVALID_CAP;
13.65 + l4_cap_idx_t _irq = L4_INVALID_CAP;
13.66
13.67 // External transfer properties with defaults.
13.68
13.69 @@ -117,9 +108,13 @@
13.70
13.71 unsigned int transfer(uint32_t source, uint32_t destination,
13.72 unsigned int count,
13.73 - enum Dma_jz4730_trans_unit_size size,
13.74 + bool source_increment, bool destination_increment,
13.75 + uint8_t source_width, uint8_t destination_width,
13.76 + uint8_t transfer_unit_size,
13.77 enum Dma_jz4730_request_type type=Dma_request_auto);
13.78
13.79 + unsigned int wait();
13.80 +
13.81 // External transfer property configuration.
13.82
13.83 void set_output_polarity(enum Dma_jz4730_ext_level polarity)
13.84 @@ -139,15 +134,13 @@
13.85
13.86 uint32_t encode_external_transfer(enum Dma_jz4730_request_type type);
13.87
13.88 - uint32_t encode_source_address_increment(enum Dma_jz4730_request_type type);
13.89 -
13.90 - uint32_t encode_destination_address_increment(enum Dma_jz4730_request_type type);
13.91 -
13.92 uint32_t encode_req_detect_int_length(uint8_t units);
13.93
13.94 - uint32_t encode_source_port_width(enum Dma_jz4730_request_type type);
13.95 + uint32_t encode_source_port_width(uint8_t width);
13.96
13.97 - uint32_t encode_destination_port_width(enum Dma_jz4730_request_type type);
13.98 + uint32_t encode_destination_port_width(uint8_t width);
13.99 +
13.100 + uint32_t encode_transfer_unit_size(uint8_t size);
13.101
13.102 // Transaction control.
13.103
13.104 @@ -209,9 +202,14 @@
13.105
13.106 void jz4730_dma_set_req_detect_mode(void *dma_channel, enum Dma_jz4730_ext_req_detect_mode mode);
13.107
13.108 -unsigned int jz4730_dma_transfer(void *dma_channel, uint32_t source,
13.109 - uint32_t destination, unsigned int count,
13.110 - enum Dma_jz4730_trans_unit_size size,
13.111 - enum Dma_jz4730_request_type type);
13.112 +unsigned int jz4730_dma_transfer(void *dma_channel,
13.113 + uint32_t source, uint32_t destination,
13.114 + unsigned int count,
13.115 + int source_increment, int destination_increment,
13.116 + uint8_t source_width, uint8_t destination_width,
13.117 + uint8_t transfer_unit_size,
13.118 + enum Dma_jz4730_request_type type);
13.119 +
13.120 +unsigned int jz4730_dma_wait(void *dma_channel);
13.121
13.122 EXTERN_C_END
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
14.2 +++ b/pkg/devices/lib/dma/include/dma-x1600.h Tue Oct 24 18:52:06 2023 +0200
14.3 @@ -0,0 +1,180 @@
14.4 +/*
14.5 + * DMA support for the X1600.
14.6 + *
14.7 + * Copyright (C) 2021, 2023 Paul Boddie <paul@boddie.org.uk>
14.8 + *
14.9 + * This program is free software; you can redistribute it and/or
14.10 + * modify it under the terms of the GNU General Public License as
14.11 + * published by the Free Software Foundation; either version 2 of
14.12 + * the License, or (at your option) any later version.
14.13 + *
14.14 + * This program is distributed in the hope that it will be useful,
14.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
14.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14.17 + * GNU General Public License for more details.
14.18 + *
14.19 + * You should have received a copy of the GNU General Public License
14.20 + * along with this program; if not, write to the Free Software
14.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
14.22 + * Boston, MA 02110-1301, USA
14.23 + */
14.24 +
14.25 +#pragma once
14.26 +
14.27 +#include <l4/sys/types.h>
14.28 +#include <stdint.h>
14.29 +
14.30 +
14.31 +
14.32 +/* Enumerated types for various transfer parameters. */
14.33 +
14.34 +enum Dma_x1600_request_type
14.35 +{
14.36 + Dma_request_auto = 8,
14.37 + Dma_request_can0_out = 10,
14.38 + Dma_request_can0_in = 11,
14.39 + Dma_request_can1_out = 10,
14.40 + Dma_request_can1_in = 11,
14.41 + Dma_request_uart3_out = 14,
14.42 + Dma_request_uart3_in = 15,
14.43 + Dma_request_uart2_out = 16,
14.44 + Dma_request_uart2_in = 17,
14.45 + Dma_request_uart1_out = 18,
14.46 + Dma_request_uart1_in = 19,
14.47 + Dma_request_uart0_out = 20,
14.48 + Dma_request_uart0_in = 21,
14.49 + Dma_request_ssi0_send_empty = 22,
14.50 + Dma_request_ssi0_recv_full = 23,
14.51 + Dma_request_i2c0_send_empty = 36,
14.52 + Dma_request_i2c0_recv_full = 37,
14.53 + Dma_request_i2c1_send_empty = 38,
14.54 + Dma_request_i2c1_recv_full = 39,
14.55 + Dma_request_ssi_slv_out = 42,
14.56 + Dma_request_ssi_slv_in = 43,
14.57 + Dma_request_msc0_send_empty = 52,
14.58 + Dma_request_msc0_recv_full = 53,
14.59 + Dma_request_msc1_send_empty = 54,
14.60 + Dma_request_msc1_recv_full = 55,
14.61 + Dma_request_sadc_in = 56,
14.62 + Dma_request_aic_loop_out = 61,
14.63 + Dma_request_aic_out = 62,
14.64 + Dma_request_aic_in = 63,
14.65 +};
14.66 +
14.67 +
14.68 +
14.69 +#ifdef __cplusplus
14.70 +
14.71 +#include <l4/devices/cpm-x1600.h>
14.72 +#include <l4/devices/hw_mmio_register_block.h>
14.73 +
14.74 +// Forward declaration.
14.75 +
14.76 +class Dma_x1600_chip;
14.77 +
14.78 +
14.79 +
14.80 +// DMA channel.
14.81 +
14.82 +class Dma_x1600_channel
14.83 +{
14.84 +private:
14.85 + Hw::Register_block<32> _regs;
14.86 + Dma_x1600_chip *_chip;
14.87 + uint8_t _channel;
14.88 + l4_cap_idx_t _irq = L4_INVALID_CAP;
14.89 +
14.90 +public:
14.91 + Dma_x1600_channel(Dma_x1600_chip *chip, uint8_t channel, l4_addr_t start, l4_cap_idx_t irq);
14.92 +
14.93 + unsigned int transfer(uint32_t source, uint32_t destination,
14.94 + unsigned int count,
14.95 + bool source_increment, bool destination_increment,
14.96 + uint8_t source_width, uint8_t destination_width,
14.97 + uint8_t transfer_unit_size,
14.98 + enum Dma_x1600_request_type type=Dma_request_auto);
14.99 +
14.100 + unsigned int wait();
14.101 +
14.102 +protected:
14.103 + // Transfer property configuration.
14.104 +
14.105 + uint32_t encode_req_detect_int_length(uint8_t units);
14.106 +
14.107 + uint32_t encode_source_port_width(uint8_t width);
14.108 +
14.109 + uint32_t encode_destination_port_width(uint8_t width);
14.110 +
14.111 + uint32_t encode_transfer_unit_size(uint8_t size);
14.112 +
14.113 + // Transaction control.
14.114 +
14.115 + void ack_irq();
14.116 +
14.117 + bool completed();
14.118 +
14.119 + bool error();
14.120 +
14.121 + bool halted();
14.122 +
14.123 + bool wait_for_irq();
14.124 +
14.125 + bool wait_for_irq(unsigned int timeout);
14.126 +};
14.127 +
14.128 +// DMA device control.
14.129 +
14.130 +class Dma_x1600_chip
14.131 +{
14.132 +private:
14.133 + Hw::Register_block<32> _regs;
14.134 + l4_addr_t _start, _end;
14.135 + Cpm_x1600_chip *_cpm;
14.136 +
14.137 +public:
14.138 + Dma_x1600_chip(l4_addr_t start, l4_addr_t end, Cpm_x1600_chip *cpm);
14.139 +
14.140 + void disable();
14.141 +
14.142 + void enable();
14.143 +
14.144 + Dma_x1600_channel *get_channel(uint8_t channel, l4_cap_idx_t irq);
14.145 +
14.146 + // Transaction control.
14.147 +
14.148 + void ack_irq(uint8_t channel);
14.149 +
14.150 + bool error();
14.151 +
14.152 + bool halted();
14.153 +
14.154 + bool have_interrupt(uint8_t channel);
14.155 +};
14.156 +
14.157 +#endif /* __cplusplus */
14.158 +
14.159 +
14.160 +
14.161 +/* C language interface. */
14.162 +
14.163 +EXTERN_C_BEGIN
14.164 +
14.165 +void *x1600_dma_init(l4_addr_t start, l4_addr_t end, void *cpm);
14.166 +
14.167 +void x1600_dma_disable(void *dma_chip);
14.168 +
14.169 +void x1600_dma_enable(void *dma_chip);
14.170 +
14.171 +void *x1600_dma_get_channel(void *dma, uint8_t channel, l4_cap_idx_t irq);
14.172 +
14.173 +unsigned int x1600_dma_transfer(void *dma_channel,
14.174 + uint32_t source, uint32_t destination,
14.175 + unsigned int count,
14.176 + int source_increment, int destination_increment,
14.177 + uint8_t source_width, uint8_t destination_width,
14.178 + uint8_t transfer_unit_size,
14.179 + enum Dma_x1600_request_type type);
14.180 +
14.181 +unsigned int x1600_dma_wait(void *dma_channel);
14.182 +
14.183 +EXTERN_C_END
15.1 --- a/pkg/devices/lib/dma/src/Makefile Fri Sep 22 21:56:34 2023 +0200
15.2 +++ b/pkg/devices/lib/dma/src/Makefile Tue Oct 24 18:52:06 2023 +0200
15.3 @@ -4,7 +4,7 @@
15.4 TARGET = libdma.o.a libdma.o.so
15.5 PC_FILENAME := libdrivers-dma
15.6
15.7 -SRC_CC := jz4730.cc
15.8 +SRC_CC := jz4730.cc x1600.cc
15.9
15.10 PRIVATE_INCDIR += $(PKGDIR)/lib/dma/include
15.11
16.1 --- a/pkg/devices/lib/dma/src/jz4730.cc Fri Sep 22 21:56:34 2023 +0200
16.2 +++ b/pkg/devices/lib/dma/src/jz4730.cc Tue Oct 24 18:52:06 2023 +0200
16.3 @@ -27,7 +27,9 @@
16.4 #include <l4/sys/irq.h>
16.5 #include <l4/util/util.h>
16.6
16.7 -#include <cstdio>
16.8 +#include <stdio.h>
16.9 +
16.10 +
16.11
16.12 enum Global_regs
16.13 {
16.14 @@ -96,7 +98,16 @@
16.15 enum Dma_control_status_bits : unsigned
16.16 {
16.17 Dma_source_address_incr = 0x00800000,
16.18 + Dma_source_address_no_incr = 0x00000000,
16.19 Dma_dest_address_incr = 0x00400000,
16.20 + Dma_dest_address_no_incr = 0x00000000,
16.21 +
16.22 + Dma_trans_unit_size_32_bit = 0x00000000,
16.23 + Dma_trans_unit_size_8_bit = 0x00000100,
16.24 + Dma_trans_unit_size_16_bit = 0x00000200,
16.25 + Dma_trans_unit_size_16_byte = 0x00000300,
16.26 + Dma_trans_unit_size_32_byte = 0x00000400,
16.27 +
16.28 Dma_address_error = 0x00000010,
16.29 Dma_trans_completed = 0x00000008,
16.30 Dma_trans_halted = 0x00000004,
16.31 @@ -142,62 +153,6 @@
16.32 ((external ? (int) _ext_end_of_process_mode : 0) << Dma_ext_end_of_process_mode);
16.33 }
16.34
16.35 -// Encode the appropriate source address increment for the given request type.
16.36 -// Here, memory-to-memory transfers and transfers to peripherals involve an
16.37 -// incrementing source address. Transfers from peripherals involve a static
16.38 -// source address.
16.39 -
16.40 -uint32_t
16.41 -Dma_jz4730_channel::encode_source_address_increment(enum Dma_jz4730_request_type type)
16.42 -{
16.43 - switch (type)
16.44 - {
16.45 - case Dma_request_auto:
16.46 - case Dma_request_pcmcia_out:
16.47 - case Dma_request_des_out:
16.48 - case Dma_request_uart3_out:
16.49 - case Dma_request_uart2_out:
16.50 - case Dma_request_uart1_out:
16.51 - case Dma_request_uart0_out:
16.52 - case Dma_request_ssi_send_empty:
16.53 - case Dma_request_aic_send_empty:
16.54 - case Dma_request_msc_send_empty:
16.55 - case Dma_request_ost2_underflow:
16.56 - return Dma_source_address_incr;
16.57 -
16.58 - default:
16.59 - return 0;
16.60 - }
16.61 -}
16.62 -
16.63 -// Encode the appropriate destination address increment for the given request
16.64 -// type. Here, memory-to-memory transfers and transfers from peripherals involve
16.65 -// an incrementing destination address. Transfers to peripherals involve a static
16.66 -// destination address.
16.67 -
16.68 -uint32_t
16.69 -Dma_jz4730_channel::encode_destination_address_increment(enum Dma_jz4730_request_type type)
16.70 -{
16.71 - switch (type)
16.72 - {
16.73 - case Dma_request_auto:
16.74 - case Dma_request_pcmcia_in:
16.75 - case Dma_request_des_in:
16.76 - case Dma_request_uart3_in:
16.77 - case Dma_request_uart2_in:
16.78 - case Dma_request_uart1_in:
16.79 - case Dma_request_uart0_in:
16.80 - case Dma_request_ssi_recv_full:
16.81 - case Dma_request_aic_recv_full:
16.82 - case Dma_request_msc_recv_full:
16.83 - case Dma_request_ost2_underflow:
16.84 - return Dma_dest_address_incr;
16.85 -
16.86 - default:
16.87 - return 0;
16.88 - }
16.89 -}
16.90 -
16.91 // Return the closest interval length greater than or equal to the number of
16.92 // units given encoded in the request detection interval length field of the
16.93 // control/status register.
16.94 @@ -211,26 +166,23 @@
16.95 if (!units)
16.96 return 0;
16.97
16.98 - for (i = 0; i < 15; i++)
16.99 + for (i = 0; i <= 15; i++)
16.100 {
16.101 - if (lengths[i++] >= units)
16.102 + if (lengths[i] >= units)
16.103 break;
16.104 }
16.105
16.106 - return lengths[i] << Dma_req_detect_int_length;
16.107 + return i << Dma_req_detect_int_length;
16.108 }
16.109
16.110 -// Encode the appropriate source port width for the given request type.
16.111 +// Encode the appropriate source port width.
16.112
16.113 uint32_t
16.114 -Dma_jz4730_channel::encode_source_port_width(enum Dma_jz4730_request_type type)
16.115 +Dma_jz4730_channel::encode_source_port_width(uint8_t width)
16.116 {
16.117 - switch (type)
16.118 + switch (width)
16.119 {
16.120 - case Dma_request_uart3_in:
16.121 - case Dma_request_uart2_in:
16.122 - case Dma_request_uart1_in:
16.123 - case Dma_request_uart0_in:
16.124 + case 1:
16.125 return Dma_port_width_8_bit << Dma_source_port_width;
16.126
16.127 default:
16.128 @@ -241,14 +193,11 @@
16.129 // Encode the appropriate destination port width for the given request type.
16.130
16.131 uint32_t
16.132 -Dma_jz4730_channel::encode_destination_port_width(enum Dma_jz4730_request_type type)
16.133 +Dma_jz4730_channel::encode_destination_port_width(uint8_t width)
16.134 {
16.135 - switch (type)
16.136 + switch (width)
16.137 {
16.138 - case Dma_request_uart3_out:
16.139 - case Dma_request_uart2_out:
16.140 - case Dma_request_uart1_out:
16.141 - case Dma_request_uart0_out:
16.142 + case 1:
16.143 return Dma_port_width_8_bit << Dma_dest_port_width;
16.144
16.145 default:
16.146 @@ -256,12 +205,38 @@
16.147 }
16.148 }
16.149
16.150 +// Encode the transfer unit size.
16.151 +
16.152 +uint32_t
16.153 +Dma_jz4730_channel::encode_transfer_unit_size(uint8_t size)
16.154 +{
16.155 + switch (size)
16.156 + {
16.157 + case 1:
16.158 + return Dma_trans_unit_size_8_bit;
16.159 +
16.160 + case 2:
16.161 + return Dma_trans_unit_size_16_bit;
16.162 +
16.163 + case 16:
16.164 + return Dma_trans_unit_size_16_byte;
16.165 +
16.166 + case 32:
16.167 + return Dma_trans_unit_size_32_byte;
16.168 +
16.169 + default:
16.170 + return Dma_trans_unit_size_32_bit;
16.171 + }
16.172 +}
16.173 +
16.174 // Transfer data between memory locations.
16.175
16.176 unsigned int
16.177 Dma_jz4730_channel::transfer(uint32_t source, uint32_t destination,
16.178 unsigned int count,
16.179 - enum Dma_jz4730_trans_unit_size size,
16.180 + bool source_increment, bool destination_increment,
16.181 + uint8_t source_width, uint8_t destination_width,
16.182 + uint8_t transfer_unit_size,
16.183 enum Dma_jz4730_request_type type)
16.184 {
16.185 // Ensure an absence of address error and halt conditions globally and in this channel.
16.186 @@ -285,7 +260,9 @@
16.187
16.188 // Set transfer count to the number of units.
16.189
16.190 - _regs[Dma_transfer_count] = count;
16.191 + unsigned int units = count < Dma_transfer_count_mask ? count : Dma_transfer_count_mask;
16.192 +
16.193 + _regs[Dma_transfer_count] = units;
16.194
16.195 // Set auto-request for memory-to-memory transfers. Otherwise, set the
16.196 // indicated request type.
16.197 @@ -303,19 +280,27 @@
16.198 */
16.199
16.200 _regs[Dma_control_status] = encode_external_transfer(type) |
16.201 - encode_source_address_increment(type) |
16.202 - encode_destination_address_increment(type) |
16.203 - encode_source_port_width(type) |
16.204 - encode_destination_port_width(type) |
16.205 - (size << Dma_trans_unit_size) |
16.206 + (source_increment ? Dma_source_address_incr : Dma_source_address_no_incr) |
16.207 + (destination_increment ? Dma_dest_address_incr : Dma_dest_address_no_incr) |
16.208 + encode_source_port_width(source_width) |
16.209 + encode_destination_port_width(destination_width) |
16.210 + encode_transfer_unit_size(transfer_unit_size) |
16.211 (Dma_trans_mode_single << Dma_trans_mode) |
16.212 Dma_channel_irq_enable |
16.213 Dma_channel_enable;
16.214
16.215 + // Return the number of units to transfer.
16.216 +
16.217 + return units;
16.218 +}
16.219 +
16.220 +unsigned int
16.221 +Dma_jz4730_channel::wait()
16.222 +{
16.223 // An interrupt will occur upon completion, the completion flag will be set
16.224 // and the transfer count will be zero.
16.225
16.226 - unsigned int remaining = count;
16.227 + unsigned int remaining = 0;
16.228
16.229 do
16.230 {
16.231 @@ -334,9 +319,16 @@
16.232 }
16.233 while (!error() && !halted() && !completed());
16.234
16.235 - // Return the number of transferred units.
16.236 + // Reset the channel status.
16.237
16.238 - return count - remaining;
16.239 + _regs[Dma_control_status] = _regs[Dma_control_status] & ~(Dma_channel_enable |
16.240 + Dma_trans_completed | Dma_address_error |
16.241 + Dma_trans_halted);
16.242 + _regs[Dma_transfer_count] = 0;
16.243 +
16.244 + // Return the number of remaining units.
16.245 +
16.246 + return remaining;
16.247 }
16.248
16.249 // Wait indefinitely for an interrupt request, returning true if one was delivered.
16.250 @@ -424,7 +416,7 @@
16.251 while (_regs[Dma_control] & Dma_control_enable);
16.252 }
16.253
16.254 -// Obtain a channel object. Only one channel is supported.
16.255 +// Obtain a channel object.
16.256
16.257 Dma_jz4730_channel *
16.258 Dma_jz4730_chip::get_channel(uint8_t channel, l4_cap_idx_t irq)
16.259 @@ -487,10 +479,20 @@
16.260 static_cast<Dma_jz4730_channel *>(dma_channel)->set_req_detect_mode(mode);
16.261 }
16.262
16.263 -unsigned int jz4730_dma_transfer(void *dma_channel, uint32_t source,
16.264 - uint32_t destination, unsigned int count,
16.265 - enum Dma_jz4730_trans_unit_size size,
16.266 +unsigned int jz4730_dma_transfer(void *dma_channel,
16.267 + uint32_t source, uint32_t destination,
16.268 + unsigned int count,
16.269 + int source_increment, int destination_increment,
16.270 + uint8_t source_width, uint8_t destination_width,
16.271 + uint8_t transfer_unit_size,
16.272 enum Dma_jz4730_request_type type)
16.273 {
16.274 - return static_cast<Dma_jz4730_channel *>(dma_channel)->transfer(source, destination, count, size, type);
16.275 + return static_cast<Dma_jz4730_channel *>(dma_channel)->transfer(source,
16.276 + destination, count, source_increment, destination_increment, source_width,
16.277 + destination_width, transfer_unit_size, type);
16.278 }
16.279 +
16.280 +unsigned int jz4730_dma_wait(void *dma_channel)
16.281 +{
16.282 + return static_cast<Dma_jz4730_channel *>(dma_channel)->wait();
16.283 +}
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
17.2 +++ b/pkg/devices/lib/dma/src/x1600.cc Tue Oct 24 18:52:06 2023 +0200
17.3 @@ -0,0 +1,509 @@
17.4 +/*
17.5 + * DMA support for the X1600.
17.6 + *
17.7 + * Copyright (C) 2021, 2023 Paul Boddie <paul@boddie.org.uk>
17.8 + *
17.9 + * This program is free software; you can redistribute it and/or
17.10 + * modify it under the terms of the GNU General Public License as
17.11 + * published by the Free Software Foundation; either version 2 of
17.12 + * the License, or (at your option) any later version.
17.13 + *
17.14 + * This program is distributed in the hope that it will be useful,
17.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
17.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17.17 + * GNU General Public License for more details.
17.18 + *
17.19 + * You should have received a copy of the GNU General Public License
17.20 + * along with this program; if not, write to the Free Software
17.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17.22 + * Boston, MA 02110-1301, USA
17.23 + */
17.24 +
17.25 +#include <l4/devices/dma-x1600.h>
17.26 +#include <l4/devices/hw_mmio_register_block.h>
17.27 +
17.28 +#include <l4/sys/icu.h>
17.29 +#include <l4/sys/ipc.h>
17.30 +#include <l4/sys/irq.h>
17.31 +#include <l4/util/util.h>
17.32 +
17.33 +#include <stdio.h>
17.34 +
17.35 +
17.36 +
17.37 +enum Global_regs
17.38 +{
17.39 + Dma_control = 0x1000, // DMAC
17.40 + Dma_irq_pending = 0x1004, // DIRQP
17.41 +};
17.42 +
17.43 +enum Channel_regs
17.44 +{
17.45 + Dma_source = 0x00, // DSA
17.46 + Dma_destination = 0x04, // DTA
17.47 + Dma_transfer_count = 0x08, // DTC
17.48 + Dma_request_source = 0x0c, // DRT
17.49 + Dma_control_status = 0x10, // DCS
17.50 + Dma_command = 0x14, // DCM
17.51 + Dma_descriptor_address = 0x18, // DDA
17.52 + Dma_stride = 0x1c, // DSD
17.53 +};
17.54 +
17.55 +enum Dma_control_bits : unsigned
17.56 +{
17.57 + Dma_fast_msc_transfer = 0x80000000, // FMSC
17.58 + Dma_fast_ssi_transfer = 0x40000000, // FSSI
17.59 + Dma_fast_tssi_transfer = 0x20000000, // FTSSI
17.60 + Dma_fast_uart_transfer = 0x10000000, // FUART
17.61 + Dma_fast_aic_transfer = 0x08000000, // FAIC
17.62 + Dma_control_trans_halted = 0x00000008, // HLT
17.63 + Dma_control_address_error = 0x00000004, // AR
17.64 + Dma_control_enable = 0x00000001, // DMAE
17.65 +};
17.66 +
17.67 +enum Dma_transfer_count_bits : unsigned
17.68 +{
17.69 + Dma_transfer_count_mask = 0x00ffffff,
17.70 +};
17.71 +
17.72 +enum Dma_request_source_bits : unsigned
17.73 +{
17.74 + Dma_request_type_mask = 0x0000001f,
17.75 +};
17.76 +
17.77 +enum Dma_control_status_bits : unsigned
17.78 +{
17.79 + Dma_no_descriptor_transfer = 0x80000000,
17.80 + Dma_8word_descriptor = 0x40000000,
17.81 + Dma_copy_offset_mask = 0x0000ff00,
17.82 + Dma_address_error = 0x00000010,
17.83 + Dma_trans_completed = 0x00000008,
17.84 + Dma_trans_halted = 0x00000004,
17.85 + Dma_channel_enable = 0x00000001,
17.86 +
17.87 + Dma_copy_offset_shift = 8,
17.88 +};
17.89 +
17.90 +enum Dma_command_bits : unsigned
17.91 +{
17.92 + Dma_source_address_increment = 0x800000,
17.93 + Dma_source_address_no_increment = 0x000000,
17.94 + Dma_destination_address_increment = 0x400000,
17.95 + Dma_destination_address_no_increment = 0x000000,
17.96 +
17.97 + Dma_source_address_increment_wrap = 0x200000,
17.98 + Dma_destination_address_increment_wrap = 0x100000,
17.99 + Dma_recommended_data_unit_size_mask = 0x0f0000,
17.100 + Dma_source_port_width_mask = 0x00c000,
17.101 + Dma_destination_port_width_mask = 0x003000,
17.102 + Dma_transfer_unit_size_mask = 0x000f00,
17.103 +
17.104 + Dma_trans_unit_size_32_bit = 0x000000,
17.105 + Dma_trans_unit_size_8_bit = 0x000100,
17.106 + Dma_trans_unit_size_16_bit = 0x000200,
17.107 + Dma_trans_unit_size_16_byte = 0x000300,
17.108 + Dma_trans_unit_size_32_byte = 0x000400,
17.109 + Dma_trans_unit_size_64_byte = 0x000500,
17.110 + Dma_trans_unit_size_128_byte = 0x000600,
17.111 + Dma_trans_unit_size_autonomous = 0x000700,
17.112 + Dma_trans_unit_size_external = 0x000800,
17.113 +
17.114 + Dma_source_address_compare_index = 0x000080,
17.115 + Dma_destination_address_compare_index = 0x000040,
17.116 + Dma_stride_enable = 0x000004,
17.117 + Dma_transfer_irq_enable = 0x000002,
17.118 + Dma_descriptor_link_enable = 0x000001,
17.119 +
17.120 + Dma_recommended_data_unit_size_shift = 16,
17.121 + Dma_source_port_width_shift = 14,
17.122 + Dma_destination_port_width_shift = 12,
17.123 + Dma_transfer_unit_size_shift = 8,
17.124 +};
17.125 +
17.126 +enum Dma_port_width_values : unsigned
17.127 +{
17.128 + Dma_port_width_32_bit = 0,
17.129 + Dma_port_width_8_bit = 1,
17.130 + Dma_port_width_16_bit = 2,
17.131 +};
17.132 +
17.133 +
17.134 +
17.135 +// Initialise a channel.
17.136 +
17.137 +Dma_x1600_channel::Dma_x1600_channel(Dma_x1600_chip *chip, uint8_t channel,
17.138 + l4_addr_t start, l4_cap_idx_t irq)
17.139 +: _chip(chip), _channel(channel), _irq(irq)
17.140 +{
17.141 + _regs = new Hw::Mmio_register_block<32>(start);
17.142 +
17.143 + // Initialise the transfer count.
17.144 +
17.145 + _regs[Dma_transfer_count] = 0;
17.146 +}
17.147 +
17.148 +// Return the closest interval length greater than or equal to the number of
17.149 +// units given encoded in the request detection interval length field of the
17.150 +// control/status register.
17.151 +
17.152 +uint32_t
17.153 +Dma_x1600_channel::encode_req_detect_int_length(uint8_t units)
17.154 +{
17.155 + static uint8_t lengths[] = {0, 1, 2, 3, 4, 8, 16, 32, 64, 128};
17.156 + int i;
17.157 +
17.158 + if (!units)
17.159 + return 0;
17.160 +
17.161 + for (i = 0; i <= 9; i++)
17.162 + {
17.163 + if (lengths[i] >= units)
17.164 + break;
17.165 + }
17.166 +
17.167 + return i << Dma_recommended_data_unit_size_shift;
17.168 +}
17.169 +
17.170 +// Encode the appropriate source port width for the given request type.
17.171 +
17.172 +uint32_t
17.173 +Dma_x1600_channel::encode_source_port_width(uint8_t width)
17.174 +{
17.175 + switch (width)
17.176 + {
17.177 + case 1:
17.178 + return Dma_port_width_8_bit << Dma_source_port_width_shift;
17.179 +
17.180 + case 2:
17.181 + return Dma_port_width_16_bit << Dma_source_port_width_shift;
17.182 +
17.183 + default:
17.184 + return Dma_port_width_32_bit << Dma_source_port_width_shift;
17.185 + }
17.186 +}
17.187 +
17.188 +// Encode the appropriate destination port width for the given request type.
17.189 +
17.190 +uint32_t
17.191 +Dma_x1600_channel::encode_destination_port_width(uint8_t width)
17.192 +{
17.193 + switch (width)
17.194 + {
17.195 + case 1:
17.196 + return Dma_port_width_8_bit << Dma_destination_port_width_shift;
17.197 +
17.198 + case 2:
17.199 + return Dma_port_width_16_bit << Dma_destination_port_width_shift;
17.200 +
17.201 + default:
17.202 + return Dma_port_width_32_bit << Dma_destination_port_width_shift;
17.203 + }
17.204 +}
17.205 +
17.206 +// Encode the transfer unit size.
17.207 +// NOTE: This does not handle the external case.
17.208 +
17.209 +uint32_t
17.210 +Dma_x1600_channel::encode_transfer_unit_size(uint8_t size)
17.211 +{
17.212 + switch (size)
17.213 + {
17.214 + case 0:
17.215 + return Dma_trans_unit_size_autonomous;
17.216 +
17.217 + case 1:
17.218 + return Dma_trans_unit_size_8_bit;
17.219 +
17.220 + case 2:
17.221 + return Dma_trans_unit_size_16_bit;
17.222 +
17.223 + case 16:
17.224 + return Dma_trans_unit_size_16_byte;
17.225 +
17.226 + case 32:
17.227 + return Dma_trans_unit_size_32_byte;
17.228 +
17.229 + case 64:
17.230 + return Dma_trans_unit_size_64_byte;
17.231 +
17.232 + case 128:
17.233 + return Dma_trans_unit_size_128_byte;
17.234 +
17.235 + default:
17.236 + return Dma_trans_unit_size_32_bit;
17.237 + }
17.238 +}
17.239 +
17.240 +// Transfer data between memory locations.
17.241 +
17.242 +unsigned int
17.243 +Dma_x1600_channel::transfer(uint32_t source, uint32_t destination,
17.244 + unsigned int count,
17.245 + bool source_increment, bool destination_increment,
17.246 + uint8_t source_width, uint8_t destination_width,
17.247 + uint8_t transfer_unit_size,
17.248 + enum Dma_x1600_request_type type)
17.249 +{
17.250 + printf("transfer:%s%s%s%s\n", error() ? " error" : "",
17.251 + halted() ? " halted" : "",
17.252 + completed() ? " completed" : "",
17.253 + _regs[Dma_transfer_count] ? " count" : "");
17.254 +
17.255 + // Ensure an absence of address error and halt conditions globally and in this channel.
17.256 +
17.257 + if (error() || halted())
17.258 + return 0;
17.259 +
17.260 + // Ensure an absence of transaction completed and zero transfer count for this channel.
17.261 +
17.262 + if (completed() || _regs[Dma_transfer_count])
17.263 + return 0;
17.264 +
17.265 + // Disable the channel.
17.266 +
17.267 + _regs[Dma_control_status] = _regs[Dma_control_status] & ~Dma_channel_enable;
17.268 +
17.269 + // Set addresses.
17.270 +
17.271 + _regs[Dma_source] = source;
17.272 + _regs[Dma_destination] = destination;
17.273 +
17.274 + // Set transfer count to the number of units.
17.275 +
17.276 + unsigned int units = count < Dma_transfer_count_mask ? count : Dma_transfer_count_mask;
17.277 +
17.278 + _regs[Dma_transfer_count] = units;
17.279 +
17.280 + // Set auto-request for memory-to-memory transfers. Otherwise, set the
17.281 + // indicated request type.
17.282 +
17.283 + _regs[Dma_request_source] = type;
17.284 +
17.285 + // For a descriptor, the actual fields would be populated instead of the
17.286 + // command register, descriptor transfer would be indicated in the control/
17.287 + // status register along with the appropriate descriptor size indicator.
17.288 +
17.289 + /* NOTE: To be considered...
17.290 + * request detection interval length (for autonomous mode)
17.291 + */
17.292 +
17.293 + _regs[Dma_command] = (source_increment ? Dma_source_address_increment : Dma_source_address_no_increment) |
17.294 + (destination_increment ? Dma_destination_address_increment : Dma_destination_address_no_increment) |
17.295 + encode_source_port_width(source_width) |
17.296 + encode_destination_port_width(destination_width) |
17.297 + encode_transfer_unit_size(transfer_unit_size) |
17.298 + Dma_transfer_irq_enable;
17.299 +
17.300 + // For a descriptor, the descriptor address would be set and the doorbell
17.301 + // register field for the channel set.
17.302 +
17.303 + // Enable the channel (and peripheral).
17.304 +
17.305 + _regs[Dma_control_status] = Dma_no_descriptor_transfer |
17.306 + Dma_channel_enable;
17.307 +
17.308 + // Return the number of units to transfer.
17.309 +
17.310 + return units;
17.311 +}
17.312 +
17.313 +unsigned int
17.314 +Dma_x1600_channel::wait()
17.315 +{
17.316 + // An interrupt will occur upon completion, the completion flag will be set
17.317 + // and the transfer count will be zero.
17.318 +
17.319 + unsigned int remaining = 0;
17.320 +
17.321 + do
17.322 + {
17.323 + if (!wait_for_irq(1000000))
17.324 + printf("status = %x\n", (uint32_t) _regs[Dma_control_status]);
17.325 + else
17.326 + {
17.327 + printf("status = %x\n", (uint32_t) _regs[Dma_control_status]);
17.328 + remaining = _regs[Dma_transfer_count];
17.329 + ack_irq();
17.330 + break;
17.331 + }
17.332 + }
17.333 + while (!error() && !halted() && !completed());
17.334 +
17.335 + // Reset the channel status.
17.336 +
17.337 + _regs[Dma_control_status] = _regs[Dma_control_status] & ~(Dma_channel_enable |
17.338 + Dma_trans_completed | Dma_address_error |
17.339 + Dma_trans_halted);
17.340 + _regs[Dma_transfer_count] = 0;
17.341 +
17.342 + // Return the number of remaining units.
17.343 +
17.344 + return remaining;
17.345 +}
17.346 +
17.347 +// Wait indefinitely for an interrupt request, returning true if one was delivered.
17.348 +
17.349 +bool
17.350 +Dma_x1600_channel::wait_for_irq()
17.351 +{
17.352 + return !l4_error(l4_irq_receive(_irq, L4_IPC_NEVER)) && _chip->have_interrupt(_channel);
17.353 +}
17.354 +
17.355 +// Wait up to the given timeout (in microseconds) for an interrupt request,
17.356 +// returning true if one was delivered.
17.357 +
17.358 +bool
17.359 +Dma_x1600_channel::wait_for_irq(unsigned int timeout)
17.360 +{
17.361 + return !l4_error(l4_irq_receive(_irq, l4_timeout(L4_IPC_TIMEOUT_NEVER, l4util_micros2l4to(timeout)))) && _chip->have_interrupt(_channel);
17.362 +}
17.363 +
17.364 +// Acknowledge an interrupt condition.
17.365 +
17.366 +void
17.367 +Dma_x1600_channel::ack_irq()
17.368 +{
17.369 + _chip->ack_irq(_channel);
17.370 +}
17.371 +
17.372 +// Return whether a transfer has completed.
17.373 +
17.374 +bool
17.375 +Dma_x1600_channel::completed()
17.376 +{
17.377 + return _regs[Dma_control_status] & Dma_trans_completed ? true : false;
17.378 +}
17.379 +
17.380 +// Return whether an address error condition has arisen.
17.381 +
17.382 +bool
17.383 +Dma_x1600_channel::error()
17.384 +{
17.385 + return _chip->error() || (_regs[Dma_control_status] & Dma_address_error ? true : false);
17.386 +}
17.387 +
17.388 +// Return whether a transfer has halted.
17.389 +
17.390 +bool
17.391 +Dma_x1600_channel::halted()
17.392 +{
17.393 + return _chip->halted() || (_regs[Dma_control_status] & Dma_trans_halted ? true : false);
17.394 +}
17.395 +
17.396 +
17.397 +
17.398 +// Initialise the I2C controller.
17.399 +
17.400 +Dma_x1600_chip::Dma_x1600_chip(l4_addr_t start, l4_addr_t end,
17.401 + Cpm_x1600_chip *cpm)
17.402 +: _start(start), _end(end), _cpm(cpm)
17.403 +{
17.404 + _regs = new Hw::Mmio_register_block<32>(start);
17.405 +}
17.406 +
17.407 +// Enable the peripheral.
17.408 +
17.409 +void
17.410 +Dma_x1600_chip::enable()
17.411 +{
17.412 + // Make sure that the DMA clock is available.
17.413 +
17.414 + _cpm->start_clock(Clock_dma);
17.415 +
17.416 + _regs[Dma_control] = Dma_control_enable;
17.417 + while (!(_regs[Dma_control] & Dma_control_enable));
17.418 +}
17.419 +
17.420 +// Disable the channel.
17.421 +
17.422 +void
17.423 +Dma_x1600_chip::disable()
17.424 +{
17.425 + _regs[Dma_control] = 0;
17.426 + while (_regs[Dma_control] & Dma_control_enable);
17.427 +}
17.428 +
17.429 +// Obtain a channel object.
17.430 +
17.431 +Dma_x1600_channel *
17.432 +Dma_x1600_chip::get_channel(uint8_t channel, l4_cap_idx_t irq)
17.433 +{
17.434 + if (channel < 32)
17.435 + return new Dma_x1600_channel(this, channel, _start + 0x20 * channel, irq);
17.436 + else
17.437 + throw -L4_EINVAL;
17.438 +}
17.439 +
17.440 +// Return whether an interrupt is pending on the given channel.
17.441 +
17.442 +bool
17.443 +Dma_x1600_chip::have_interrupt(uint8_t channel)
17.444 +{
17.445 + return _regs[Dma_irq_pending] & (1 << channel) ? true : false;
17.446 +}
17.447 +
17.448 +// Acknowledge an interrupt condition on the given channel.
17.449 +
17.450 +void
17.451 +Dma_x1600_chip::ack_irq(uint8_t channel)
17.452 +{
17.453 + _regs[Dma_irq_pending] = _regs[Dma_irq_pending] & ~(1 << channel);
17.454 +}
17.455 +
17.456 +// Return whether an address error condition has arisen.
17.457 +
17.458 +bool
17.459 +Dma_x1600_chip::error()
17.460 +{
17.461 + return _regs[Dma_control] & Dma_control_address_error ? true : false;
17.462 +}
17.463 +
17.464 +// Return whether a transfer has halted.
17.465 +
17.466 +bool
17.467 +Dma_x1600_chip::halted()
17.468 +{
17.469 + return _regs[Dma_control] & Dma_control_trans_halted ? true : false;
17.470 +}
17.471 +
17.472 +
17.473 +
17.474 +// C language interface functions.
17.475 +
17.476 +void *x1600_dma_init(l4_addr_t start, l4_addr_t end, void *cpm)
17.477 +{
17.478 + return (void *) new Dma_x1600_chip(start, end, static_cast<Cpm_x1600_chip *>(cpm));
17.479 +}
17.480 +
17.481 +void x1600_dma_disable(void *dma_chip)
17.482 +{
17.483 + static_cast<Dma_x1600_chip *>(dma_chip)->disable();
17.484 +}
17.485 +
17.486 +void x1600_dma_enable(void *dma_chip)
17.487 +{
17.488 + static_cast<Dma_x1600_chip *>(dma_chip)->enable();
17.489 +}
17.490 +
17.491 +void *x1600_dma_get_channel(void *dma, uint8_t channel, l4_cap_idx_t irq)
17.492 +{
17.493 + return static_cast<Dma_x1600_chip *>(dma)->get_channel(channel, irq);
17.494 +}
17.495 +
17.496 +unsigned int x1600_dma_transfer(void *dma_channel,
17.497 + uint32_t source, uint32_t destination,
17.498 + unsigned int count,
17.499 + int source_increment, int destination_increment,
17.500 + uint8_t source_width, uint8_t destination_width,
17.501 + uint8_t transfer_unit_size,
17.502 + enum Dma_x1600_request_type type)
17.503 +{
17.504 + return static_cast<Dma_x1600_channel *>(dma_channel)->transfer(source,
17.505 + destination, count, source_increment, destination_increment, source_width,
17.506 + destination_width, transfer_unit_size, type);
17.507 +}
17.508 +
17.509 +unsigned int x1600_dma_wait(void *dma_channel)
17.510 +{
17.511 + return static_cast<Dma_x1600_channel *>(dma_channel)->wait();
17.512 +}
18.1 --- a/pkg/devices/lib/gpio/include/gpio-jz4730.h Fri Sep 22 21:56:34 2023 +0200
18.2 +++ b/pkg/devices/lib/gpio/include/gpio-jz4730.h Tue Oct 24 18:52:06 2023 +0200
18.3 @@ -2,7 +2,7 @@
18.4 * GPIO driver for Ingenic JZ4730.
18.5 * (See below for additional copyright and licensing notices.)
18.6 *
18.7 - * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
18.8 + * Copyright (C) 2017, 2018, 2023 Paul Boddie <paul@boddie.org.uk>
18.9 *
18.10 * This program is free software; you can redistribute it and/or
18.11 * modify it under the terms of the GNU General Public License as
18.12 @@ -117,6 +117,11 @@
18.13
18.14 void _config_pad(unsigned bitmap, unsigned func, unsigned value);
18.15
18.16 + // Paired register field access.
18.17 +
18.18 + void _get_pin_value(unsigned pin, uint32_t reg_upper, uint32_t reg_lower,
18.19 + unsigned *value);
18.20 +
18.21 public:
18.22 Gpio_jz4730_chip(l4_addr_t start, l4_addr_t end,
18.23 unsigned nr_pins);
18.24 @@ -136,6 +141,7 @@
18.25 void config_pull(unsigned pin, unsigned mode);
18.26 void config_pad(unsigned pin, unsigned func, unsigned value);
18.27 void config_get(unsigned pin, unsigned reg, unsigned *value);
18.28 + void config_pad_get(unsigned pin, unsigned *func, unsigned *value);
18.29
18.30 // Multiple pin configuration methods.
18.31
18.32 @@ -172,6 +178,7 @@
18.33 void jz4730_gpio_config_pull(void *gpio, unsigned pin, unsigned mode);
18.34 void jz4730_gpio_config_pad(void *gpio, unsigned pin, unsigned func, unsigned value);
18.35 void jz4730_gpio_config_get(void *gpio, unsigned pin, unsigned reg, unsigned *value);
18.36 +void jz4730_gpio_config_pad_get(void *gpio, unsigned pin, unsigned *func, unsigned *value);
18.37
18.38 void jz4730_gpio_multi_setup(void *gpio, Pin_slice const *mask, unsigned mode, unsigned outvalues);
18.39 void jz4730_gpio_multi_config_pull(void *gpio, Pin_slice const *mask, unsigned mode);
19.1 --- a/pkg/devices/lib/gpio/include/gpio-jz4740.h Fri Sep 22 21:56:34 2023 +0200
19.2 +++ b/pkg/devices/lib/gpio/include/gpio-jz4740.h Tue Oct 24 18:52:06 2023 +0200
19.3 @@ -2,7 +2,7 @@
19.4 * GPIO driver for Ingenic JZ4740.
19.5 * (See below for additional copyright and licensing notices.)
19.6 *
19.7 - * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
19.8 + * Copyright (C) 2017, 2018, 2023 Paul Boddie <paul@boddie.org.uk>
19.9 *
19.10 * This program is free software; you can redistribute it and/or
19.11 * modify it under the terms of the GNU General Public License as
19.12 @@ -128,6 +128,7 @@
19.13 void config_pull(unsigned pin, unsigned mode);
19.14 void config_pad(unsigned pin, unsigned func, unsigned value);
19.15 void config_get(unsigned pin, unsigned reg, unsigned *value);
19.16 + void config_pad_get(unsigned pin, unsigned *func, unsigned *value);
19.17
19.18 // Multiple pin configuration methods.
19.19
19.20 @@ -164,6 +165,7 @@
19.21 void jz4740_gpio_config_pull(void *gpio, unsigned pin, unsigned mode);
19.22 void jz4740_gpio_config_pad(void *gpio, unsigned pin, unsigned func, unsigned value);
19.23 void jz4740_gpio_config_get(void *gpio, unsigned pin, unsigned reg, unsigned *value);
19.24 +void jz4740_gpio_config_pad_get(void *gpio, unsigned pin, unsigned *func, unsigned *value);
19.25
19.26 void jz4740_gpio_multi_setup(void *gpio, Pin_slice const *mask, unsigned mode, unsigned outvalues);
19.27 void jz4740_gpio_multi_config_pull(void *gpio, Pin_slice const *mask, unsigned mode);
20.1 --- a/pkg/devices/lib/gpio/include/gpio-jz4780.h Fri Sep 22 21:56:34 2023 +0200
20.2 +++ b/pkg/devices/lib/gpio/include/gpio-jz4780.h Tue Oct 24 18:52:06 2023 +0200
20.3 @@ -2,7 +2,7 @@
20.4 * GPIO driver for Ingenic JZ4780.
20.5 * (See below for additional copyright and licensing notices.)
20.6 *
20.7 - * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
20.8 + * Copyright (C) 2017, 2018, 2023 Paul Boddie <paul@boddie.org.uk>
20.9 *
20.10 * This program is free software; you can redistribute it and/or
20.11 * modify it under the terms of the GNU General Public License as
20.12 @@ -118,6 +118,7 @@
20.13 void config_pull(unsigned pin, unsigned mode);
20.14 void config_pad(unsigned pin, unsigned func, unsigned value);
20.15 void config_get(unsigned pin, unsigned reg, unsigned *value);
20.16 + void config_pad_get(unsigned pin, unsigned *func, unsigned *value);
20.17
20.18 // Multiple pin configuration methods.
20.19
20.20 @@ -154,6 +155,7 @@
20.21 void jz4780_gpio_config_pull(void *gpio, unsigned pin, unsigned mode);
20.22 void jz4780_gpio_config_pad(void *gpio, unsigned pin, unsigned func, unsigned value);
20.23 void jz4780_gpio_config_get(void *gpio, unsigned pin, unsigned reg, unsigned *value);
20.24 +void jz4780_gpio_config_pad_get(void *gpio, unsigned pin, unsigned *func, unsigned *value);
20.25
20.26 void jz4780_gpio_multi_setup(void *gpio, Pin_slice const *mask, unsigned mode, unsigned outvalues);
20.27 void jz4780_gpio_multi_config_pad(void *gpio, Pin_slice const *mask, unsigned func, unsigned value);
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
21.2 +++ b/pkg/devices/lib/gpio/include/gpio-x1600.h Tue Oct 24 18:52:06 2023 +0200
21.3 @@ -0,0 +1,171 @@
21.4 +/*
21.5 + * GPIO driver for Ingenic X1600.
21.6 + * (See below for additional copyright and licensing notices.)
21.7 + *
21.8 + * Copyright (C) 2017, 2018, 2023 Paul Boddie <paul@boddie.org.uk>
21.9 + *
21.10 + * This program is free software; you can redistribute it and/or
21.11 + * modify it under the terms of the GNU General Public License as
21.12 + * published by the Free Software Foundation; either version 2 of
21.13 + * the License, or (at your option) any later version.
21.14 + *
21.15 + * This program is distributed in the hope that it will be useful,
21.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
21.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21.18 + * GNU General Public License for more details.
21.19 + *
21.20 + * You should have received a copy of the GNU General Public License
21.21 + * along with this program; if not, write to the Free Software
21.22 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
21.23 + * Boston, MA 02110-1301, USA
21.24 + *
21.25 + *
21.26 + * Subject to other copyrights, being derived from the bcm2835.cc and
21.27 + * omap.cc GPIO driver implementations.
21.28 + *
21.29 + * This file is part of TUD:OS and distributed under the terms of the
21.30 + * GNU General Public License 2.
21.31 + * Please see the COPYING-GPL-2 file for details.
21.32 + */
21.33 +
21.34 +#pragma once
21.35 +
21.36 +#include <l4/sys/err.h>
21.37 +#include <l4/sys/types.h>
21.38 +#include <stdint.h>
21.39 +#include "gpio.h"
21.40 +
21.41 +
21.42 +
21.43 +#ifdef __cplusplus
21.44 +
21.45 +#include <l4/devices/hw_mmio_register_block.h>
21.46 +
21.47 +// GPIO device control.
21.48 +
21.49 +class Gpio_x1600_irq_pin : public Hw::Gpio_irq_pin
21.50 +{
21.51 + unsigned _pin;
21.52 + Hw::Register_block<32> _regs;
21.53 +
21.54 + // Convenience method for obtaining the bit corresponding to a pin.
21.55 +
21.56 + l4_uint32_t _pin_bit(unsigned pin)
21.57 + { return 1 << (pin & 31); }
21.58 +
21.59 + void write_reg_pin(unsigned reg);
21.60 +
21.61 +public:
21.62 + Gpio_x1600_irq_pin(unsigned pin, Hw::Register_block<32> const ®s);
21.63 +
21.64 + void do_mask();
21.65 + void do_unmask();
21.66 + bool do_set_mode(unsigned mode);
21.67 + int clear();
21.68 + bool enabled();
21.69 +};
21.70 +
21.71 +class Gpio_x1600_chip : public Hw::Gpio_chip
21.72 +{
21.73 +private:
21.74 + Hw::Register_block<32> _regs;
21.75 +
21.76 + l4_addr_t _start, _end;
21.77 + unsigned _nr_pins;
21.78 + l4_uint32_t _pull_ups, _pull_downs;
21.79 +
21.80 + // Convenience method for obtaining the bit corresponding to a pin.
21.81 +
21.82 + l4_uint32_t _pin_bit(unsigned pin)
21.83 + { return 1 << (pin & 31); }
21.84 +
21.85 + // Convenience method for obtaining the bit position of a pin.
21.86 +
21.87 + unsigned _pin_shift(unsigned pin)
21.88 + { return pin % 32; }
21.89 +
21.90 + // Permit only "aligned" accesses to registers.
21.91 +
21.92 + unsigned _reg_offset_check(unsigned pin_offset) const
21.93 + {
21.94 + switch (pin_offset)
21.95 + {
21.96 + case 0:
21.97 + return 0;
21.98 +
21.99 + default:
21.100 + throw -L4_EINVAL;
21.101 + }
21.102 + }
21.103 +
21.104 +public:
21.105 + Gpio_x1600_chip(l4_addr_t start, l4_addr_t end,
21.106 + unsigned nr_pins,
21.107 + l4_uint32_t pull_ups, l4_uint32_t pull_downs);
21.108 +
21.109 + // Obtain the number of pins.
21.110 +
21.111 + unsigned nr_pins() const { return _nr_pins; }
21.112 +
21.113 + // Unnecessary operations.
21.114 +
21.115 + void request(unsigned) {}
21.116 + void free(unsigned) {}
21.117 +
21.118 + // Configuration methods.
21.119 +
21.120 + void setup(unsigned pin, unsigned mode, int value = 0);
21.121 + void config_pull(unsigned pin, unsigned mode);
21.122 + void config_pad(unsigned pin, unsigned func, unsigned value);
21.123 + void config_get(unsigned pin, unsigned reg, unsigned *value);
21.124 + void config_pad_get(unsigned pin, unsigned *func, unsigned *value);
21.125 +
21.126 + // Multiple pin configuration methods.
21.127 +
21.128 + void multi_setup(Pin_slice const &mask, unsigned mode, unsigned outvalues = 0);
21.129 + void multi_config_pad(Pin_slice const &mask, unsigned func, unsigned value = 0);
21.130 + void multi_set(Pin_slice const &mask, unsigned data);
21.131 + unsigned multi_get(unsigned offset);
21.132 +
21.133 + // IRQ pin configuration.
21.134 +
21.135 + Hw::Gpio_irq_pin *get_irq(unsigned pin);
21.136 +
21.137 + // Pin/port data methods.
21.138 +
21.139 + int get(unsigned pin);
21.140 + void set(unsigned pin, int value);
21.141 +
21.142 +private:
21.143 + void config(unsigned pin, unsigned mode);
21.144 +};
21.145 +
21.146 +#endif /* __cplusplus */
21.147 +
21.148 +
21.149 +
21.150 +/* C language interface. */
21.151 +
21.152 +EXTERN_C_BEGIN
21.153 +
21.154 +void *x1600_gpio_init(l4_addr_t start, l4_addr_t end, unsigned pins,
21.155 + l4_uint32_t pull_ups, l4_uint32_t pull_downs);
21.156 +
21.157 +void x1600_gpio_setup(void *gpio, unsigned pin, unsigned mode, int value);
21.158 +void x1600_gpio_config_pull(void *gpio, unsigned pin, unsigned mode);
21.159 +void x1600_gpio_config_pad(void *gpio, unsigned pin, unsigned func, unsigned value);
21.160 +void x1600_gpio_config_get(void *gpio, unsigned pin, unsigned reg, unsigned *value);
21.161 +void x1600_gpio_config_pad_get(void *gpio, unsigned pin, unsigned *func, unsigned *value);
21.162 +
21.163 +void x1600_gpio_multi_setup(void *gpio, Pin_slice const *mask, unsigned mode, unsigned outvalues);
21.164 +void x1600_gpio_multi_config_pad(void *gpio, Pin_slice const *mask, unsigned func, unsigned value);
21.165 +void x1600_gpio_multi_set(void *gpio, Pin_slice const *mask, unsigned data);
21.166 +unsigned x1600_gpio_multi_get(void *gpio, unsigned offset);
21.167 +
21.168 +int x1600_gpio_get(void *gpio, unsigned pin);
21.169 +void x1600_gpio_set(void *gpio, unsigned pin, int value);
21.170 +
21.171 +void *x1600_gpio_get_irq(void *gpio, unsigned pin);
21.172 +bool x1600_gpio_irq_set_mode(void *gpio_irq, unsigned mode);
21.173 +
21.174 +EXTERN_C_END
22.1 --- a/pkg/devices/lib/gpio/include/gpio.h Fri Sep 22 21:56:34 2023 +0200
22.2 +++ b/pkg/devices/lib/gpio/include/gpio.h Tue Oct 24 18:52:06 2023 +0200
22.3 @@ -2,7 +2,7 @@
22.4 * GPIO driver definitions.
22.5 * (See below for additional copyright and licensing notices.)
22.6 *
22.7 - * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
22.8 + * Copyright (C) 2017, 2018, 2023 Paul Boddie <paul@boddie.org.uk>
22.9 *
22.10 * This program is free software; you can redistribute it and/or
22.11 * modify it under the terms of the GNU General Public License as
22.12 @@ -80,6 +80,7 @@
22.13 {
22.14 Function_gpio,
22.15 Function_alt,
22.16 + Function_irq,
22.17 };
22.18
22.19 virtual void request(unsigned pin) = 0;
22.20 @@ -123,6 +124,14 @@
22.21 virtual void config_get(unsigned pin, unsigned func, unsigned *value) = 0;
22.22
22.23 /**
22.24 + * \brief Get platform specific pad configuration.
22.25 + * \param pin the pin to configure.
22.26 + * \param func a platform specific sub-function of a pad to be configured
22.27 + * \param value a platform specific value for the given sub-function.
22.28 + */
22.29 + virtual void config_pad_get(unsigned pin, unsigned *func, unsigned *value) = 0;
22.30 +
22.31 + /**
22.32 * \brief Get the value of the given pin (generic API).
22.33 * \param pin the pin to read the value from.
22.34 */
22.35 @@ -210,6 +219,7 @@
22.36 {
22.37 Function_gpio,
22.38 Function_alt,
22.39 + Function_irq,
22.40 };
22.41
22.42 #endif /* __cplusplus */
23.1 --- a/pkg/devices/lib/gpio/src/Makefile Fri Sep 22 21:56:34 2023 +0200
23.2 +++ b/pkg/devices/lib/gpio/src/Makefile Tue Oct 24 18:52:06 2023 +0200
23.3 @@ -4,7 +4,7 @@
23.4 TARGET = libgpio.o.a libgpio.o.so
23.5 PC_FILENAME := libdrivers-gpio
23.6
23.7 -SRC_CC := jz4730.cc jz4740.cc jz4780.cc
23.8 +SRC_CC := jz4730.cc jz4740.cc jz4780.cc x1600.cc
23.9
23.10 PRIVATE_INCDIR += $(PKGDIR)/lib/gpio/include
23.11
24.1 --- a/pkg/devices/lib/gpio/src/jz4730.cc Fri Sep 22 21:56:34 2023 +0200
24.2 +++ b/pkg/devices/lib/gpio/src/jz4730.cc Tue Oct 24 18:52:06 2023 +0200
24.3 @@ -2,7 +2,7 @@
24.4 * GPIO driver for Ingenic JZ4730.
24.5 * (See below for additional copyright and licensing notices.)
24.6 *
24.7 - * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
24.8 + * Copyright (C) 2017, 2018, 2023 Paul Boddie <paul@boddie.org.uk>
24.9 *
24.10 * This program is free software; you can redistribute it and/or
24.11 * modify it under the terms of the GNU General Public License as
24.12 @@ -46,6 +46,7 @@
24.13 Irq_detect_lower = 0x018, // PxGPDLR
24.14 Irq_detect_upper = 0x01c, // PxGPDUR
24.15 Irq_enable = 0x020, // PxGPIER
24.16 + Irq_mask = 0x024, // PxGPIM
24.17 Irq_flag = 0x028, // PxGPFR
24.18 };
24.19
24.20 @@ -70,8 +71,6 @@
24.21 }
24.22 }
24.23
24.24 -
24.25 -
24.26 // IRQ control for each GPIO pin.
24.27
24.28 Gpio_jz4730_irq_pin::Gpio_jz4730_irq_pin(unsigned pin, Hw::Register_block<32> const ®s)
24.29 @@ -129,6 +128,9 @@
24.30 {
24.31 // Set the interrupt bit in the PxGPIER register.
24.32
24.33 + /* NOTE: This should use the Irq_mask/PxGPIM register, with the enable
24.34 + register actually setting IRQ mode. */
24.35 +
24.36 clear_reg_pin(Irq_enable);
24.37 }
24.38
24.39 @@ -137,6 +139,9 @@
24.40 // Set the interrupt bit in the PxGPIER register, first also clearing the
24.41 // flag bit in the PxGPFR register to allow interrupts to be delivered.
24.42
24.43 + /* NOTE: This should use the Irq_mask/PxGPIM register, with the enable
24.44 + register actually setting IRQ mode. */
24.45 +
24.46 clear_reg_pin(Irq_flag);
24.47 set_reg_pin(Irq_enable);
24.48 }
24.49 @@ -306,19 +311,23 @@
24.50 Gpio_jz4730_chip::_config(unsigned bitmap, unsigned mode)
24.51 {
24.52 uint32_t upper_mask, lower_mask;
24.53 - unsigned bitmap_values = bitmap;
24.54
24.55 switch (mode)
24.56 {
24.57 case Input:
24.58 case Irq:
24.59 - // Clear the direction flags below.
24.60 - bitmap_values = 0;
24.61 - // Fall through to the next case to complete the operation.
24.62 + // Clear the direction flags.
24.63 + _regs[Port_direction] = _regs[Port_direction] & ~bitmap;
24.64 +
24.65 + // Clear the port function for the bits.
24.66 + _get_bitmaps(bitmap, 3, &upper_mask, &lower_mask);
24.67 + _regs[Port_function_upper] = (_regs[Port_function_upper] & ~upper_mask);
24.68 + _regs[Port_function_lower] = (_regs[Port_function_lower] & ~lower_mask);
24.69 + break;
24.70
24.71 case Output:
24.72 - // Clear the flags if set immediately above; otherwise, set them.
24.73 - _regs[Port_direction] = (_regs[Port_direction] & ~bitmap) | bitmap_values;
24.74 + // Set the direction flags.
24.75 + _regs[Port_direction] = _regs[Port_direction] | bitmap;
24.76
24.77 // Clear the port function for the bits.
24.78 _get_bitmaps(bitmap, 3, &upper_mask, &lower_mask);
24.79 @@ -382,12 +391,15 @@
24.80 {
24.81 case Hw::Gpio_chip::Function_alt:
24.82 _get_bitmaps(bitmap, value, &upper, &lower);
24.83 - // Fall through to the next case to complete the operation.
24.84 + _get_bitmaps(bitmap, 3, &upper_mask, &lower_mask);
24.85 + _regs[Port_function_upper] = (_regs[Port_function_upper] & ~upper_mask) | upper;
24.86 + _regs[Port_function_lower] = (_regs[Port_function_lower] & ~lower_mask) | lower;
24.87 + break;
24.88
24.89 case Hw::Gpio_chip::Function_gpio:
24.90 _get_bitmaps(bitmap, 3, &upper_mask, &lower_mask);
24.91 - _regs[Port_function_upper] = (_regs[Port_function_upper] & ~upper_mask) | upper;
24.92 - _regs[Port_function_lower] = (_regs[Port_function_lower] & ~lower_mask) | lower;
24.93 + _regs[Port_function_upper] = _regs[Port_function_upper] & ~upper_mask;
24.94 + _regs[Port_function_lower] = _regs[Port_function_lower] & ~lower_mask;
24.95 break;
24.96
24.97 default:
24.98 @@ -406,6 +418,62 @@
24.99 *value = (_regs[reg] >> _pin_shift(pin)) & 1;
24.100 }
24.101
24.102 +// Return function and function-specific configuration for a pin.
24.103 +
24.104 +void
24.105 +Gpio_jz4730_chip::config_pad_get(unsigned pin, unsigned *func, unsigned *value)
24.106 +{
24.107 + unsigned detect, direction, pin_function, interrupt;
24.108 +
24.109 + // Get the pin function using the awkward register pairing.
24.110 +
24.111 + _get_pin_value(pin, Port_function_upper, Port_function_lower, &pin_function);
24.112 +
24.113 + if (pin_function)
24.114 + {
24.115 + *func = Hw::Gpio_chip::Function_alt;
24.116 + *value = pin_function;
24.117 + return;
24.118 + }
24.119 +
24.120 + config_get(pin, Irq_enable, &interrupt);
24.121 +
24.122 + if (interrupt)
24.123 + {
24.124 + _get_pin_value(pin, Irq_detect_upper, Irq_detect_lower, &detect);
24.125 +
24.126 + *func = Hw::Gpio_chip::Function_irq;
24.127 +
24.128 + switch (detect)
24.129 + {
24.130 + case 0: *value = L4_IRQ_F_LEVEL_LOW; break;
24.131 + case 1: *value = L4_IRQ_F_LEVEL_HIGH; break;
24.132 + case 2: *value = L4_IRQ_F_NEG_EDGE; break;
24.133 + default: case 3: *value = L4_IRQ_F_POS_EDGE; break;
24.134 + }
24.135 + return;
24.136 + }
24.137 +
24.138 + config_get(pin, Port_direction, &direction);
24.139 +
24.140 + *func = Hw::Gpio_chip::Function_gpio;
24.141 + *value = direction ? Output : Input;
24.142 +}
24.143 +
24.144 +void
24.145 +Gpio_jz4730_chip::_get_pin_value(unsigned pin, uint32_t reg_upper,
24.146 + uint32_t reg_lower, unsigned *value)
24.147 +{
24.148 + uint8_t pin_out;
24.149 +
24.150 + if (pin >= _nr_pins)
24.151 + throw -L4_EINVAL;
24.152 +
24.153 + uint32_t reg = _select_bank_for_pin(reg_upper, reg_lower, pin, &pin_out);
24.154 +
24.155 + *value = (_regs[reg] & (3 << (pin_out << 1))) >> (pin_out << 1);
24.156 +}
24.157 +
24.158 // Obtain an IRQ abstraction for a pin.
24.159
24.160 Hw::Gpio_irq_pin *
24.161 @@ -473,6 +541,11 @@
24.162 static_cast<Gpio_jz4730_chip *>(gpio)->config_get(pin, reg, value);
24.163 }
24.164
24.165 +void jz4730_gpio_config_pad_get(void *gpio, unsigned pin, unsigned *func, unsigned *value)
24.166 +{
24.167 + static_cast<Gpio_jz4730_chip *>(gpio)->config_pad_get(pin, func, value);
24.168 +}
24.169 +
24.170 void jz4730_gpio_multi_setup(void *gpio, Pin_slice const *mask, unsigned mode, unsigned outvalues)
24.171 {
24.172 static_cast<Gpio_jz4730_chip *>(gpio)->multi_setup(*mask, mode, outvalues);
25.1 --- a/pkg/devices/lib/gpio/src/jz4740.cc Fri Sep 22 21:56:34 2023 +0200
25.2 +++ b/pkg/devices/lib/gpio/src/jz4740.cc Tue Oct 24 18:52:06 2023 +0200
25.3 @@ -2,7 +2,7 @@
25.4 * GPIO driver for Ingenic JZ4740.
25.5 * (See below for additional copyright and licensing notices.)
25.6 *
25.7 - * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
25.8 + * Copyright (C) 2017, 2018, 2023 Paul Boddie <paul@boddie.org.uk>
25.9 *
25.10 * This program is free software; you can redistribute it and/or
25.11 * modify it under the terms of the GNU General Public License as
25.12 @@ -339,6 +339,38 @@
25.13 *value = (_regs[reg] >> _pin_shift(pin)) & 1;
25.14 }
25.15
25.16 +// Return function and function-specific configuration for a pin.
25.17 +
25.18 +void
25.19 +Gpio_jz4740_chip::config_pad_get(unsigned pin, unsigned *func, unsigned *value)
25.20 +{
25.21 + unsigned direction, function, select, trigger;
25.22 +
25.23 + config_get(pin, Port_function, &function);
25.24 + config_get(pin, Port_select, &select);
25.25 + config_get(pin, Port_dir, &direction);
25.26 +
25.27 + if (function)
25.28 + {
25.29 + *func = Hw::Gpio_chip::Function_alt;
25.30 + *value = select;
25.31 + return;
25.32 + }
25.33 +
25.34 + if (select)
25.35 + {
25.36 + config_get(pin, Port_trigger, &trigger);
25.37 +
25.38 + *func = Hw::Gpio_chip::Function_irq;
25.39 + *value = (trigger ? (direction ? L4_IRQ_F_POS_EDGE : L4_IRQ_F_NEG_EDGE)
25.40 + : (direction ? L4_IRQ_F_LEVEL_HIGH : L4_IRQ_F_LEVEL_LOW));
25.41 + return;
25.42 + }
25.43 +
25.44 + *func = Hw::Gpio_chip::Function_gpio;
25.45 + *value = direction ? Input : Output;
25.46 +}
25.47 +
25.48 // Obtain an IRQ abstraction for a pin.
25.49
25.50 Hw::Gpio_irq_pin *
25.51 @@ -406,6 +438,11 @@
25.52 static_cast<Gpio_jz4740_chip *>(gpio)->config_get(pin, reg, value);
25.53 }
25.54
25.55 +void jz4740_gpio_config_pad_get(void *gpio, unsigned pin, unsigned *func, unsigned *value)
25.56 +{
25.57 + static_cast<Gpio_jz4740_chip *>(gpio)->config_pad_get(pin, func, value);
25.58 +}
25.59 +
25.60 void jz4740_gpio_multi_setup(void *gpio, Pin_slice const *mask, unsigned mode, unsigned outvalues)
25.61 {
25.62 static_cast<Gpio_jz4740_chip *>(gpio)->multi_setup(*mask, mode, outvalues);
26.1 --- a/pkg/devices/lib/gpio/src/jz4780.cc Fri Sep 22 21:56:34 2023 +0200
26.2 +++ b/pkg/devices/lib/gpio/src/jz4780.cc Tue Oct 24 18:52:06 2023 +0200
26.3 @@ -2,7 +2,7 @@
26.4 * GPIO driver for Ingenic JZ4780.
26.5 * (See below for additional copyright and licensing notices.)
26.6 *
26.7 - * Copyright (C) 2017 Paul Boddie <paul@boddie.org.uk>
26.8 + * Copyright (C) 2017, 2023 Paul Boddie <paul@boddie.org.uk>
26.9 *
26.10 * This program is free software; you can redistribute it and/or
26.11 * modify it under the terms of the GNU General Public License as
26.12 @@ -47,20 +47,20 @@
26.13 */
26.14
26.15 enum Regs
26.16 -{
26.17 +{
26.18 Pin_level = 0x000, // PxPIN (read-only)
26.19 -
26.20 +
26.21 Port_int = 0x010, // PxINT
26.22 Port_int_set = 0x014, // PxINTS
26.23 Port_int_clear = 0x018, // PxINTC
26.24 -
26.25 +
26.26 Irq_mask = 0x020, // PxMSK (for PxINT == 1)
26.27 Irq_mask_set = 0x024, // PxMSKS
26.28 Irq_mask_clear = 0x028, // PxMSKC
26.29 Port_gpio = 0x020, // PxMSK (for PxINT == 0)
26.30 Port_gpio_set = 0x024, // PxMSKS
26.31 Port_gpio_clear = 0x028, // PxMSKC
26.32 -
26.33 +
26.34 Port_trigger = 0x030, // PxPAT1 (for PxINT == 1)
26.35 Port_trigger_set = 0x034, // PxPAT1S
26.36 Port_trigger_clear = 0x038, // PxPAT1C
26.37 @@ -70,7 +70,7 @@
26.38 Port_group1 = 0x030, // PxPAT1 (for PxINT == 0, PxMSK == 0)
26.39 Port_group1_set = 0x034, // PxPAT1S
26.40 Port_group1_clear = 0x038, // PxPAT1C
26.41 -
26.42 +
26.43 Port_level = 0x040, // PxPAT0 (for PxINT == 1)
26.44 Port_level_set = 0x044, // PxPAT0S
26.45 Port_level_clear = 0x048, // PxPAT0C
26.46 @@ -80,10 +80,10 @@
26.47 Port_group0 = 0x040, // PxPAT0 (for PxINT == 0, PxMSK == 0)
26.48 Port_group0_set = 0x044, // PxPAT0S
26.49 Port_group0_clear = 0x048, // PxPAT0C
26.50 -
26.51 +
26.52 Irq_flag = 0x050, // PxFLG (read-only)
26.53 Irq_flag_clear = 0x058, // PxFLGC
26.54 -
26.55 +
26.56 Pull_disable = 0x070, // PxPE
26.57 Pull_disable_set = 0x074, // PxPES
26.58 Pull_disable_clear = 0x078, // PxPEC
26.59 @@ -317,7 +317,7 @@
26.60 if (pin >= _nr_pins)
26.61 throw -L4_EINVAL;
26.62
26.63 - if (value > 1)
26.64 + if (value > 3)
26.65 throw -L4_EINVAL;
26.66
26.67 switch (func)
26.68 @@ -354,6 +354,45 @@
26.69 *value = (_regs[reg] >> _pin_shift(pin)) & 1;
26.70 }
26.71
26.72 +// Return function and function-specific configuration for a pin.
26.73 +
26.74 +void
26.75 +Gpio_jz4780_chip::config_pad_get(unsigned pin, unsigned *func, unsigned *value)
26.76 +{
26.77 + unsigned direction, gpio, group0, group1, interrupt, level, trigger;
26.78 +
26.79 + config_get(pin, Port_int, &interrupt);
26.80 +
26.81 + if (interrupt)
26.82 + {
26.83 + config_get(pin, Port_trigger, &trigger);
26.84 + config_get(pin, Port_level, &level);
26.85 +
26.86 + *func = Hw::Gpio_chip::Function_irq;
26.87 + *value = (trigger ? (level ? L4_IRQ_F_POS_EDGE : L4_IRQ_F_NEG_EDGE)
26.88 + : (level ? L4_IRQ_F_LEVEL_HIGH : L4_IRQ_F_LEVEL_LOW));
26.89 + return;
26.90 + }
26.91 +
26.92 + config_get(pin, Port_gpio, &gpio);
26.93 +
26.94 + if (gpio)
26.95 + {
26.96 + config_get(pin, Port_dir, &direction);
26.97 +
26.98 + *func = Hw::Gpio_chip::Function_gpio;
26.99 + *value = direction ? Input : Output;
26.100 + return;
26.101 + }
26.102 +
26.103 + *func = Hw::Gpio_chip::Function_alt;
26.104 +
26.105 + config_get(pin, Port_group0, &group0);
26.106 + config_get(pin, Port_group1, &group1);
26.107 +
26.108 + *value = (group1 << 1) | group0;
26.109 +}
26.110 +
26.111 // Obtain an IRQ abstraction for a pin.
26.112
26.113 Hw::Gpio_irq_pin *
26.114 @@ -417,6 +456,11 @@
26.115 static_cast<Gpio_jz4780_chip *>(gpio)->config_get(pin, reg, value);
26.116 }
26.117
26.118 +void jz4780_gpio_config_pad_get(void *gpio, unsigned pin, unsigned *func, unsigned *value)
26.119 +{
26.120 + static_cast<Gpio_jz4780_chip *>(gpio)->config_pad_get(pin, func, value);
26.121 +}
26.122 +
26.123 void jz4780_gpio_multi_setup(void *gpio, Pin_slice const *mask, unsigned mode, unsigned outvalues)
26.124 {
26.125 static_cast<Gpio_jz4780_chip *>(gpio)->multi_setup(*mask, mode, outvalues);
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
27.2 +++ b/pkg/devices/lib/gpio/src/x1600.cc Tue Oct 24 18:52:06 2023 +0200
27.3 @@ -0,0 +1,519 @@
27.4 +/*
27.5 + * GPIO driver for Ingenic X1600.
27.6 + * (See below for additional copyright and licensing notices.)
27.7 + *
27.8 + * Copyright (C) 2017, 2023 Paul Boddie <paul@boddie.org.uk>
27.9 + *
27.10 + * This program is free software; you can redistribute it and/or
27.11 + * modify it under the terms of the GNU General Public License as
27.12 + * published by the Free Software Foundation; either version 2 of
27.13 + * the License, or (at your option) any later version.
27.14 + *
27.15 + * This program is distributed in the hope that it will be useful,
27.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
27.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27.18 + * GNU General Public License for more details.
27.19 + *
27.20 + * You should have received a copy of the GNU General Public License
27.21 + * along with this program; if not, write to the Free Software
27.22 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
27.23 + * Boston, MA 02110-1301, USA
27.24 + *
27.25 + *
27.26 + * Subject to other copyrights, being derived from the bcm2835.cc and
27.27 + * omap.cc GPIO driver implementations.
27.28 + *
27.29 + * This file is part of TUD:OS and distributed under the terms of the
27.30 + * GNU General Public License 2.
27.31 + * Please see the COPYING-GPL-2 file for details.
27.32 + */
27.33 +
27.34 +#include <l4/sys/icu.h>
27.35 +#include <l4/util/util.h>
27.36 +#include <l4/devices/hw_mmio_register_block.h>
27.37 +
27.38 +#include "gpio-x1600.h"
27.39 +
27.40 +/*
27.41 +GPIO register offsets (x in A..D).
27.42 +
27.43 +Register summary:
27.44 +
27.45 +PxINT 0 (function/GPIO) 1 (interrupt)
27.46 +PxMSK 0 (function) 1 (GPIO) 0 (IRQ enable)/1 (IRQ disable)
27.47 +PxPAT1 0 (function 0/1) 1 (function 2/3) 0 (output) 1 (input) 0 (level trigger) 1 (edge trigger)
27.48 +PxPAT0 0 (function 0) 0 (function 2) 0 (output value 0) 0 (low level) 0 (falling edge)
27.49 + 1 (function 1) 1 (function 3) 1 (output value 1) 1 (high level) 1 (rising edge)
27.50 +*/
27.51 +
27.52 +enum Regs
27.53 +{
27.54 + Pin_level = 0x000, // PxPINL (read-only)
27.55 +
27.56 + Port_int = 0x010, // PxINT
27.57 + Port_int_set = 0x014, // PxINTS
27.58 + Port_int_clear = 0x018, // PxINTC
27.59 +
27.60 + Irq_mask = 0x020, // PxMSK (for PxINT == 1)
27.61 + Irq_mask_set = 0x024, // PxMSKS
27.62 + Irq_mask_clear = 0x028, // PxMSKC
27.63 + Port_gpio = 0x020, // PxMSK (for PxINT == 0)
27.64 + Port_gpio_set = 0x024, // PxMSKS
27.65 + Port_gpio_clear = 0x028, // PxMSKC
27.66 +
27.67 + Port_trigger = 0x030, // PxPAT1 (for PxINT == 1)
27.68 + Port_trigger_set = 0x034, // PxPAT1S
27.69 + Port_trigger_clear = 0x038, // PxPAT1C
27.70 + Port_dir = 0x030, // PxPAT1 (for PxINT == 0, PxMSK == 1)
27.71 + Port_dir_set = 0x034, // PxPAT1S
27.72 + Port_dir_clear = 0x038, // PxPAT1C
27.73 + Port_group1 = 0x030, // PxPAT1 (for PxINT == 0, PxMSK == 0)
27.74 + Port_group1_set = 0x034, // PxPAT1S
27.75 + Port_group1_clear = 0x038, // PxPAT1C
27.76 +
27.77 + Port_level = 0x040, // PxPAT0 (for PxINT == 1)
27.78 + Port_level_set = 0x044, // PxPAT0S
27.79 + Port_level_clear = 0x048, // PxPAT0C
27.80 + Port_data = 0x040, // PxPAT0 (for PxINT == 0, PxMSK == 1, PxPAT1 == 0)
27.81 + Port_data_set = 0x044, // PxPAT0S
27.82 + Port_data_clear = 0x048, // PxPAT0C
27.83 + Port_group0 = 0x040, // PxPAT0 (for PxINT == 0, PxMSK == 0)
27.84 + Port_group0_set = 0x044, // PxPAT0S
27.85 + Port_group0_clear = 0x048, // PxPAT0C
27.86 +
27.87 + Irq_flag = 0x050, // PxFLG (read-only)
27.88 + Irq_flag_clear = 0x058, // PxFLGC
27.89 +
27.90 + // Only the following registers differ from the JZ4780. The dual-edge
27.91 + // registers being added to the X1600, with the pull-up/down registers being
27.92 + // relocated and their sense changed from disable to enable.
27.93 +
27.94 + Pull_edge = 0x070, // PxEDG
27.95 + Pull_edge_set = 0x074, // PxEDGS
27.96 + Pull_edge_clear = 0x078, // PxEDGC
27.97 +
27.98 + Pull_enable = 0x080, // PxPE
27.99 + Pull_enable_set = 0x084, // PxPES
27.100 + Pull_enable_clear = 0x088, // PxPEC
27.101 +
27.102 + // The shadow port Z is available at offset 0x700 and supports the INTS, INTC,
27.103 + // MSKS, MSKC, PAT1S, PAT1C, PAT0S, PAT0C registers, along with the following.
27.104 +
27.105 + Shadow_transfer = 0x0f0, // PzGID2LD
27.106 +};
27.107 +
27.108 +
27.109 +
27.110 +// IRQ control for each GPIO pin.
27.111 +
27.112 +Gpio_x1600_irq_pin::Gpio_x1600_irq_pin(unsigned pin, Hw::Register_block<32> const ®s)
27.113 +: _pin(pin), _regs(regs)
27.114 +{}
27.115 +
27.116 +void
27.117 +Gpio_x1600_irq_pin::write_reg_pin(unsigned reg)
27.118 +{
27.119 + // Write the pin bit to the register, setting or clearing the pin
27.120 + // depending on the register chosen.
27.121 +
27.122 + _regs[reg] = _pin_bit(_pin);
27.123 +}
27.124 +
27.125 +void Gpio_x1600_irq_pin::do_mask()
27.126 +{
27.127 + // Set the interrupt bit in the PxIM register.
27.128 +
27.129 + write_reg_pin(Irq_mask_set);
27.130 +}
27.131 +
27.132 +void Gpio_x1600_irq_pin::do_unmask()
27.133 +{
27.134 + // Clear the interrupt bit in the PxIM register, first also clearing the
27.135 + // flag bit in the PxFLG register to allow interrupts to be delivered.
27.136 +
27.137 + write_reg_pin(Irq_flag_clear);
27.138 + write_reg_pin(Irq_mask_clear);
27.139 +}
27.140 +
27.141 +bool Gpio_x1600_irq_pin::do_set_mode(unsigned mode)
27.142 +{
27.143 + // Standard comment found for this method:
27.144 + // this operation touches multiple mmio registers and is thus
27.145 + // not atomic, that's why we first mask the IRQ and if it was
27.146 + // enabled we unmask it after we have changed the mode
27.147 +
27.148 + /* NOTE: The X1600 provides a special port Z that allows changes to be made
27.149 + and then committed atomically using PzGID2LD. This is not currently
27.150 + used. */
27.151 +
27.152 + if (enabled())
27.153 + do_mask();
27.154 +
27.155 + // Do the PxINT, PxPAT1 and PxPAT0 configuration.
27.156 +
27.157 + switch(mode)
27.158 + {
27.159 + case L4_IRQ_F_LEVEL_HIGH:
27.160 + write_reg_pin(Port_int_set);
27.161 + write_reg_pin(Port_trigger_clear);
27.162 + write_reg_pin(Port_level_set);
27.163 + break;
27.164 + case L4_IRQ_F_LEVEL_LOW:
27.165 + write_reg_pin(Port_int_set);
27.166 + write_reg_pin(Port_trigger_clear);
27.167 + write_reg_pin(Port_level_clear);
27.168 + break;
27.169 + case L4_IRQ_F_POS_EDGE:
27.170 + write_reg_pin(Port_int_set);
27.171 + write_reg_pin(Port_trigger_set);
27.172 + write_reg_pin(Port_level_set);
27.173 + break;
27.174 + case L4_IRQ_F_NEG_EDGE:
27.175 + write_reg_pin(Port_int_set);
27.176 + write_reg_pin(Port_trigger_set);
27.177 + write_reg_pin(Port_level_clear);
27.178 + break;
27.179 +
27.180 + default:
27.181 + return false;
27.182 + }
27.183 +
27.184 + if (enabled())
27.185 + do_unmask();
27.186 +
27.187 + return true;
27.188 +}
27.189 +
27.190 +int Gpio_x1600_irq_pin::clear()
27.191 +{
27.192 + // Obtain the flag status for the pin, clearing it if set.
27.193 +
27.194 + l4_uint32_t e = _regs[Irq_flag] & (1UL << _pin);
27.195 + if (e)
27.196 + _regs[Irq_flag_clear] = e;
27.197 +
27.198 + return (e >> _pin);
27.199 +}
27.200 +
27.201 +bool Gpio_x1600_irq_pin::enabled()
27.202 +{
27.203 + return true;
27.204 +}
27.205 +
27.206 +
27.207 +
27.208 +// Initialise the GPIO controller.
27.209 +
27.210 +Gpio_x1600_chip::Gpio_x1600_chip(l4_addr_t start, l4_addr_t end,
27.211 + unsigned nr_pins,
27.212 + l4_uint32_t pull_ups, l4_uint32_t pull_downs)
27.213 +: _start(start), _end(end),
27.214 + _nr_pins(nr_pins),
27.215 + _pull_ups(pull_ups), _pull_downs(pull_downs)
27.216 +{
27.217 + _regs = new Hw::Mmio_register_block<32>(_start);
27.218 +}
27.219 +
27.220 +// Return the value of a pin.
27.221 +
27.222 +int
27.223 +Gpio_x1600_chip::get(unsigned pin)
27.224 +{
27.225 + if (pin >= _nr_pins)
27.226 + throw -L4_EINVAL;
27.227 +
27.228 + l4_uint32_t val = _regs[Pin_level];
27.229 + return (val >> _pin_shift(pin)) & 1;
27.230 +}
27.231 +
27.232 +// Return multiple pin values.
27.233 +
27.234 +unsigned
27.235 +Gpio_x1600_chip::multi_get(unsigned offset)
27.236 +{
27.237 + _reg_offset_check(offset);
27.238 + return _regs[Pin_level];
27.239 +}
27.240 +
27.241 +// Set the value of a pin.
27.242 +
27.243 +void
27.244 +Gpio_x1600_chip::set(unsigned pin, int value)
27.245 +{
27.246 + if (pin >= _nr_pins)
27.247 + throw -L4_EINVAL;
27.248 +
27.249 + l4_uint32_t reg_set = value ? Port_data_set : Port_data_clear;
27.250 + _regs[reg_set] = _pin_bit(pin);
27.251 +}
27.252 +
27.253 +// Set multiple pin values.
27.254 +
27.255 +void
27.256 +Gpio_x1600_chip::multi_set(Pin_slice const &mask, unsigned data)
27.257 +{
27.258 + _reg_offset_check(mask.offset);
27.259 + if (mask.mask & data)
27.260 + _regs[Port_data_set] = (mask.mask & data);
27.261 + if (mask.mask & ~data)
27.262 + _regs[Port_data_clear] = (mask.mask & ~data);
27.263 +}
27.264 +
27.265 +// Set a pin up with the given mode and value (if appropriate).
27.266 +
27.267 +void
27.268 +Gpio_x1600_chip::setup(unsigned pin, unsigned mode, int value)
27.269 +{
27.270 + if (pin >= _nr_pins)
27.271 + throw -L4_EINVAL;
27.272 +
27.273 + config(pin, mode);
27.274 +
27.275 + if (mode == Output)
27.276 + set(pin, value);
27.277 +}
27.278 +
27.279 +// Configuration of a pin using the generic input/output/IRQ mode.
27.280 +
27.281 +void
27.282 +Gpio_x1600_chip::config(unsigned pin, unsigned mode)
27.283 +{
27.284 + switch (mode)
27.285 + {
27.286 + case Input:
27.287 + _regs[Port_int_clear] = _pin_bit(pin);
27.288 + _regs[Port_gpio_set] = _pin_bit(pin);
27.289 + _regs[Port_dir_set] = _pin_bit(pin);
27.290 + break;
27.291 + case Output:
27.292 + _regs[Port_int_clear] = _pin_bit(pin);
27.293 + _regs[Port_gpio_set] = _pin_bit(pin);
27.294 + _regs[Port_dir_clear] = _pin_bit(pin);
27.295 + break;
27.296 + case Irq:
27.297 + _regs[Port_int_set] = _pin_bit(pin);
27.298 + // Other details depend on the actual trigger mode.
27.299 + break;
27.300 + default:
27.301 + break;
27.302 + }
27.303 +}
27.304 +
27.305 +// Pull-up/down configuration for a pin.
27.306 +
27.307 +void
27.308 +Gpio_x1600_chip::config_pull(unsigned pin, unsigned mode)
27.309 +{
27.310 + if (pin >= _nr_pins)
27.311 + throw -L4_EINVAL;
27.312 +
27.313 + switch (mode)
27.314 + {
27.315 + case Pull_none:
27.316 + _regs[Pull_enable_clear] = _pin_bit(pin);
27.317 + break;
27.318 + case Pull_down:
27.319 + if (_pin_bit(pin) & _pull_downs)
27.320 + _regs[Pull_enable_set] = _pin_bit(pin);
27.321 + break;
27.322 + case Pull_up:
27.323 + if (_pin_bit(pin) & _pull_ups)
27.324 + _regs[Pull_enable_set] = _pin_bit(pin);
27.325 + break;
27.326 + default:
27.327 + // Invalid pull-up/down mode for pin.
27.328 + throw -L4_EINVAL;
27.329 + }
27.330 +}
27.331 +
27.332 +// Pin function configuration.
27.333 +
27.334 +void
27.335 +Gpio_x1600_chip::config_pad(unsigned pin, unsigned func, unsigned value)
27.336 +{
27.337 + if (pin >= _nr_pins)
27.338 + throw -L4_EINVAL;
27.339 +
27.340 + if (value > 3)
27.341 + throw -L4_EINVAL;
27.342 +
27.343 + switch (func)
27.344 + {
27.345 + // Support two different outputs.
27.346 +
27.347 + case Hw::Gpio_chip::Function_gpio:
27.348 + _regs[Port_int_clear] = _pin_bit(pin);
27.349 + _regs[Port_gpio_set] = _pin_bit(pin);
27.350 + _regs[value & 1 ? Port_data_set : Port_data_clear] = _pin_bit(pin);
27.351 + break;
27.352 +
27.353 + // Support four different device functions.
27.354 +
27.355 + case Hw::Gpio_chip::Function_alt:
27.356 + _regs[Port_int_clear] = _pin_bit(pin);
27.357 + _regs[Port_gpio_clear] = _pin_bit(pin);
27.358 + _regs[value & 2 ? Port_group1_set : Port_group1_clear] = _pin_bit(pin);
27.359 + _regs[value & 1 ? Port_group0_set : Port_group0_clear] = _pin_bit(pin);
27.360 + break;
27.361 + default:
27.362 + throw -L4_EINVAL;
27.363 + }
27.364 +}
27.365 +
27.366 +// Obtain a pin's configuration from a register in the supplied value.
27.367 +
27.368 +void
27.369 +Gpio_x1600_chip::config_get(unsigned pin, unsigned reg, unsigned *value)
27.370 +{
27.371 + if (pin >= _nr_pins)
27.372 + throw -L4_EINVAL;
27.373 +
27.374 + *value = (_regs[reg] >> _pin_shift(pin)) & 1;
27.375 +}
27.376 +
27.377 +// Return function and function-specific configuration for a pin.
27.378 +
27.379 +void
27.380 +Gpio_x1600_chip::config_pad_get(unsigned pin, unsigned *func, unsigned *value)
27.381 +{
27.382 + unsigned direction, gpio, group0, group1, interrupt, level, trigger;
27.383 +
27.384 + config_get(pin, Port_int, &interrupt);
27.385 +
27.386 + if (interrupt)
27.387 + {
27.388 + config_get(pin, Port_trigger, &trigger);
27.389 + config_get(pin, Port_level, &level);
27.390 +
27.391 + *func = Hw::Gpio_chip::Function_irq;
27.392 + *value = (trigger ? (level ? L4_IRQ_F_POS_EDGE : L4_IRQ_F_NEG_EDGE)
27.393 + : (level ? L4_IRQ_F_LEVEL_HIGH : L4_IRQ_F_LEVEL_LOW));
27.394 + return;
27.395 + }
27.396 +
27.397 + config_get(pin, Port_gpio, &gpio);
27.398 +
27.399 + if (gpio)
27.400 + {
27.401 + config_get(pin, Port_dir, &direction);
27.402 +
27.403 + *func = Hw::Gpio_chip::Function_gpio;
27.404 + *value = direction ? Input : Output;
27.405 + return;
27.406 + }
27.407 +
27.408 + *func = Hw::Gpio_chip::Function_alt;
27.409 +
27.410 + config_get(pin, Port_group0, &group0);
27.411 + config_get(pin, Port_group1, &group1);
27.412 +
27.413 + *value = (group1 << 1) | group0;
27.414 +}
27.415 +
27.416 +// Obtain an IRQ abstraction for a pin.
27.417 +
27.418 +Hw::Gpio_irq_pin *
27.419 +Gpio_x1600_chip::get_irq(unsigned pin)
27.420 +{
27.421 + if (pin >= _nr_pins)
27.422 + throw -L4_EINVAL;
27.423 +
27.424 + return new Gpio_x1600_irq_pin(pin, _regs);
27.425 +}
27.426 +
27.427 +// Pin function configuration for multiple pins.
27.428 +
27.429 +void
27.430 +Gpio_x1600_chip::multi_config_pad(Pin_slice const &mask, unsigned func, unsigned val)
27.431 +{
27.432 + unsigned m = mask.mask;
27.433 + for (unsigned pin = mask.offset; pin < _nr_pins; ++pin, m >>= 1)
27.434 + if (m & 1)
27.435 + config_pad(pin, func, val);
27.436 +}
27.437 +
27.438 +// Set up multiple pins with the given mode.
27.439 +
27.440 +void
27.441 +Gpio_x1600_chip::multi_setup(Pin_slice const &mask, unsigned mode, unsigned outvalues)
27.442 +{
27.443 + unsigned m = mask.mask;
27.444 + for (unsigned pin = mask.offset; pin < _nr_pins; ++pin, m >>= 1, outvalues >>= 1)
27.445 + if (m & 1)
27.446 + setup(pin, mode, outvalues & 1);
27.447 +}
27.448 +
27.449 +
27.450 +
27.451 +// C language interface functions.
27.452 +
27.453 +void *x1600_gpio_init(l4_addr_t start, l4_addr_t end, unsigned pins,
27.454 + l4_uint32_t pull_ups, l4_uint32_t pull_downs)
27.455 +{
27.456 + return (void *) new Gpio_x1600_chip(start, end, pins, pull_ups, pull_downs);
27.457 +}
27.458 +
27.459 +void x1600_gpio_setup(void *gpio, unsigned pin, unsigned mode, int value)
27.460 +{
27.461 + static_cast<Gpio_x1600_chip *>(gpio)->setup(pin, mode, value);
27.462 +}
27.463 +
27.464 +void x1600_gpio_config_pull(void *gpio, unsigned pin, unsigned mode)
27.465 +{
27.466 + static_cast<Gpio_x1600_chip *>(gpio)->config_pull(pin, mode);
27.467 +}
27.468 +
27.469 +void x1600_gpio_config_pad(void *gpio, unsigned pin, unsigned func, unsigned value)
27.470 +{
27.471 + static_cast<Gpio_x1600_chip *>(gpio)->config_pad(pin, func, value);
27.472 +}
27.473 +
27.474 +void x1600_gpio_config_get(void *gpio, unsigned pin, unsigned reg, unsigned *value)
27.475 +{
27.476 + static_cast<Gpio_x1600_chip *>(gpio)->config_get(pin, reg, value);
27.477 +}
27.478 +
27.479 +void x1600_gpio_config_pad_get(void *gpio, unsigned pin, unsigned *func, unsigned *value)
27.480 +{
27.481 + static_cast<Gpio_x1600_chip *>(gpio)->config_pad_get(pin, func, value);
27.482 +}
27.483 +
27.484 +void x1600_gpio_multi_setup(void *gpio, Pin_slice const *mask, unsigned mode, unsigned outvalues)
27.485 +{
27.486 + static_cast<Gpio_x1600_chip *>(gpio)->multi_setup(*mask, mode, outvalues);
27.487 +}
27.488 +
27.489 +void x1600_gpio_multi_config_pad(void *gpio, Pin_slice const *mask, unsigned func, unsigned value)
27.490 +{
27.491 + static_cast<Gpio_x1600_chip *>(gpio)->multi_config_pad(*mask, func, value);
27.492 +}
27.493 +
27.494 +void x1600_gpio_multi_set(void *gpio, Pin_slice const *mask, unsigned data)
27.495 +{
27.496 + static_cast<Gpio_x1600_chip *>(gpio)->multi_set(*mask, data);
27.497 +}
27.498 +
27.499 +unsigned x1600_gpio_multi_get(void *gpio, unsigned offset)
27.500 +{
27.501 + return static_cast<Gpio_x1600_chip *>(gpio)->multi_get(offset);
27.502 +}
27.503 +
27.504 +int x1600_gpio_get(void *gpio, unsigned pin)
27.505 +{
27.506 + return static_cast<Gpio_x1600_chip *>(gpio)->get(pin);
27.507 +}
27.508 +
27.509 +void x1600_gpio_set(void *gpio, unsigned pin, int value)
27.510 +{
27.511 + static_cast<Gpio_x1600_chip *>(gpio)->set(pin, value);
27.512 +}
27.513 +
27.514 +void *x1600_gpio_get_irq(void *gpio, unsigned pin)
27.515 +{
27.516 + return (void *) static_cast<Gpio_x1600_chip *>(gpio)->get_irq(pin);
27.517 +}
27.518 +
27.519 +bool x1600_gpio_irq_set_mode(void *gpio_irq, unsigned mode)
27.520 +{
27.521 + return static_cast<Hw::Gpio_irq_pin *>(gpio_irq)->do_set_mode(mode);
27.522 +}
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
28.2 +++ b/pkg/devices/lib/i2c/include/i2c-gpio.h Tue Oct 24 18:52:06 2023 +0200
28.3 @@ -0,0 +1,76 @@
28.4 +/*
28.5 + * Manual GPIO-based I2C communication.
28.6 + *
28.7 + * Copyright (C) 2013, 2023 Paul Boddie <paul@boddie.org.uk>
28.8 + *
28.9 + * This program is free software; you can redistribute it and/or
28.10 + * modify it under the terms of the GNU General Public License as
28.11 + * published by the Free Software Foundation; either version 2 of
28.12 + * the License, or (at your option) any later version.
28.13 + *
28.14 + * This program is distributed in the hope that it will be useful,
28.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
28.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28.17 + * GNU General Public License for more details.
28.18 + *
28.19 + * You should have received a copy of the GNU General Public License
28.20 + * along with this program; if not, write to the Free Software
28.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
28.22 + * Boston, MA 02110-1301, USA
28.23 + */
28.24 +
28.25 +#pragma once
28.26 +
28.27 +#include <l4/devices/gpio.h>
28.28 +#include <stdint.h>
28.29 +
28.30 +/* I2C modifiers. */
28.31 +
28.32 +#define I2C_READ 1
28.33 +#define I2C_WRITE 0
28.34 +
28.35 +#ifdef __cplusplus
28.36 +
28.37 +class I2c_gpio
28.38 +{
28.39 + Hw::Gpio_chip *_scl_chip;
28.40 + int I2C_SCL;
28.41 + Hw::Gpio_chip *_sda_chip;
28.42 + int I2C_SDA;
28.43 +
28.44 + void CLR(int pin);
28.45 + void SET(int pin);
28.46 + void IN(int pin);
28.47 + int PIN(int pin);
28.48 + void wait();
28.49 +
28.50 +public:
28.51 + explicit I2c_gpio(Hw::Gpio_chip *scl_chip, int scl, Hw::Gpio_chip *sda_chip, int sda);
28.52 +
28.53 + void start();
28.54 + void stop();
28.55 + void ack(bool ack);
28.56 + uint8_t recv();
28.57 + void recvmany(uint8_t *data, uint8_t len);
28.58 + bool send(uint8_t data);
28.59 + bool sendmany(uint8_t *data, uint8_t len);
28.60 +};
28.61 +
28.62 +#endif /* __cplusplus */
28.63 +
28.64 +
28.65 +
28.66 +/* C language interface. */
28.67 +
28.68 +EXTERN_C_BEGIN
28.69 +
28.70 +void *i2c_gpio_get_channel(void *scl_chip, int scl, void *sda_chip, int sda);
28.71 +void i2c_gpio_start(void *channel);
28.72 +void i2c_gpio_stop(void *channel);
28.73 +void i2c_gpio_ack(void *channel, bool ack);
28.74 +uint8_t i2c_gpio_recv(void *channel);
28.75 +void i2c_gpio_recvmany(void *channel, uint8_t *data, uint8_t len);
28.76 +bool i2c_gpio_send(void *channel, uint8_t data);
28.77 +bool i2c_gpio_sendmany(void *channel, uint8_t *data, uint8_t len);
28.78 +
28.79 +EXTERN_C_END
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
29.2 +++ b/pkg/devices/lib/i2c/include/i2c-x1600.h Tue Oct 24 18:52:06 2023 +0200
29.3 @@ -0,0 +1,157 @@
29.4 +/*
29.5 + * I2C support for the X1600.
29.6 + *
29.7 + * Copyright (C) 2017, 2018, 2019, 2023 Paul Boddie <paul@boddie.org.uk>
29.8 + *
29.9 + * This program is free software; you can redistribute it and/or
29.10 + * modify it under the terms of the GNU General Public License as
29.11 + * published by the Free Software Foundation; either version 2 of
29.12 + * the License, or (at your option) any later version.
29.13 + *
29.14 + * This program is distributed in the hope that it will be useful,
29.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
29.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29.17 + * GNU General Public License for more details.
29.18 + *
29.19 + * You should have received a copy of the GNU General Public License
29.20 + * along with this program; if not, write to the Free Software
29.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
29.22 + * Boston, MA 02110-1301, USA
29.23 + */
29.24 +
29.25 +#pragma once
29.26 +
29.27 +#include <l4/sys/types.h>
29.28 +#include <stdint.h>
29.29 +
29.30 +
29.31 +
29.32 +#ifdef __cplusplus
29.33 +
29.34 +#include <l4/devices/cpm-x1600.h>
29.35 +#include <l4/devices/hw_mmio_register_block.h>
29.36 +
29.37 +// I2C channel.
29.38 +
29.39 +class I2c_x1600_channel
29.40 +{
29.41 +private:
29.42 + Hw::Register_block<32> _regs;
29.43 + Cpm_x1600_chip *_cpm;
29.44 + uint32_t _frequency;
29.45 +
29.46 + // Buffer management.
29.47 +
29.48 + unsigned int _pos, _reqpos, _total;
29.49 + uint8_t *_buf;
29.50 +
29.51 + // Status conditions.
29.52 +
29.53 + int _fail;
29.54 + int _stop;
29.55 +
29.56 +public:
29.57 + I2c_x1600_channel(l4_addr_t start, enum Clock_identifiers clock,
29.58 + Cpm_x1600_chip *cpm, uint32_t frequency);
29.59 +
29.60 + uint32_t get_frequency();
29.61 + void set_target(uint8_t addr);
29.62 +
29.63 + // Reading initiation and execution.
29.64 +
29.65 + void start_read(uint8_t buf[], unsigned int total, int stop = 0);
29.66 + void read();
29.67 +
29.68 + // Writing initiation and execution.
29.69 +
29.70 + void start_write(uint8_t buf[], unsigned int total, int stop = 0);
29.71 + void write();
29.72 +
29.73 + // Transaction control.
29.74 +
29.75 + void stop();
29.76 + void disable();
29.77 +
29.78 + // Specific status conditions.
29.79 +
29.80 + unsigned int have_read();
29.81 + unsigned int have_written();
29.82 + int read_done();
29.83 + int write_done();
29.84 +
29.85 + int failed();
29.86 + int read_failed();
29.87 + int write_failed();
29.88 +
29.89 +private:
29.90 + void enable();
29.91 +
29.92 + int active();
29.93 + int have_input();
29.94 + int have_output();
29.95 + int can_send();
29.96 +
29.97 + void reset_flags();
29.98 + void init_parameters();
29.99 + void set_frequency();
29.100 +
29.101 + void set_read_threshold();
29.102 + void queue_reads();
29.103 + void queue_writes();
29.104 + void store_reads();
29.105 +};
29.106 +
29.107 +// I2C device control.
29.108 +
29.109 +class I2c_x1600_chip
29.110 +{
29.111 +private:
29.112 + l4_addr_t _start, _end;
29.113 + Cpm_x1600_chip *_cpm;
29.114 + uint32_t _frequency;
29.115 +
29.116 +public:
29.117 + I2c_x1600_chip(l4_addr_t start, l4_addr_t end, Cpm_x1600_chip *cpm,
29.118 + uint32_t frequency);
29.119 +
29.120 + I2c_x1600_channel *get_channel(uint8_t channel);
29.121 +};
29.122 +
29.123 +#endif /* __cplusplus */
29.124 +
29.125 +
29.126 +
29.127 +/* C language interface. */
29.128 +
29.129 +EXTERN_C_BEGIN
29.130 +
29.131 +void *x1600_i2c_init(l4_addr_t start, l4_addr_t end, void *cpm,
29.132 + uint32_t frequency);
29.133 +
29.134 +void *x1600_i2c_get_channel(void *i2c, uint8_t channel);
29.135 +
29.136 +uint32_t x1600_i2c_get_frequency(void *i2c_channel);
29.137 +
29.138 +void x1600_i2c_set_target(void *i2c_channel, uint8_t addr);
29.139 +
29.140 +void x1600_i2c_start_read(void *i2c_channel, uint8_t buf[], unsigned int total,
29.141 + int stop);
29.142 +
29.143 +void x1600_i2c_read(void *i2c_channel);
29.144 +
29.145 +void x1600_i2c_start_write(void *i2c_channel, uint8_t buf[], unsigned int total,
29.146 + int stop);
29.147 +
29.148 +void x1600_i2c_write(void *i2c_channel);
29.149 +
29.150 +int x1600_i2c_read_done(void *i2c_channel);
29.151 +
29.152 +int x1600_i2c_write_done(void *i2c_channel);
29.153 +
29.154 +unsigned int x1600_i2c_have_read(void *i2c_channel);
29.155 +
29.156 +unsigned int x1600_i2c_have_written(void *i2c_channel);
29.157 +
29.158 +int x1600_i2c_failed(void *i2c_channel);
29.159 +
29.160 +EXTERN_C_END
30.1 --- a/pkg/devices/lib/i2c/src/Makefile Fri Sep 22 21:56:34 2023 +0200
30.2 +++ b/pkg/devices/lib/i2c/src/Makefile Tue Oct 24 18:52:06 2023 +0200
30.3 @@ -4,10 +4,10 @@
30.4 TARGET = libi2c.o.a libi2c.o.so
30.5 PC_FILENAME := libdrivers-i2c
30.6
30.7 -SRC_CC := jz4730.cc jz4780.cc
30.8 +SRC_CC := jz4730.cc jz4780.cc x1600.cc gpio.cc
30.9
30.10 PRIVATE_INCDIR += $(PKGDIR)/lib/i2c/include
30.11
30.12 -REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-common
30.13 +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-common libdrivers-cpm libdrivers-gpio
30.14
30.15 include $(L4DIR)/mk/lib.mk
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
31.2 +++ b/pkg/devices/lib/i2c/src/gpio.cc Tue Oct 24 18:52:06 2023 +0200
31.3 @@ -0,0 +1,243 @@
31.4 +/*
31.5 + * Manual GPIO-based I2C communication.
31.6 + *
31.7 + * Copyright (C) 2013, 2023 Paul Boddie <paul@boddie.org.uk>
31.8 + *
31.9 + * This program is free software; you can redistribute it and/or
31.10 + * modify it under the terms of the GNU General Public License as
31.11 + * published by the Free Software Foundation; either version 2 of
31.12 + * the License, or (at your option) any later version.
31.13 + *
31.14 + * This program is distributed in the hope that it will be useful,
31.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
31.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31.17 + * GNU General Public License for more details.
31.18 + *
31.19 + * You should have received a copy of the GNU General Public License
31.20 + * along with this program; if not, write to the Free Software
31.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
31.22 + * Boston, MA 02110-1301, USA
31.23 + */
31.24 +
31.25 +#include <unistd.h>
31.26 +#include "i2c-gpio.h"
31.27 +
31.28 +/* Declare the pins for initial I2C communications. */
31.29 +
31.30 +I2c_gpio::I2c_gpio(Hw::Gpio_chip *scl_chip, int scl, Hw::Gpio_chip *sda_chip, int sda)
31.31 +{
31.32 + _scl_chip = scl_chip;
31.33 + _sda_chip = sda_chip;
31.34 + I2C_SCL = scl;
31.35 + I2C_SDA = sda;
31.36 +}
31.37 +
31.38 +void I2c_gpio::CLR(int pin)
31.39 +{
31.40 + (pin == I2C_SCL ? _scl_chip : _sda_chip)->setup(pin, Hw::Gpio_chip::Output, 0);
31.41 +}
31.42 +
31.43 +void I2c_gpio::SET(int pin)
31.44 +{
31.45 + (pin == I2C_SCL ? _scl_chip : _sda_chip)->setup(pin, Hw::Gpio_chip::Output, 1);
31.46 +}
31.47 +
31.48 +void I2c_gpio::IN(int pin)
31.49 +{
31.50 + (pin == I2C_SCL ? _scl_chip : _sda_chip)->setup(pin, Hw::Gpio_chip::Input, 0);
31.51 +}
31.52 +
31.53 +int I2c_gpio::PIN(int pin)
31.54 +{
31.55 + return (pin == I2C_SCL ? _scl_chip : _sda_chip)->get(pin);
31.56 +}
31.57 +
31.58 +void I2c_gpio::wait()
31.59 +{
31.60 + usleep(4);
31.61 +}
31.62 +
31.63 +/* Initiate an I2C transaction. */
31.64 +
31.65 +void I2c_gpio::start()
31.66 +{
31.67 + /* Set up the data signal. */
31.68 +
31.69 + CLR(I2C_SCL);
31.70 + wait();
31.71 + SET(I2C_SDA);
31.72 +
31.73 + /* During a clock pulse, produce the start condition. */
31.74 +
31.75 + SET(I2C_SCL);
31.76 + wait();
31.77 + CLR(I2C_SDA);
31.78 +}
31.79 +
31.80 +/* Terminate an I2C transaction. */
31.81 +
31.82 +void I2c_gpio::stop()
31.83 +{
31.84 + /* Set up the data signal. */
31.85 +
31.86 + CLR(I2C_SCL);
31.87 + wait();
31.88 + CLR(I2C_SDA);
31.89 +
31.90 + /* During a clock pulse, produce the stop condition. */
31.91 +
31.92 + SET(I2C_SCL);
31.93 + wait();
31.94 + SET(I2C_SDA);
31.95 +}
31.96 +
31.97 +/* Send an I2C acknowledgement to a transmitting device. */
31.98 +
31.99 +void I2c_gpio::ack(bool ack)
31.100 +{
31.101 + if (ack)
31.102 + CLR(I2C_SDA);
31.103 + else
31.104 + SET(I2C_SDA);
31.105 +
31.106 + SET(I2C_SCL);
31.107 + wait();
31.108 + CLR(I2C_SCL);
31.109 +
31.110 + IN(I2C_SDA);
31.111 +}
31.112 +
31.113 +/* Receive a single byte from an I2C device as part of a transaction. */
31.114 +
31.115 +uint8_t I2c_gpio::recv()
31.116 +{
31.117 + uint8_t mask, result = 0;
31.118 +
31.119 + IN(I2C_SDA);
31.120 + CLR(I2C_SCL);
31.121 +
31.122 + for (mask = 0x80; mask; mask >>= 1)
31.123 + {
31.124 + SET(I2C_SCL);
31.125 + wait();
31.126 +
31.127 + if (PIN(I2C_SDA))
31.128 + result |= mask;
31.129 +
31.130 + CLR(I2C_SCL);
31.131 + wait();
31.132 + }
31.133 +
31.134 + return result;
31.135 +}
31.136 +
31.137 +/* Receive into a buffer a transmission of the given length in bytes. */
31.138 +
31.139 +void I2c_gpio::recvmany(uint8_t *data, uint8_t len)
31.140 +{
31.141 + uint8_t *end = data + len;
31.142 +
31.143 + for (; data != end; data++, len--)
31.144 + {
31.145 + *data = recv();
31.146 + ack(len > 1);
31.147 + }
31.148 +}
31.149 +
31.150 +/* Send a single byte of data to an I2C device as part of a transaction,
31.151 + returning whether the transmission succeeded. */
31.152 +
31.153 +bool I2c_gpio::send(uint8_t data)
31.154 +{
31.155 + uint8_t mask;
31.156 + bool status;
31.157 +
31.158 + CLR(I2C_SCL);
31.159 +
31.160 + for (mask = 0x80; mask; mask >>= 1)
31.161 + {
31.162 + wait();
31.163 +
31.164 + if (data & mask)
31.165 + SET(I2C_SDA);
31.166 + else
31.167 + CLR(I2C_SDA);
31.168 +
31.169 + SET(I2C_SCL);
31.170 + wait();
31.171 + CLR(I2C_SCL);
31.172 + }
31.173 +
31.174 + /* Wait for acknowledgement, failing if none is given. */
31.175 +
31.176 + IN(I2C_SDA);
31.177 + SET(I2C_SCL);
31.178 + wait();
31.179 +
31.180 + status = PIN(I2C_SDA);
31.181 + CLR(I2C_SCL);
31.182 + return !status;
31.183 +}
31.184 +
31.185 +/* Send from the buffer provided a transmission with the given length to an I2C
31.186 + device. */
31.187 +
31.188 +bool I2c_gpio::sendmany(uint8_t *data, uint8_t len)
31.189 +{
31.190 + uint8_t *end = data + len;
31.191 +
31.192 + for (; data != end; data++)
31.193 + {
31.194 + if (!send(*data))
31.195 + return false;
31.196 +
31.197 + /* NOTE: Should test for the slave holding the clock signal low. */
31.198 + }
31.199 +
31.200 + return true;
31.201 +}
31.202 +
31.203 +
31.204 +
31.205 +// C language interface functions.
31.206 +
31.207 +void *i2c_gpio_get_channel(void *scl_chip, int scl, void *sda_chip, int sda)
31.208 +{
31.209 + return (void *) new I2c_gpio(reinterpret_cast<Hw::Gpio_chip *>(scl_chip), scl,
31.210 + reinterpret_cast<Hw::Gpio_chip *>(sda_chip), sda);
31.211 +}
31.212 +
31.213 +void i2c_gpio_start(void *channel)
31.214 +{
31.215 + static_cast<I2c_gpio *>(channel)->start();
31.216 +}
31.217 +
31.218 +void i2c_gpio_stop(void *channel)
31.219 +{
31.220 + static_cast<I2c_gpio *>(channel)->stop();
31.221 +}
31.222 +
31.223 +void i2c_gpio_ack(void *channel, bool ack)
31.224 +{
31.225 + static_cast<I2c_gpio *>(channel)->ack(ack);
31.226 +}
31.227 +
31.228 +uint8_t i2c_gpio_recv(void *channel)
31.229 +{
31.230 + return static_cast<I2c_gpio *>(channel)->recv();
31.231 +}
31.232 +
31.233 +void i2c_gpio_recvmany(void *channel, uint8_t *data, uint8_t len)
31.234 +{
31.235 + static_cast<I2c_gpio *>(channel)->recvmany(data, len);
31.236 +}
31.237 +
31.238 +bool i2c_gpio_send(void *channel, uint8_t data)
31.239 +{
31.240 + return static_cast<I2c_gpio *>(channel)->send(data);
31.241 +}
31.242 +
31.243 +bool i2c_gpio_sendmany(void *channel, uint8_t *data, uint8_t len)
31.244 +{
31.245 + return static_cast<I2c_gpio *>(channel)->sendmany(data, len);
31.246 +}
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
32.2 +++ b/pkg/devices/lib/i2c/src/x1600.cc Tue Oct 24 18:52:06 2023 +0200
32.3 @@ -0,0 +1,769 @@
32.4 +/*
32.5 + * I2C support for the X1600.
32.6 + *
32.7 + * Copyright (C) 2017, 2018, 2021, 2023 Paul Boddie <paul@boddie.org.uk>
32.8 + *
32.9 + * This program is free software; you can redistribute it and/or
32.10 + * modify it under the terms of the GNU General Public License as
32.11 + * published by the Free Software Foundation; either version 2 of
32.12 + * the License, or (at your option) any later version.
32.13 + *
32.14 + * This program is distributed in the hope that it will be useful,
32.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
32.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32.17 + * GNU General Public License for more details.
32.18 + *
32.19 + * You should have received a copy of the GNU General Public License
32.20 + * along with this program; if not, write to the Free Software
32.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
32.22 + * Boston, MA 02110-1301, USA
32.23 + */
32.24 +
32.25 +#include <l4/devices/i2c-x1600.h>
32.26 +#include <l4/devices/hw_mmio_register_block.h>
32.27 +
32.28 +#include <l4/sys/icu.h>
32.29 +#include <l4/util/util.h>
32.30 +#include <sys/time.h>
32.31 +
32.32 +/* NOTE: This peripheral is very similar to the JZ4780 with the registers
32.33 + renamed to I2C from SMB, with a few high speed registers added, and
32.34 + with I2C_SDAHD appearing at a different location. */
32.35 +
32.36 +enum Regs
32.37 +{
32.38 + I2c_control = 0x000, // I2C_CON
32.39 + I2c_target_address = 0x004, // I2C_TAR
32.40 + I2c_slave_address = 0x008, // I2C_SAR
32.41 + I2c_master_code = 0x00c, // I2C_HS_MADDR
32.42 + I2c_data_command = 0x010, // I2C_DC
32.43 + Std_high_count = 0x014, // I2C_SHCNT
32.44 + Std_low_count = 0x018, // I2C_SLCNT
32.45 + Fast_high_count = 0x01c, // I2C_FHCNT
32.46 + Fast_low_count = 0x020, // I2C_FLCNT
32.47 + High_high_count = 0x024, // I2C_HHCNT
32.48 + High_low_count = 0x028, // I2C_HLCNT
32.49 + Int_status = 0x02c, // I2C_INTST (read-only)
32.50 + Int_mask = 0x030, // I2C_INTM
32.51 + Int_raw_status = 0x034, // I2C_RINTST (read-only)
32.52 + Rx_fifo_thold = 0x038, // I2C_RXTL
32.53 + Tx_fifo_thold = 0x03c, // I2C_TXTL
32.54 + Int_combined_clear = 0x040, // I2C_CINT (read-only)
32.55 + Int_rx_uf_clear = 0x044, // I2C_CRXUF (read-only)
32.56 + Int_rx_of_clear = 0x048, // I2C_CRXOF (read-only)
32.57 + Int_tx_of_clear = 0x04c, // I2C_CTXOF (read-only)
32.58 + Int_rd_req_clear = 0x050, // I2C_CRXREQ (read-only)
32.59 + Int_tx_abort_clear = 0x054, // I2C_CTXABT (read-only)
32.60 + Int_rx_done_clear = 0x058, // I2C_CRXDN (read-only)
32.61 + Int_activity_clear = 0x05c, // I2C_CACT (read-only)
32.62 + Int_stop_clear = 0x060, // I2C_CSTP (read-only)
32.63 + Int_start_clear = 0x064, // I2C_CSTT (read-only)
32.64 + Int_call_clear = 0x068, // I2C_CGC (read-only)
32.65 + I2c_enable = 0x06c, // I2C_ENB
32.66 + I2c_status = 0x070, // I2C_ST (read-only)
32.67 + Tx_fifo_count = 0x074, // I2C_TXFLR (read-only)
32.68 + Rx_fifo_count = 0x078, // I2C_RXFLR (read-only)
32.69 + I2c_sda_hold_time = 0x07c, // I2C_SDAHD
32.70 + Trans_abort_status = 0x080, // I2C_ABTSRC (read-only)
32.71 + Slv_data_nack = 0x084, // I2CSDNACK
32.72 + I2c_dma_ctrl = 0x088, // I2C_DMACR
32.73 + I2c_trans_data_lvl = 0x08c, // I2C_DMATDLR
32.74 + I2c_recv_data_lvl = 0x090, // I2C_DMARDLR
32.75 + I2c_sda_setup_time = 0x094, // I2C_SDASU
32.76 + I2c_ack_call = 0x098, // I2C_ACKGC
32.77 + I2c_enable_status = 0x09c, // I2C_ENBST (read-only)
32.78 + I2c_spike_suppress = 0x0a0, // I2C_FSPKLEN
32.79 +
32.80 + I2c_block_offset = 0x1000
32.81 +};
32.82 +
32.83 +enum I2c_control_bits : unsigned
32.84 +{
32.85 + I2c_disable_slave = 0x40, // SLVDIS (slave disabled)
32.86 + I2c_enable_restart = 0x20, // RESTART
32.87 + I2c_master_10bit = 0x10, // MATP (read-only)
32.88 + I2c_slave_10bit = 0x08, // SATP
32.89 + I2c_speed_mode_mask = 0x06, // SPEED
32.90 + I2c_enable_master = 0x01, // MD (master enabled)
32.91 + I2c_speed_bit = 1, // SPD
32.92 +};
32.93 +
32.94 +enum I2c_speed_mode_values : unsigned
32.95 +{
32.96 + I2c_speed_standard = 1,
32.97 + I2c_speed_fast = 2,
32.98 + I2c_speed_high = 3,
32.99 +};
32.100 +
32.101 +enum I2c_enable_bits : unsigned
32.102 +{
32.103 + I2c_enable_enabled = 0x01, // I2CEN
32.104 +};
32.105 +
32.106 +enum I2c_status_bits : unsigned
32.107 +{
32.108 + I2c_status_master_act = 0x20, // MSTACT (master active)
32.109 + I2c_status_rx_nempty = 0x08, // RFNE (read queue not empty)
32.110 + I2c_status_tx_empty = 0x04, // TFE (write queue empty)
32.111 + I2c_status_tx_nfull = 0x02, // TFNF (write queue not full)
32.112 + I2c_status_active = 0x01, // ACT (device active as master or slave)
32.113 +};
32.114 +
32.115 +enum I2c_target_bits : unsigned
32.116 +{
32.117 + I2c_target_master_10bit = 0x1000,
32.118 + I2c_target_special = 0x0800, // SPECIAL: perform general call or start byte
32.119 + I2c_target_start_byte = 0x0400, // Special: start byte (1) or general call (0)
32.120 + I2c_target_10bits = 0x3ff, // Mask for 10-bit address
32.121 + I2c_target_7bits = 0x7f, // Mask for 7-bit address
32.122 +};
32.123 +
32.124 +enum I2c_hold_control_bits : unsigned
32.125 +{
32.126 + /* The hold enable flag has been removed since the JZ4780 and the hold time
32.127 + field widened. */
32.128 +
32.129 + I2c_hold_mask = 0xffff,
32.130 +};
32.131 +
32.132 +enum I2c_setup_control_bits : unsigned
32.133 +{
32.134 + I2c_setup_mask = 0x0ff, // SDASU
32.135 +};
32.136 +
32.137 +enum I2c_command_bits : unsigned
32.138 +{
32.139 + I2c_command_restart = 0x400, // RESTART: explicit restart before next byte
32.140 + I2c_command_stop = 0x200, // STOP: explicit stop after next byte
32.141 + I2c_command_no_stop = 0x000,
32.142 + I2c_command_read = 0x100, // CMD
32.143 + I2c_command_write = 0x000, // CMD
32.144 +};
32.145 +
32.146 +enum I2c_fifo_bits : unsigned
32.147 +{
32.148 + I2c_fifo_limit = 64, // RXTL, TXTL (256 noted in field description)
32.149 +};
32.150 +
32.151 +enum Int_bits : unsigned
32.152 +{
32.153 + Int_call = 0x800, // IGC (general call received)
32.154 + Int_start = 0x400, // ISTT (start/restart condition occurred)
32.155 + Int_stop = 0x200, // ISTP (stop condition occurred)
32.156 + Int_activity = 0x100, // IACT (bus activity interrupt)
32.157 + Int_rx_done = 0x080, // RXDN (read from master device done)
32.158 + Int_tx_abort = 0x040, // TXABT (transmit abort)
32.159 + Int_rd_req = 0x020, // RDREQ (read request from master device)
32.160 + Int_tx_empty = 0x010, // TXEMP (threshold reached or passed)
32.161 + Int_tx_of = 0x008, // TXOF (overflow when writing to queue)
32.162 + Int_rx_full = 0x004, // RXFL (threshold reached or exceeded)
32.163 + Int_rx_of = 0x002, // RXOF (overflow from device)
32.164 + Int_rx_uf = 0x001, // RXUF (underflow when reading from queue)
32.165 +};
32.166 +
32.167 +
32.168 +
32.169 +// Initialise a channel.
32.170 +
32.171 +I2c_x1600_channel::I2c_x1600_channel(l4_addr_t start,
32.172 + enum Clock_identifiers clock,
32.173 + Cpm_x1600_chip *cpm,
32.174 + uint32_t frequency)
32.175 +: _cpm(cpm), _frequency(frequency)
32.176 +{
32.177 + _regs = new Hw::Mmio_register_block<32>(start);
32.178 + _cpm->start_clock(clock);
32.179 +}
32.180 +
32.181 +// Enable the channel.
32.182 +
32.183 +void
32.184 +I2c_x1600_channel::enable()
32.185 +{
32.186 + _regs[I2c_enable] = I2c_enable_enabled;
32.187 + while (!(_regs[I2c_enable_status] & I2c_enable_enabled));
32.188 +}
32.189 +
32.190 +// Disable the channel.
32.191 +
32.192 +void
32.193 +I2c_x1600_channel::disable()
32.194 +{
32.195 + _regs[I2c_enable] = 0;
32.196 + while (_regs[I2c_enable_status] & I2c_enable_enabled);
32.197 +}
32.198 +
32.199 +// Return the configured frequency.
32.200 +
32.201 +uint32_t
32.202 +I2c_x1600_channel::get_frequency()
32.203 +{
32.204 + return _frequency;
32.205 +}
32.206 +
32.207 +// Set the frequency-related peripheral parameters.
32.208 +
32.209 +void
32.210 +I2c_x1600_channel::set_frequency()
32.211 +{
32.212 + // The APB clock (PCLK) is used to drive I2C transfers. Its value must be
32.213 + // obtained from the CPM unit. It is known as I2C_DEV_CLK here and is scaled
32.214 + // to kHz in order to keep the numbers easily representable, as is the bus
32.215 + // frequency.
32.216 +
32.217 + uint32_t i2c_dev_clk = _cpm->get_frequency(Clock_pclock) / 1000;
32.218 +
32.219 + // Note that this is not I2C_DEV_CLK but the actual I2C bus frequency.
32.220 +
32.221 + uint32_t i2c_clk = _frequency / 1000;
32.222 +
32.223 + // Select the appropriate speed.
32.224 +
32.225 + unsigned int speed = (i2c_clk <= 100) ? I2c_speed_standard
32.226 + : (i2c_clk <= 400 ? I2c_speed_fast
32.227 + : I2c_speed_high);
32.228 +
32.229 + // NOTE: Permit broader configuration elsewhere.
32.230 +
32.231 + _regs[I2c_control] = (speed << I2c_speed_bit) |
32.232 + I2c_disable_slave |
32.233 + I2c_enable_restart |
32.234 + I2c_enable_master;
32.235 +
32.236 + // According to the programming manual, if the PCLK period is T{I2C_DEV_CLK}
32.237 + // then the I2C clock period is...
32.238 +
32.239 + // T{SCL} = T{SCL_high} + T{SCL_low}
32.240 +
32.241 + // Where...
32.242 +
32.243 + // T{SCL_low} = T{I2C_DEV_CLK} * (#cycles for low signal)
32.244 + // T{SCL_high} = T{I2C_DEV_CLK} * (#cycles for high signal)
32.245 +
32.246 + // Since, with minimum periods being defined...
32.247 +
32.248 + // T{SCL} >= T{min_SCL}
32.249 + // T{SCL_low} >= T{min_SCL_low}
32.250 + // T{SCL_high} >= T{min_SCL_high}
32.251 + // T{min_SCL} = T{min_SCL_low} + T{min_SCL_high}
32.252 +
32.253 + // Then the following applies...
32.254 +
32.255 + // T{I2C_DEV_CLK} * (#cycles for low signal)) >= T{min_SCL_low}
32.256 + // T{I2C_DEV_CLK} * (#cycles for high signal) >= T{min_SCL_high}
32.257 +
32.258 + // To work with different clock speeds while maintaining the low-to-high
32.259 + // ratios:
32.260 +
32.261 + // T{min_SCL_low} = T{min_SCL} * T{min_SCL_low} / T{min_SCL}
32.262 + // = T{min_SCL} * (T{min_SCL_low} / (T{min_SCL_low} + T{min_SCL_high}))
32.263 +
32.264 + // T{min_SCL_high} = T{min_SCL} * T{min_SCL_high} / T{min_SCL}
32.265 + // = T{min_SCL} * (T{min_SCL_high} / (T{min_SCL_low} + T{min_SCL_high}))
32.266 +
32.267 + // Constraints are given with respect to the high and low count registers.
32.268 +
32.269 + // #cycles for high signal = I2CxHCNT + 8
32.270 + // #cycles for low signal = I2CxLCNT + 1
32.271 +
32.272 + // From earlier, this yields...
32.273 +
32.274 + // T{I2C_DEV_CLK} * (I2CxLCNT + 1) >= T{min_SCL_low}
32.275 + // T{I2C_DEV_CLK} * (I2CxHCNT + 8) >= T{min_SCL_high}
32.276 +
32.277 + // Rearranging...
32.278 +
32.279 + // I2CxLCNT >= (T{min_SCL_low} / T{I2C_DEV_CLK}) - 1
32.280 + // >= T{min_SCL_low} * I2C_DEV_CLK - 1
32.281 +
32.282 + // I2CxHCNT >= (T{min_SCL_high} / T{I2C_DEV_CLK}) - 8
32.283 + // >= T{min_SCL_high} * I2C_DEV_CLK - 8
32.284 +
32.285 + // Introducing the definitions for the high and low periods...
32.286 +
32.287 + // I2CxLCNT >= T{min_SCL} * (T{min_SCL_low} / (T{min_SCL_low} + T{min_SCL_high})) * I2C_DEV_CLK - 1
32.288 + // >= (T{min_SCL_low} / T{min_SCL}) * I2C_DEV_CLK / I2C_BUS_CLK - 1
32.289 +
32.290 + // I2CxHCNT >= T{min_SCL} * (T{min_SCL_high} / (T{min_SCL_low} + T{min_SCL_high})) * I2C_DEV_CLK - 8
32.291 + // >= (T{min_SCL_high} / T{min_SCL}) * I2C_DEV_CLK / I2C_BUS_CLK - 8
32.292 +
32.293 + uint32_t high_reg, low_reg;
32.294 + uint32_t high_count, low_count;
32.295 + int32_t hold_count;
32.296 + uint32_t setup_count;
32.297 +
32.298 + // Level hold times:
32.299 +
32.300 + // Standard Fast High
32.301 + // SCL low 4.7us 1.3us 0.5us
32.302 + // SCL high 4.0us 0.6us 0.26us +
32.303 + // SCL period 8.7us 1.9us 0.76us =
32.304 +
32.305 + // See: UM10204 "I2C-bus specification and user manual"
32.306 + // Table 10: t{LOW} and t{HIGH}
32.307 +
32.308 + if (i2c_clk <= 100) // 100 kHz
32.309 + {
32.310 + low_count = (i2c_dev_clk * 47) / (i2c_clk * 87) - 1;
32.311 + high_count = (i2c_dev_clk * 40) / (i2c_clk * 87) - 8;
32.312 + low_reg = Std_low_count;
32.313 + high_reg = Std_high_count;
32.314 + }
32.315 + else if (i2c_clk <= 400) // 400 kHz
32.316 + {
32.317 + low_count = (i2c_dev_clk * 13) / (i2c_clk * 19) - 1;
32.318 + high_count = (i2c_dev_clk * 6) / (i2c_clk * 19) - 8;
32.319 + low_reg = Fast_low_count;
32.320 + high_reg = Fast_high_count;
32.321 + }
32.322 + else // > 400 kHz
32.323 + {
32.324 + // Note how the frequencies are scaled to accommodate the extra precision
32.325 + // required.
32.326 +
32.327 + low_count = (i2c_dev_clk / 10 * 50) / (i2c_clk / 10 * 76) - 1;
32.328 + high_count = (i2c_dev_clk / 10 * 26) / (i2c_clk / 10 * 76) - 8;
32.329 + low_reg = High_low_count;
32.330 + high_reg = High_high_count;
32.331 + }
32.332 +
32.333 + // Minimum counts are 8 and 6 for low and high respectively.
32.334 +
32.335 + _regs[low_reg] = low_count < 8 ? 8 : low_count;
32.336 + _regs[high_reg] = high_count < 6 ? 6 : high_count;
32.337 +
32.338 + // Data hold and setup times:
32.339 +
32.340 + // Standard Fast High
32.341 + // t{HD;DAT} 300ns 300ns 300ns
32.342 + // t{SU;DAT} 250ns 100ns 50ns
32.343 +
32.344 + // See: UM10204 "I2C-bus specification and user manual"
32.345 + // Table 10: t{HD;DAT} and t{SU;DAT}, also note [3]
32.346 +
32.347 + // T{delay} = (I2CSDAHD + 2) * T{I2C_DEV_CLK}
32.348 + // I2CSDAHD = T{delay} / T{I2C_DEV_CLK} - 2
32.349 + // I2CSDAHD = I2C_DEV_CLK * T{delay} - 2
32.350 +
32.351 + // Since the device clock is in kHz (scaled down by 1000) and the times are
32.352 + // given in ns (scaled up by 1000000000), a division of 1000000 is introduced.
32.353 +
32.354 + hold_count = (i2c_dev_clk * 300) / 1000000 - 1;
32.355 +
32.356 + _regs[I2c_sda_hold_time] = (_regs[I2c_sda_hold_time] & ~I2c_hold_mask) |
32.357 + (hold_count < 0 ? 0
32.358 + : (hold_count < (int) I2c_hold_mask ? (uint32_t) hold_count
32.359 + : I2c_hold_mask));
32.360 +
32.361 + // I2C_SDASU is apparently not used in master mode.
32.362 +
32.363 + // T{delay} = (I2CSDASU - 1) * T{I2C_DEV_CLK}
32.364 + // I2CSDASU = T{delay} / T{I2C_DEV_CLK} + 1
32.365 + // I2CSDASU = I2C_DEV_CLK * T{delay} + 1
32.366 +
32.367 + if (i2c_clk <= 100)
32.368 + setup_count = (i2c_dev_clk * 250) / 1000000 + 1;
32.369 + else if (i2c_clk <= 400)
32.370 + setup_count = (i2c_dev_clk * 100) / 1000000 + 1;
32.371 + else
32.372 + setup_count = (i2c_dev_clk * 50) / 1000000 + 1;
32.373 +
32.374 + _regs[I2c_sda_setup_time] = (_regs[I2c_sda_setup_time] & ~I2c_setup_mask) |
32.375 + (setup_count < I2c_setup_mask ? setup_count : I2c_setup_mask);
32.376 +}
32.377 +
32.378 +// Set the target address and enable transfer.
32.379 +// NOTE: Only supporting 7-bit addresses currently.
32.380 +
32.381 +void
32.382 +I2c_x1600_channel::set_target(uint8_t address)
32.383 +{
32.384 + disable();
32.385 + set_frequency();
32.386 + _regs[I2c_target_address] = address & I2c_target_7bits;
32.387 + init_parameters();
32.388 + enable();
32.389 +}
32.390 +
32.391 +
32.392 +
32.393 +// Reset interrupt flags upon certain conditions.
32.394 +
32.395 +void
32.396 +I2c_x1600_channel::reset_flags()
32.397 +{
32.398 + volatile uint32_t r;
32.399 +
32.400 + _regs[Int_mask] = 0;
32.401 +
32.402 + // Read from the register to clear interrupts.
32.403 +
32.404 + r = _regs[Int_combined_clear];
32.405 + (void) r;
32.406 +}
32.407 +
32.408 +// Initialise interrupt flags and queue thresholds for reading and writing.
32.409 +
32.410 +void
32.411 +I2c_x1600_channel::init_parameters()
32.412 +{
32.413 + // Handle read queue conditions for data, write queue conditions for commands.
32.414 +
32.415 + reset_flags();
32.416 +
32.417 + _regs[Tx_fifo_thold] = 0; // write when 0 in queue
32.418 +}
32.419 +
32.420 +
32.421 +
32.422 +// Return whether the device is active.
32.423 +
32.424 +int
32.425 +I2c_x1600_channel::active()
32.426 +{
32.427 + return _regs[I2c_status] & I2c_status_master_act;
32.428 +}
32.429 +
32.430 +// Return whether data is available to receive.
32.431 +
32.432 +int
32.433 +I2c_x1600_channel::have_input()
32.434 +{
32.435 + return _regs[I2c_status] & I2c_status_rx_nempty;
32.436 +}
32.437 +
32.438 +// Return whether data is queued for sending.
32.439 +
32.440 +int
32.441 +I2c_x1600_channel::have_output()
32.442 +{
32.443 + return !(_regs[I2c_status] & I2c_status_tx_empty);
32.444 +}
32.445 +
32.446 +// Return whether data can be queued for sending.
32.447 +
32.448 +int
32.449 +I2c_x1600_channel::can_send()
32.450 +{
32.451 + return _regs[I2c_status] & I2c_status_tx_nfull;
32.452 +}
32.453 +
32.454 +// Return whether a receive operation has failed.
32.455 +
32.456 +int
32.457 +I2c_x1600_channel::read_failed()
32.458 +{
32.459 + return _regs[Int_status] & Int_rx_of;
32.460 +}
32.461 +
32.462 +// Return whether a send operation has failed.
32.463 +
32.464 +int
32.465 +I2c_x1600_channel::write_failed()
32.466 +{
32.467 + return _regs[Int_status] & Int_tx_abort;
32.468 +}
32.469 +
32.470 +int
32.471 +I2c_x1600_channel::read_done()
32.472 +{
32.473 + return _pos == _total;
32.474 +}
32.475 +
32.476 +int
32.477 +I2c_x1600_channel::write_done()
32.478 +{
32.479 + return (_reqpos == _total) && !have_output();
32.480 +}
32.481 +
32.482 +unsigned
32.483 +I2c_x1600_channel::have_read()
32.484 +{
32.485 + return _pos;
32.486 +}
32.487 +
32.488 +unsigned
32.489 +I2c_x1600_channel::have_written()
32.490 +{
32.491 + return _reqpos;
32.492 +}
32.493 +
32.494 +int
32.495 +I2c_x1600_channel::failed()
32.496 +{
32.497 + return _fail;
32.498 +}
32.499 +
32.500 +
32.501 +
32.502 +// Send read commands for empty queue entries.
32.503 +
32.504 +void
32.505 +I2c_x1600_channel::queue_reads()
32.506 +{
32.507 + unsigned int remaining = _total - _reqpos;
32.508 + unsigned int queued = _reqpos - _pos;
32.509 + unsigned int can_queue = I2c_fifo_limit - queued;
32.510 +
32.511 + // Keep the number of reads in progress below the length of the read queue.
32.512 +
32.513 + if (!can_queue)
32.514 + return;
32.515 +
32.516 + // At most, only queue as many reads as are remaining.
32.517 +
32.518 + if (remaining < can_queue)
32.519 + can_queue = remaining;
32.520 +
32.521 + // Queue read requests for any remaining queue entries.
32.522 +
32.523 + while (can_queue && can_send())
32.524 + {
32.525 + uint32_t stop = _stop && (_reqpos == _total - 1) ? I2c_command_stop : I2c_command_no_stop;
32.526 +
32.527 + _regs[I2c_data_command] = I2c_command_read | stop;
32.528 + _reqpos++;
32.529 + can_queue--;
32.530 + }
32.531 +
32.532 + // Update the threshold to be notified of any reduced remaining amount.
32.533 +
32.534 + set_read_threshold();
32.535 +}
32.536 +
32.537 +// Send write commands for empty queue entries.
32.538 +
32.539 +void
32.540 +I2c_x1600_channel::queue_writes()
32.541 +{
32.542 + unsigned int remaining = _total - _reqpos;
32.543 + unsigned int can_queue = I2c_fifo_limit;
32.544 +
32.545 + if (remaining < can_queue)
32.546 + can_queue = remaining;
32.547 +
32.548 + // Queue write requests for any remaining queue entries.
32.549 +
32.550 + while (can_queue && can_send())
32.551 + {
32.552 + uint32_t stop = _stop && (_reqpos == _total - 1) ? I2c_command_stop : I2c_command_no_stop;
32.553 +
32.554 + _regs[I2c_data_command] = I2c_command_write | _buf[_reqpos] | stop;
32.555 + _reqpos++;
32.556 + can_queue--;
32.557 + }
32.558 +}
32.559 +
32.560 +// Store read command results from the queue.
32.561 +
32.562 +void
32.563 +I2c_x1600_channel::store_reads()
32.564 +{
32.565 + // Read any input and store it in the buffer.
32.566 +
32.567 + while (have_input() && (_pos < _reqpos))
32.568 + {
32.569 + _buf[_pos] = _regs[I2c_data_command] & 0xff;
32.570 + _pos++;
32.571 + }
32.572 +}
32.573 +
32.574 +void
32.575 +I2c_x1600_channel::set_read_threshold()
32.576 +{
32.577 + unsigned int queued = _reqpos - _pos;
32.578 +
32.579 + if (!queued)
32.580 + return;
32.581 +
32.582 + // Read all expected.
32.583 +
32.584 + _regs[Rx_fifo_thold] = queued - 1;
32.585 +}
32.586 +
32.587 +// Read from the target device.
32.588 +
32.589 +void
32.590 +I2c_x1600_channel::start_read(uint8_t buf[], unsigned int total, int stop)
32.591 +{
32.592 + _buf = buf;
32.593 + _total = total;
32.594 + _pos = 0;
32.595 + _reqpos = 0;
32.596 + _fail = 0;
32.597 + _stop = stop;
32.598 +
32.599 + reset_flags();
32.600 +
32.601 + _regs[Int_mask] = Int_rx_full | // read condition (reading needed)
32.602 + Int_rx_of | // abort condition
32.603 + Int_tx_abort; // general abort condition
32.604 +
32.605 + // Perform initial read requests.
32.606 +
32.607 + read();
32.608 +}
32.609 +
32.610 +void
32.611 +I2c_x1600_channel::read()
32.612 +{
32.613 + // Test for the general transfer abort condition.
32.614 +
32.615 + if (read_failed() || write_failed())
32.616 + {
32.617 + _fail = 1;
32.618 + _regs[Int_mask] = 0;
32.619 + disable();
32.620 + enable();
32.621 + return;
32.622 + }
32.623 +
32.624 + if (_regs[Int_status] & Int_rx_full)
32.625 + store_reads();
32.626 +
32.627 + // Always attempt to queue more read requests.
32.628 +
32.629 + queue_reads();
32.630 +}
32.631 +
32.632 +// Write to the target device.
32.633 +
32.634 +void
32.635 +I2c_x1600_channel::start_write(uint8_t buf[], unsigned int total, int stop)
32.636 +{
32.637 + _buf = buf;
32.638 + _total = total;
32.639 + _reqpos = 0;
32.640 + _fail = 0;
32.641 + _stop = stop;
32.642 +
32.643 + reset_flags();
32.644 +
32.645 + // Enable interrupts for further writes.
32.646 +
32.647 + _regs[Int_mask] = Int_tx_empty | // write condition (writing needed)
32.648 + Int_tx_abort; // abort condition
32.649 +
32.650 + // Perform initial writes.
32.651 +
32.652 + write();
32.653 +}
32.654 +
32.655 +void
32.656 +I2c_x1600_channel::write()
32.657 +{
32.658 + if (write_failed())
32.659 + {
32.660 + _fail = 1;
32.661 + _regs[Int_mask] = 0;
32.662 + disable();
32.663 + enable();
32.664 + return;
32.665 + }
32.666 +
32.667 + if (_regs[Int_status] & Int_tx_empty)
32.668 + queue_writes();
32.669 +}
32.670 +
32.671 +// Explicitly stop communication.
32.672 +
32.673 +void
32.674 +I2c_x1600_channel::stop()
32.675 +{
32.676 +}
32.677 +
32.678 +
32.679 +
32.680 +// Initialise the I2C controller.
32.681 +
32.682 +I2c_x1600_chip::I2c_x1600_chip(l4_addr_t start, l4_addr_t end,
32.683 + Cpm_x1600_chip *cpm,
32.684 + uint32_t frequency)
32.685 +: _start(start), _end(end), _cpm(cpm), _frequency(frequency)
32.686 +{
32.687 +}
32.688 +
32.689 +// Obtain a channel object.
32.690 +
32.691 +I2c_x1600_channel *
32.692 +I2c_x1600_chip::get_channel(uint8_t channel)
32.693 +{
32.694 + l4_addr_t block = _start + channel * I2c_block_offset;
32.695 + enum Clock_identifiers clocks[] = {Clock_i2c0, Clock_i2c1};
32.696 +
32.697 + if (channel < 2)
32.698 + return new I2c_x1600_channel(block, clocks[channel], _cpm, _frequency);
32.699 + else
32.700 + throw -L4_EINVAL;
32.701 +}
32.702 +
32.703 +
32.704 +
32.705 +// C language interface functions.
32.706 +
32.707 +void *x1600_i2c_init(l4_addr_t start, l4_addr_t end, void *cpm, uint32_t frequency)
32.708 +{
32.709 + return (void *) new I2c_x1600_chip(start, end, static_cast<Cpm_x1600_chip *>(cpm), frequency);
32.710 +}
32.711 +
32.712 +void *x1600_i2c_get_channel(void *i2c, uint8_t channel)
32.713 +{
32.714 + return static_cast<I2c_x1600_chip *>(i2c)->get_channel(channel);
32.715 +}
32.716 +
32.717 +uint32_t x1600_i2c_get_frequency(void *i2c_channel)
32.718 +{
32.719 + return static_cast<I2c_x1600_channel *>(i2c_channel)->get_frequency();
32.720 +}
32.721 +
32.722 +void x1600_i2c_set_target(void *i2c_channel, uint8_t addr)
32.723 +{
32.724 + static_cast<I2c_x1600_channel *>(i2c_channel)->set_target(addr);
32.725 +}
32.726 +
32.727 +void x1600_i2c_start_read(void *i2c_channel, uint8_t buf[], unsigned int total,
32.728 + int stop)
32.729 +{
32.730 + static_cast<I2c_x1600_channel *>(i2c_channel)->start_read(buf, total, stop);
32.731 +}
32.732 +
32.733 +void x1600_i2c_read(void *i2c_channel)
32.734 +{
32.735 + static_cast<I2c_x1600_channel *>(i2c_channel)->read();
32.736 +}
32.737 +
32.738 +void x1600_i2c_start_write(void *i2c_channel, uint8_t buf[], unsigned int total,
32.739 + int stop)
32.740 +{
32.741 + static_cast<I2c_x1600_channel *>(i2c_channel)->start_write(buf, total, stop);
32.742 +}
32.743 +
32.744 +void x1600_i2c_write(void *i2c_channel)
32.745 +{
32.746 + static_cast<I2c_x1600_channel *>(i2c_channel)->write();
32.747 +}
32.748 +
32.749 +int x1600_i2c_read_done(void *i2c_channel)
32.750 +{
32.751 + return static_cast<I2c_x1600_channel *>(i2c_channel)->read_done();
32.752 +}
32.753 +
32.754 +int x1600_i2c_write_done(void *i2c_channel)
32.755 +{
32.756 + return static_cast<I2c_x1600_channel *>(i2c_channel)->write_done();
32.757 +}
32.758 +
32.759 +unsigned int x1600_i2c_have_read(void *i2c_channel)
32.760 +{
32.761 + return static_cast<I2c_x1600_channel *>(i2c_channel)->have_read();
32.762 +}
32.763 +
32.764 +unsigned int x1600_i2c_have_written(void *i2c_channel)
32.765 +{
32.766 + return static_cast<I2c_x1600_channel *>(i2c_channel)->have_written();
32.767 +}
32.768 +
32.769 +int x1600_i2c_failed(void *i2c_channel)
32.770 +{
32.771 + return static_cast<I2c_x1600_channel *>(i2c_channel)->failed();
32.772 +}
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
33.2 +++ b/pkg/devices/lib/spi/Makefile Tue Oct 24 18:52:06 2023 +0200
33.3 @@ -0,0 +1,8 @@
33.4 +PKGDIR ?= ../..
33.5 +L4DIR ?= $(PKGDIR)/../..
33.6 +
33.7 +TARGET := include src
33.8 +
33.9 +include $(L4DIR)/mk/subdir.mk
33.10 +
33.11 +src: include
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
34.2 +++ b/pkg/devices/lib/spi/include/Makefile Tue Oct 24 18:52:06 2023 +0200
34.3 @@ -0,0 +1,4 @@
34.4 +PKGDIR = ../../..
34.5 +L4DIR ?= $(PKGDIR)/../..
34.6 +
34.7 +include $(L4DIR)/mk/include.mk
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
35.2 +++ b/pkg/devices/lib/spi/include/spi-gpio.h Tue Oct 24 18:52:06 2023 +0200
35.3 @@ -0,0 +1,69 @@
35.4 +/*
35.5 + * Perform SPI communication using GPIO operations.
35.6 + *
35.7 + * Copyright (C) 2018, 2020, 2023 Paul Boddie <paul@boddie.org.uk>
35.8 + *
35.9 + * This program is free software; you can redistribute it and/or
35.10 + * modify it under the terms of the GNU General Public License as
35.11 + * published by the Free Software Foundation; either version 2 of
35.12 + * the License, or (at your option) any later version.
35.13 + *
35.14 + * This program is distributed in the hope that it will be useful,
35.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
35.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35.17 + * GNU General Public License for more details.
35.18 + *
35.19 + * You should have received a copy of the GNU General Public License
35.20 + * along with this program; if not, write to the Free Software
35.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
35.22 + * Boston, MA 02110-1301, USA
35.23 + */
35.24 +
35.25 +#include <l4/devices/gpio.h>
35.26 +#include <stdint.h>
35.27 +
35.28 +#pragma once
35.29 +
35.30 +
35.31 +
35.32 +#ifdef __cplusplus
35.33 +
35.34 +/* SPI peripheral device. */
35.35 +
35.36 +class Spi_gpio
35.37 +{
35.38 + Hw::Gpio_chip *_clock_device;
35.39 + int _clock_pin;
35.40 + Hw::Gpio_chip *_data_device;
35.41 + int _data_pin;
35.42 + Hw::Gpio_chip *_enable_device;
35.43 + int _enable_pin;
35.44 + uint32_t _frequency;
35.45 +
35.46 +public:
35.47 + /* Associate the device with a particular memory region. */
35.48 +
35.49 + explicit Spi_gpio(Hw::Gpio_chip *clock_device, int clock_pin,
35.50 + Hw::Gpio_chip *data_device, int data_pin,
35.51 + Hw::Gpio_chip *enable_device, int enable_pin,
35.52 + uint32_t frequency = 0);
35.53 +
35.54 + void send(int bytes, const uint8_t data[]);
35.55 +};
35.56 +
35.57 +#endif /* __cplusplus */
35.58 +
35.59 +
35.60 +
35.61 +/* C language interface. */
35.62 +
35.63 +EXTERN_C_BEGIN
35.64 +
35.65 +void *spi_gpio_get_channel(void *clock_chip, int clock_pin,
35.66 + void *data_chip, int data_pin,
35.67 + void *enable_chip, int enable_pin,
35.68 + uint32_t frequency);
35.69 +
35.70 +void spi_gpio_send(void *channel, int bytes, const uint8_t data[]);
35.71 +
35.72 +EXTERN_C_END
36.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
36.2 +++ b/pkg/devices/lib/spi/src/Makefile Tue Oct 24 18:52:06 2023 +0200
36.3 @@ -0,0 +1,13 @@
36.4 +PKGDIR ?= ../../..
36.5 +L4DIR ?= $(PKGDIR)/../..
36.6 +
36.7 +TARGET = libspi.o.a libspi.o.so
36.8 +PC_FILENAME := libdrivers-spi
36.9 +
36.10 +SRC_CC := gpio.cc
36.11 +
36.12 +PRIVATE_INCDIR += $(PKGDIR)/lib/spi/include
36.13 +
36.14 +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-common libdrivers-gpio
36.15 +
36.16 +include $(L4DIR)/mk/lib.mk
37.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
37.2 +++ b/pkg/devices/lib/spi/src/gpio.cc Tue Oct 24 18:52:06 2023 +0200
37.3 @@ -0,0 +1,116 @@
37.4 +/*
37.5 + * Perform SPI communication using GPIO operations.
37.6 + *
37.7 + * Copyright (C) 2018, 2020, 2023 Paul Boddie <paul@boddie.org.uk>
37.8 + *
37.9 + * This program is free software; you can redistribute it and/or
37.10 + * modify it under the terms of the GNU General Public License as
37.11 + * published by the Free Software Foundation; either version 2 of
37.12 + * the License, or (at your option) any later version.
37.13 + *
37.14 + * This program is distributed in the hope that it will be useful,
37.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
37.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37.17 + * GNU General Public License for more details.
37.18 + *
37.19 + * You should have received a copy of the GNU General Public License
37.20 + * along with this program; if not, write to the Free Software
37.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
37.22 + * Boston, MA 02110-1301, USA
37.23 + */
37.24 +
37.25 +#include <l4/devices/spi-gpio.h>
37.26 +#include <time.h>
37.27 +
37.28 +
37.29 +
37.30 +Spi_gpio::Spi_gpio(Hw::Gpio_chip *clock_device, int clock_pin,
37.31 + Hw::Gpio_chip *data_device, int data_pin,
37.32 + Hw::Gpio_chip *enable_device, int enable_pin,
37.33 + uint32_t frequency)
37.34 +: _clock_device(clock_device),
37.35 + _clock_pin(clock_pin),
37.36 + _data_device(data_device),
37.37 + _data_pin(data_pin),
37.38 + _enable_device(enable_device),
37.39 + _enable_pin(enable_pin),
37.40 + _frequency(frequency)
37.41 +{
37.42 + _clock_device->setup(_clock_pin, Hw::Gpio_chip::Output, 1);
37.43 + _data_device->setup(_data_pin, Hw::Gpio_chip::Output, 0);
37.44 + _enable_device->setup(_enable_pin, Hw::Gpio_chip::Output, 1);
37.45 +}
37.46 +
37.47 +/* Send a SPI command. */
37.48 +
37.49 +void Spi_gpio::send(int bytes, const uint8_t data[])
37.50 +{
37.51 + struct timespec ts;
37.52 + uint8_t mask;
37.53 + int bit, byte;
37.54 +
37.55 + if (_frequency)
37.56 + {
37.57 + ts.tv_sec = 0;
37.58 + ts.tv_nsec = 1000000000 / _frequency;
37.59 + }
37.60 +
37.61 + /* Initialise pin levels. */
37.62 +
37.63 + _enable_device->set(_enable_pin, 1);
37.64 + _clock_device->set(_clock_pin, 1);
37.65 + _data_device->set(_data_pin, 0);
37.66 +
37.67 + /* Enter the transmission state. */
37.68 +
37.69 + _enable_device->set(_enable_pin, 0);
37.70 +
37.71 + /* Clock data using the clock and data outputs. */
37.72 +
37.73 + for (byte = 0; byte < bytes; byte++)
37.74 + {
37.75 + mask = 0x80;
37.76 +
37.77 + for (bit = 0; bit < 8; bit++)
37.78 + {
37.79 + /* NOTE: Data presented on falling clock level and sampled on rising clock
37.80 + level. This is SPI mode 3, or 0 given that the enable level is
37.81 + driven low immediately before the first bit is presented. */
37.82 +
37.83 + _clock_device->set(_clock_pin, 0);
37.84 + _data_device->set(_data_pin, data[byte] & mask ? 1 : 0);
37.85 +
37.86 + if (_frequency)
37.87 + nanosleep(&ts, NULL);
37.88 +
37.89 + _clock_device->set(_clock_pin, 1);
37.90 +
37.91 + if (_frequency)
37.92 + nanosleep(&ts, NULL);
37.93 +
37.94 + mask >>= 1;
37.95 + }
37.96 + }
37.97 +
37.98 + _enable_device->set(_enable_pin, 1);
37.99 +}
37.100 +
37.101 +
37.102 +
37.103 +/* C language interface. */
37.104 +
37.105 +void *spi_gpio_get_channel(void *clock_chip, int clock_pin,
37.106 + void *data_chip, int data_pin,
37.107 + void *enable_chip, int enable_pin,
37.108 + uint32_t frequency)
37.109 +{
37.110 + return (void *) new Spi_gpio(reinterpret_cast<Hw::Gpio_chip *>(clock_chip), clock_pin,
37.111 + reinterpret_cast<Hw::Gpio_chip *>(data_chip), data_pin,
37.112 + reinterpret_cast<Hw::Gpio_chip *>(enable_chip), enable_pin,
37.113 + frequency);
37.114 +}
37.115 +
37.116 +void spi_gpio_send(void *channel, int bytes, const uint8_t data[])
37.117 +{
37.118 + static_cast<Spi_gpio *>(channel)->send(bytes, data);
37.119 +}
38.1 --- a/pkg/devices/spi/src/jz4740/Makefile Fri Sep 22 21:56:34 2023 +0200
38.2 +++ b/pkg/devices/spi/src/jz4740/Makefile Tue Oct 24 18:52:06 2023 +0200
38.3 @@ -27,7 +27,7 @@
38.4
38.5 SRC_CC = $(SERVER_INTERFACES_SRC_CC) $(PLAIN_SRC_CC)
38.6
38.7 -REQUIRES_LIBS = l4re_c l4re_c-util libdevice-util libdrivers-gpio libipc
38.8 +REQUIRES_LIBS = l4re_c l4re_c-util libdevice-util libdrivers-gpio libdrivers-spi libipc
38.9
38.10 PRIVATE_INCDIR = $(PKGDIR)/spi/include $(PKGDIR)/util/include \
38.11 $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR)
39.1 --- a/pkg/devices/spi/src/jz4740/spi-jz4740.cc Fri Sep 22 21:56:34 2023 +0200
39.2 +++ b/pkg/devices/spi/src/jz4740/spi-jz4740.cc Tue Oct 24 18:52:06 2023 +0200
39.3 @@ -20,6 +20,7 @@
39.4 */
39.5
39.6 #include <l4/devices/gpio-jz4740.h>
39.7 +#include <l4/devices/spi-gpio.h>
39.8 #include <l4/devices/memory.h>
39.9
39.10 #include <l4/re/env.h>
39.11 @@ -54,20 +55,13 @@
39.12
39.13 class SPI_server : public SPI
39.14 {
39.15 - Gpio_jz4740_chip *_clock_device = 0, *_data_device = 0, *_enable_device = 0;
39.16 - int _clock_pin, _data_pin, _enable_pin;
39.17 + Spi_gpio *_spi;
39.18
39.19 public:
39.20 /* Associate the device with a particular memory region. */
39.21
39.22 - explicit SPI_server(Gpio_jz4740_chip *clock_device,
39.23 - Gpio_jz4740_chip *data_device,
39.24 - Gpio_jz4740_chip *enable_device,
39.25 - int clock_pin, int data_pin, int enable_pin)
39.26 - : _clock_device(clock_device),
39.27 - _data_device(data_device),
39.28 - _enable_device(enable_device),
39.29 - _clock_pin(clock_pin), _data_pin(data_pin), _enable_pin(enable_pin)
39.30 + explicit SPI_server(Spi_gpio *spi)
39.31 + : _spi(spi)
39.32 {
39.33 }
39.34
39.35 @@ -75,31 +69,15 @@
39.36
39.37 long send(int bits, int data)
39.38 {
39.39 - uint32_t mask = 1 << (bits - 1);
39.40 - int bit;
39.41 -
39.42 - /* Initialise pin levels. */
39.43 + int bytes = (bits + 7) / 8;
39.44 + uint8_t buffer[bytes];
39.45
39.46 - _enable_device->set(_enable_pin, 1);
39.47 - _clock_device->set(_clock_pin, 1);
39.48 - _data_device->set(_data_pin, 0);
39.49 -
39.50 - /* Enter the transmission state. */
39.51 + /* Convert the data into a sequence of bytes. */
39.52
39.53 - _enable_device->set(_enable_pin, 0);
39.54 -
39.55 - /* Clock data using the clock and data outputs. */
39.56 -
39.57 - for (bit = 0; bit < bits; bit++)
39.58 - {
39.59 - _clock_device->set(_clock_pin, 0);
39.60 - _data_device->set(_data_pin, data & mask ? 1 : 0);
39.61 - _clock_device->set(_clock_pin, 1);
39.62 - mask >>= 1;
39.63 - }
39.64 + for (int byte = bytes; byte > 0; byte--)
39.65 + buffer[byte - 1] = (data >> ((byte - 1) * 8)) & 0xff;
39.66
39.67 - _enable_device->set(_enable_pin, 1);
39.68 -
39.69 + _spi->send(bytes, buffer);
39.70 return L4_EOK;
39.71 }
39.72 };
39.73 @@ -182,10 +160,14 @@
39.74
39.75 gpio_port_enable.setup(enable_pin, Hw::Gpio_chip::Output, 0);
39.76
39.77 + /* Create an object for SPI communication. */
39.78 +
39.79 + Spi_gpio spi(&gpio_port_clock, clock_pin, &gpio_port_data, data_pin,
39.80 + &gpio_port_enable, enable_pin);
39.81 +
39.82 /* Initialise and register a new server object. */
39.83
39.84 - SPI_server obj(&gpio_port_clock, &gpio_port_data, &gpio_port_enable,
39.85 - clock_pin, data_pin, enable_pin);
39.86 + SPI_server obj(&spi);
39.87
39.88 /* Bind and start the IPC server loop. */
39.89
40.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
40.2 +++ b/pkg/devices/util/include/dma.h Tue Oct 24 18:52:06 2023 +0200
40.3 @@ -0,0 +1,32 @@
40.4 +/*
40.5 + * DMA-related memory allocation utility functions.
40.6 + *
40.7 + * Copyright (C) 2023 Paul Boddie <paul@boddie.org.uk>
40.8 + *
40.9 + * This program is free software; you can redistribute it and/or
40.10 + * modify it under the terms of the GNU General Public License as
40.11 + * published by the Free Software Foundation; either version 2 of
40.12 + * the License, or (at your option) any later version.
40.13 + *
40.14 + * This program is distributed in the hope that it will be useful,
40.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
40.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40.17 + * GNU General Public License for more details.
40.18 + *
40.19 + * You should have received a copy of the GNU General Public License
40.20 + * along with this program; if not, write to the Free Software
40.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
40.22 + * Boston, MA 02110-1301, USA
40.23 + */
40.24 +
40.25 +#pragma once
40.26 +
40.27 +#include <l4/re/c/dma_space.h>
40.28 +#include <l4/sys/types.h>
40.29 +
40.30 +EXTERN_C_BEGIN
40.31 +
40.32 +long get_dma_region(unsigned long size, int align, l4_addr_t *vaddr,
40.33 + l4re_dma_space_dma_addr_t *paddr, l4_cap_idx_t *mem);
40.34 +
40.35 +EXTERN_C_END
41.1 --- a/pkg/devices/util/include/memory.h Fri Sep 22 21:56:34 2023 +0200
41.2 +++ b/pkg/devices/util/include/memory.h Tue Oct 24 18:52:06 2023 +0200
41.3 @@ -40,4 +40,7 @@
41.4
41.5 int get_memory(char const *hid, l4_addr_t *start, l4_addr_t *end);
41.6
41.7 +int get_memory_complete(char const *hid, l4_addr_t *start, l4_addr_t *end,
41.8 + l4_addr_t *phys_start, l4_addr_t *phys_end);
41.9 +
41.10 EXTERN_C_END
42.1 --- a/pkg/devices/util/src/Makefile Fri Sep 22 21:56:34 2023 +0200
42.2 +++ b/pkg/devices/util/src/Makefile Tue Oct 24 18:52:06 2023 +0200
42.3 @@ -4,7 +4,7 @@
42.4 TARGET = libdevice_util.o.a libdevice_util.o.so
42.5 PC_FILENAME := libdevice-util
42.6
42.7 -SRC_CC := dataspace.cc dl.cc event-loop.cc memory.cc
42.8 +SRC_CC := dataspace.cc dl.cc dma.cc event-loop.cc memory.cc
42.9
42.10 PRIVATE_INCDIR += $(PKGDIR)/util/include
42.11
43.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
43.2 +++ b/pkg/devices/util/src/dma.cc Tue Oct 24 18:52:06 2023 +0200
43.3 @@ -0,0 +1,108 @@
43.4 +/*
43.5 + * DMA-related memory allocation utility functions.
43.6 + *
43.7 + * Copyright (C) 2023 Paul Boddie <paul@boddie.org.uk>
43.8 + *
43.9 + * This program is free software; you can redistribute it and/or
43.10 + * modify it under the terms of the GNU General Public License as
43.11 + * published by the Free Software Foundation; either version 2 of
43.12 + * the License, or (at your option) any later version.
43.13 + *
43.14 + * This program is distributed in the hope that it will be useful,
43.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
43.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43.17 + * GNU General Public License for more details.
43.18 + *
43.19 + * You should have received a copy of the GNU General Public License
43.20 + * along with this program; if not, write to the Free Software
43.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
43.22 + * Boston, MA 02110-1301, USA
43.23 + */
43.24 +
43.25 +#include <l4/re/c/dataspace.h>
43.26 +#include <l4/re/c/dma_space.h>
43.27 +#include <l4/re/c/mem_alloc.h>
43.28 +#include <l4/re/env.h>
43.29 +#include <l4/re/protocols.h>
43.30 +#include <l4/sys/factory.h>
43.31 +#include <l4/sys/types.h>
43.32 +#include <l4/vbus/vbus.h>
43.33 +
43.34 +#include <ipc/cap_alloc.h>
43.35 +#include <ipc/mem_ipc.h>
43.36 +
43.37 +#include "dma.h"
43.38 +#include "memory.h"
43.39 +
43.40 +
43.41 +
43.42 +// Allocate a memory region of the given size for DMA.
43.43 +
43.44 +long get_dma_region(unsigned long size, int align, l4_addr_t *vaddr,
43.45 + l4re_dma_space_dma_addr_t *paddr, l4_cap_idx_t *mem)
43.46 +{
43.47 + // Memory allocation capabilities.
43.48 +
43.49 + l4_cap_idx_t dma, vbus;
43.50 +
43.51 + // Obtain capabilities for the DMA region and the vbus.
43.52 +
43.53 + dma = ipc_cap_alloc();
43.54 +
43.55 + if (l4_is_invalid_cap(dma))
43.56 + return -L4_ENOENT;
43.57 +
43.58 + vbus = l4re_env_get_cap("vbus");
43.59 +
43.60 + if (l4_is_invalid_cap(vbus))
43.61 + return -L4_ENOENT;
43.62 +
43.63 + // Create the DMA space.
43.64 +
43.65 + if (l4_error(l4_factory_create(l4re_env()->mem_alloc, L4RE_PROTO_DMA_SPACE, dma)))
43.66 + return -L4_ENOMEM;
43.67 +
43.68 + // Find the DMA domain and assign the DMA space.
43.69 +
43.70 + l4vbus_device_handle_t device = L4VBUS_NULL;
43.71 + l4vbus_resource_t dma_resource;
43.72 +
43.73 + if (!find_resource(&device, &dma_resource, L4VBUS_RESOURCE_DMA_DOMAIN))
43.74 + return -L4_ENOENT;
43.75 +
43.76 + if (l4vbus_assign_dma_domain(vbus, dma_resource.start,
43.77 + L4VBUS_DMAD_BIND | L4VBUS_DMAD_L4RE_DMA_SPACE,
43.78 + dma))
43.79 + return -L4_ENOMEM;
43.80 +
43.81 + // Allocate memory at the given alignment.
43.82 +
43.83 + const l4_size_t alloc_flags = L4RE_MA_CONTINUOUS | L4RE_MA_PINNED;
43.84 + const l4re_rm_flags_t attach_flags = L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_RW;
43.85 +
43.86 + // Map the allocated memory, obtaining a virtual address.
43.87 +
43.88 + *vaddr = 0;
43.89 +
43.90 + if (ipc_new_dataspace(size, alloc_flags, align, mem))
43.91 + return -L4_ENOMEM;
43.92 +
43.93 + if (ipc_attach_dataspace_align(*mem, size, attach_flags, align, (void **) vaddr))
43.94 + return -L4_ENOMEM;
43.95 +
43.96 + // Obtain a physical address.
43.97 +
43.98 + l4_size_t size_out = size;
43.99 + *paddr = 0;
43.100 +
43.101 + if (l4re_dma_space_map(dma, *mem | L4_CAP_FPAGE_RW, 0, &size_out, 0,
43.102 + L4RE_DMA_SPACE_TO_DEVICE, paddr))
43.103 + return -L4_ENOMEM;
43.104 +
43.105 + // Test the mapped region size.
43.106 +
43.107 + if (size_out != size)
43.108 + return -L4_ENOMEM;
43.109 +
43.110 + return L4_EOK;
43.111 +}
44.1 --- a/pkg/devices/util/src/memory.cc Fri Sep 22 21:56:34 2023 +0200
44.2 +++ b/pkg/devices/util/src/memory.cc Tue Oct 24 18:52:06 2023 +0200
44.3 @@ -76,6 +76,14 @@
44.4
44.5 int get_memory(char const *hid, l4_addr_t *start, l4_addr_t *end)
44.6 {
44.7 + l4_addr_t phys_start, phys_end;
44.8 +
44.9 + return get_memory_complete(hid, start, end, &phys_start, &phys_end);
44.10 +}
44.11 +
44.12 +int get_memory_complete(char const *hid, l4_addr_t *start, l4_addr_t *end,
44.13 + l4_addr_t *phys_start, l4_addr_t *phys_end)
44.14 +{
44.15 l4io_device_handle_t dh;
44.16 l4io_resource_handle_t rh;
44.17 l4io_resource_t res;
44.18 @@ -98,6 +106,8 @@
44.19 return result;
44.20
44.21 *end = *start + (res.end - res.start + 1);
44.22 + *phys_start = res.start;
44.23 + *phys_end = res.end;
44.24
44.25 return 0;
44.26 }
45.1 --- a/pkg/landfall-examples/letux400_dma/letux400_dma.cc Fri Sep 22 21:56:34 2023 +0200
45.2 +++ b/pkg/landfall-examples/letux400_dma/letux400_dma.cc Tue Oct 24 18:52:06 2023 +0200
45.3 @@ -19,16 +19,14 @@
45.4 * Boston, MA 02110-1301, USA
45.5 */
45.6
45.7 +#include <l4/devices/dma.h>
45.8 #include <l4/devices/cpm-jz4730.h>
45.9 #include <l4/devices/dma-jz4730.h>
45.10 #include <l4/devices/memory.h>
45.11
45.12 #include <l4/re/c/util/cap_alloc.h>
45.13 #include <l4/re/c/dataspace.h>
45.14 -#include <l4/re/c/dma_space.h>
45.15 -#include <l4/re/c/mem_alloc.h>
45.16 #include <l4/re/c/rm.h>
45.17 -#include <l4/re/protocols.h>
45.18
45.19 #include <l4/sys/err.h>
45.20 #include <l4/sys/factory.h>
45.21 @@ -36,8 +34,6 @@
45.22 #include <l4/sys/irq.h>
45.23 #include <l4/sys/rcv_endpoint.h>
45.24
45.25 -#include <l4/vbus/vbus.h>
45.26 -
45.27 #include <stdio.h>
45.28 #include <string.h>
45.29 #include <unistd.h>
45.30 @@ -61,88 +57,27 @@
45.31 long err;
45.32 void *cpm;
45.33 void *dmac, *dma0;
45.34 - l4_cap_idx_t dma, vbus;
45.35 -
45.36 - dma = l4re_util_cap_alloc();
45.37 - vbus = l4re_env_get_cap("vbus");
45.38 -
45.39 - if (l4_is_invalid_cap(dma))
45.40 - {
45.41 - printf("Could not allocate DMA capability.\n");
45.42 - return 1;
45.43 - }
45.44 -
45.45 - /* Create the DMA space. */
45.46 -
45.47 - err = l4_error(l4_factory_create(l4re_env()->mem_alloc, L4RE_PROTO_DMA_SPACE, dma));
45.48 -
45.49 - if (err)
45.50 - {
45.51 - printf("Could not create DMA space: %s\n", l4sys_errtostr(err));
45.52 - return 1;
45.53 - }
45.54 -
45.55 - l4vbus_device_handle_t device = L4VBUS_NULL;
45.56 - l4vbus_resource_t dma_resource;
45.57 -
45.58 - if (!find_resource(&device, &dma_resource, L4VBUS_RESOURCE_DMA_DOMAIN))
45.59 - {
45.60 - printf("Could not find DMA domain.\n");
45.61 - return 1;
45.62 - }
45.63 -
45.64 - err = l4vbus_assign_dma_domain(vbus, dma_resource.start,
45.65 - L4VBUS_DMAD_BIND | L4VBUS_DMAD_L4RE_DMA_SPACE,
45.66 - dma);
45.67 -
45.68 - if (err)
45.69 - {
45.70 - printf("Could not assign DMA space: %s\n", l4sys_errtostr(err));
45.71 - return 1;
45.72 - }
45.73
45.74 /* Allocate memory to test transfers. */
45.75
45.76 l4_cap_idx_t ds0_mem, ds1_mem;
45.77 - l4_size_t ds0_size = L4_PAGESIZE, ds0_psize, ds1_size = L4_PAGESIZE, ds1_psize;
45.78 + l4_size_t ds0_size = L4_PAGESIZE, ds1_size = L4_PAGESIZE;
45.79 l4_addr_t ds0_addr, ds1_addr;
45.80 l4re_dma_space_dma_addr_t ds0_paddr, ds1_paddr;
45.81
45.82 - ds0_mem = l4re_util_cap_alloc();
45.83 - ds1_mem = l4re_util_cap_alloc();
45.84 + err = get_dma_region(ds0_size, 8, &ds0_addr, &ds0_paddr, &ds0_mem);
45.85
45.86 - if (l4_is_invalid_cap(ds0_mem) || l4_is_invalid_cap(ds1_mem))
45.87 - {
45.88 - printf("Could not allocate memory capabilities.\n");
45.89 - return 1;
45.90 - }
45.91 -
45.92 - if (l4re_ma_alloc_align(ds0_size, ds0_mem, L4RE_MA_CONTINUOUS | L4RE_MA_PINNED, 8) ||
45.93 - l4re_ma_alloc_align(ds1_size, ds1_mem, L4RE_MA_CONTINUOUS | L4RE_MA_PINNED, 8))
45.94 + if (err)
45.95 {
45.96 - printf("Could not allocate memory.\n");
45.97 + printf("Could not allocate region #0.\n");
45.98 return 1;
45.99 }
45.100
45.101 - if (l4re_rm_attach((void **) &ds0_addr, ds0_size,
45.102 - L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_EAGER_MAP | L4RE_RM_F_RW,
45.103 - ds0_mem, 0, L4_PAGESHIFT) ||
45.104 - l4re_rm_attach((void **) &ds1_addr, ds1_size,
45.105 - L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_EAGER_MAP | L4RE_RM_F_RW,
45.106 - ds1_mem, 0, L4_PAGESHIFT))
45.107 - {
45.108 - printf("Could not map memory.\n");
45.109 - return 1;
45.110 - }
45.111 -
45.112 - err = l4re_dma_space_map(dma, ds0_mem | L4_CAP_FPAGE_RW, 0, &ds0_psize, 0,
45.113 - L4RE_DMA_SPACE_BIDIRECTIONAL, &ds0_paddr) ||
45.114 - l4re_dma_space_map(dma, ds1_mem | L4_CAP_FPAGE_RW, 0, &ds1_psize, 0,
45.115 - L4RE_DMA_SPACE_BIDIRECTIONAL, &ds1_paddr);
45.116 + err = get_dma_region(ds1_size, 8, &ds1_addr, &ds1_paddr, &ds1_mem);
45.117
45.118 if (err)
45.119 {
45.120 - printf("Could not get physical addresses for memory: %s\n", l4sys_errtostr(err));
45.121 + printf("Could not allocate region #1.\n");
45.122 return 1;
45.123 }
45.124
45.125 @@ -253,13 +188,19 @@
45.126
45.127 printf("Transfer from %llx to %llx...\n", ds0_paddr, ds1_paddr);
45.128
45.129 - unsigned int ntransferred = jz4730_dma_transfer(dma0, (uint32_t) ds0_paddr,
45.130 - (uint32_t) ds1_paddr,
45.131 - L4_PAGESIZE / 4,
45.132 - Dma_trans_unit_size_32_bit,
45.133 - Dma_request_auto);
45.134 + unsigned int count = L4_PAGESIZE / 4;
45.135
45.136 - printf("Transferred: %d\n", ntransferred);
45.137 + unsigned int to_transfer = jz4730_dma_transfer(dma0, (uint32_t) ds0_paddr,
45.138 + (uint32_t) ds1_paddr,
45.139 + count,
45.140 + 1, 1,
45.141 + 4, 4,
45.142 + 4,
45.143 + Dma_request_auto);
45.144 +
45.145 + unsigned int transferred = to_transfer ? count - jz4730_dma_wait(dma0) : 0;
45.146 +
45.147 + printf("Transferred: %d\n", transferred);
45.148 printf("Source: %s\n", (char *) ds0_addr);
45.149 printf("Destination: %s\n", (char *) ds1_addr);
45.150