# HG changeset patch # User Paul Boddie # Date 1714254388 -7200 # Node ID e7c6fdf897063d73caef2af02c510fcf9173b8f3 # Parent 8aead0ac0492376c12c50b5827503b80bf187f17 Introduced more generic handling of CPM, DMA and MSC abstractions. Added improved CPM support for the JZ4730. Changed the MSC block server to use the machine name for configuration. diff -r 8aead0ac0492 -r e7c6fdf89706 conf/landfall-examples/mips-jz4780-msc-block.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-jz4780-msc-block.cfg Sat Apr 27 23:46:28 2024 +0200 @@ -0,0 +1,87 @@ +-- vim:set ft=lua: + +local L4 = require("L4"); + +local l = L4.default_loader; + +local io_buses = + { + common = l:new_channel(); + }; + +l:start({ + caps = { + common = io_buses.common:svr(), + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + log = { "IO", "y" }, + l4re_dbg = L4.Dbg.Warn, + }, + "rom/io rom/hw_devices.io rom/mips-jz4780-msc-block.io"); + +local block_server = l:new_channel(); + +l:startv({ + caps = { + fsserver = block_server:svr(), + jdb = L4.Env.jdb, -- to set the server name + icu = L4.Env.icu, + vbus = io_buses.common, + }, + log = { "server", "r" }, + }, + -- arguments: machine, MSC channel/device, DMA channel, card index, memory pages + "rom/msc_block_server", "jz4780", "0", "0", "0", "10"); + +local pipe_server = l:new_channel(); + +l:startv({ + caps = { + pipeserver = pipe_server:svr(), + jdb = L4.Env.jdb, -- to set the server name + }, + log = { "pipes", "r" }, + }, + "rom/pipe_server", "10"); + +local ext2server = l:new_channel(); + +l:startv({ + caps = { + blockserver = block_server, + pipeserver = pipe_server, + fsserver = ext2server:svr(), + jdb = L4.Env.jdb, -- to set the server name + }, + log = { "ext2svr", "y" }, + }, + "rom/ext2_server", "blockserver", "1", "20", "fsserver"); + +-- Obtain user filesystems with umask 0022 (18). + +local open_for_user = 6; +local ext2server_paulb = L4.cast(L4.Proto.Factory, ext2server):create(open_for_user, 1000, 1000, 18); + +local process_server = l:new_channel(); + +l:startv({ + caps = { + fsserver = ext2server_paulb, + prserver = process_server:svr(), + jdb = L4.Env.jdb, -- to set the server name + }, + log = { "process", "y" }, + }, + "rom/process_server", "l4/exec_region_mapper"); + +l:startv({ + log = L4.Env.log, + caps = { + fsserver = ext2server_paulb, + pipeserver = pipe_server, + prserver = process_server, + }, + }, + -- program, options, operation involving a script file + "rom/fsaccess", "-m", "0022", "script", "-"); diff -r 8aead0ac0492 -r e7c6fdf89706 conf/landfall-examples/mips-jz4780-msc-block.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-jz4780-msc-block.io Sat Apr 27 23:46:28 2024 +0200 @@ -0,0 +1,14 @@ +-- vi:ft=lua +-- configuration file for io + +local hw = Io.system_bus() + +local bus = Io.Vi.System_bus +{ + CPM = wrap(hw:match("jz4780-cpm")); + DMA = wrap(hw:match("jz4780-dma")); + GPIO = wrap(hw:match("jz4780-gpio")); + MSC = wrap(hw:match("jz4780-msc")); +} + +Io.add_vbus("common", bus) diff -r 8aead0ac0492 -r e7c6fdf89706 conf/landfall-examples/mips-jz4780-msc-block.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-jz4780-msc-block.list Sat Apr 27 23:46:28 2024 +0200 @@ -0,0 +1,18 @@ + +modaddr 0x1100000 + +entry mips-jz4780-msc-block +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-jz4780-msc-block.cfg +module mips-jz4780-msc-block.cfg +module mips-jz4780-msc-block.io +module plat-ingenic-jz4780/hw_devices.io +module l4re +module io +module ned +module msc_block_server +module ext2_server +module pipe_server +module process_server +module fsaccess diff -r 8aead0ac0492 -r e7c6fdf89706 conf/landfall-examples/mips-x1600-msc-block.cfg --- a/conf/landfall-examples/mips-x1600-msc-block.cfg Wed Apr 24 00:47:34 2024 +0200 +++ b/conf/landfall-examples/mips-x1600-msc-block.cfg Sat Apr 27 23:46:28 2024 +0200 @@ -31,8 +31,8 @@ }, log = { "server", "r" }, }, - -- arguments: MSC channel/device, DMA channel, card index, memory pages - "rom/msc_block_server", "0", "0", "0", "10"); + -- arguments: machine, MSC channel/device, DMA channel, card index, memory pages + "rom/msc_block_server", "x1600", "0", "0", "0", "10"); local pipe_server = l:new_channel(); diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/cpm/src/jz4730/cpm-jz4730.cc --- a/pkg/devices/cpm/src/jz4730/cpm-jz4730.cc Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/cpm/src/jz4730/cpm-jz4730.cc Sat Apr 27 23:46:28 2024 +0200 @@ -94,7 +94,7 @@ /* Initialise the CPM abstraction. */ - Cpm_jz4730_chip cpm_device(cpm_virt_base, 3686400); + Cpm_jz4730_chip cpm_device(cpm_virt_base); /* Initialise and register a server object. */ diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/include/clocks.h --- a/pkg/devices/include/clocks.h Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/include/clocks.h Sat Apr 27 23:46:28 2024 +0200 @@ -1,7 +1,7 @@ /* * Clock identifiers for clock and power management. * - * Copyright (C) 2021, 2023 Paul Boddie + * Copyright (C) 2021, 2023, 2024 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -41,7 +41,7 @@ Clock_dma, Clock_emac, Clock_external, /* EXCLK */ - Clock_external_div_512, + Clock_external_div, /* EXCLK/128 (JZ4730) or EXCLK/512 (JZ4780) */ Clock_hclock0, /* AHB0 */ Clock_hclock2, /* AHB2 */ Clock_hclock2_pclock, /* AHB2, APB parent clock (JZ4780, X1600) */ @@ -64,6 +64,7 @@ Clock_lcd_pixel1, Clock_mac, Clock_main, /* SCLK_A */ + Clock_mclock, /* EMC and SDRAM parent clock (JZ4730) */ Clock_mipi_csi, Clock_msc, /* MSC parent clock (JZ4780) */ Clock_msc0, @@ -74,6 +75,7 @@ Clock_otg1, Clock_pclock, /* APB */ Clock_pcm, + Clock_pll, Clock_pll_A, Clock_pll_E, Clock_pll_M, diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lcd/src/jz4780/lcd-jz4780-spi-device.cc --- a/pkg/devices/lcd/src/jz4780/lcd-jz4780-spi-device.cc Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lcd/src/jz4780/lcd-jz4780-spi-device.cc Sat Apr 27 23:46:28 2024 +0200 @@ -62,7 +62,7 @@ static Gpio_jz4780_chip *gpio_chip; static Spi_jz4780_chip *spi_chip; -static Dma_jz4780_channel *dma_channel; +static Dma_channel *dma_channel; static Spi_hybrid *spi_channel; static Spi_jz4780_channel *spi_jz4780_channel; diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/cpm/include/cpm-common.h --- a/pkg/devices/lib/cpm/include/cpm-common.h Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/cpm/include/cpm-common.h Sat Apr 27 23:46:28 2024 +0200 @@ -64,6 +64,7 @@ uint8_t bit; bool defined; uint32_t adjustment; + const int *table = NULL; uint32_t _asserted = 0, _deasserted = 0; public: @@ -72,6 +73,16 @@ { } + // Field with table describing the encoded value. + + explicit Field(uint32_t reg, uint32_t mask, uint32_t bit, const int *table) + : reg(reg), mask(mask), bit(bit), defined(true), table(table) + { + _asserted = mask; + } + + // Field with possible inversion and encoded value adjustment. + explicit Field(uint32_t reg, uint32_t mask, uint32_t bit, bool inverted = false, uint32_t adjustment = 0) : reg(reg), mask(mask), bit(bit), defined(true), adjustment(adjustment) diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/cpm/include/cpm-generic.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/cpm/include/cpm-generic.h Sat Apr 27 23:46:28 2024 +0200 @@ -0,0 +1,88 @@ +/* + * Common clock and power management (CPM) abstractions. + * + * Copyright (C) 2017, 2018, 2020, 2021, 2023 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include +#include + + + +#ifdef __cplusplus + +/* A transitional abstraction supporting older CPM abstractions. */ + +class Cpm_chip_base +{ +public: + virtual int have_clock(enum Clock_identifiers clock) = 0; + virtual void start_clock(enum Clock_identifiers clock) = 0; + virtual void stop_clock(enum Clock_identifiers clock) = 0; +}; + +/* A simple abstraction for accessing the CPM registers. */ + +class Cpm_chip : public Cpm_chip_base +{ +protected: + Clock_base **_clocks; + Cpm_regs _cpm_regs; + +public: + explicit Cpm_chip(l4_addr_t addr, Clock_base *clocks[]); + + const char *clock_type(enum Clock_identifiers clock); + + // Clock control. + + int have_clock(enum Clock_identifiers clock); + void start_clock(enum Clock_identifiers clock); + void stop_clock(enum Clock_identifiers clock); + + // Clock dividers. + + int get_parameters(enum Clock_identifiers clock, uint32_t parameters[]); + int set_parameters(enum Clock_identifiers clock, int num_parameters, + uint32_t parameters[]); + + // Clock sources. + + uint8_t get_source(enum Clock_identifiers clock); + void set_source(enum Clock_identifiers clock, uint8_t source); + enum Clock_identifiers get_source_clock(enum Clock_identifiers clock); + void set_source_clock(enum Clock_identifiers clock, enum Clock_identifiers source); + + // Source frequencies. + + uint64_t get_source_frequency(enum Clock_identifiers clock); + + // Output clock frequencies. + + uint64_t get_frequency(enum Clock_identifiers clock); + int set_frequency(enum Clock_identifiers clock, uint64_t frequency); +}; + +/* Generic access to the CPM abstraction. */ + +Cpm_chip *new_cpm_chip(const char *name, l4_addr_t cpm_base); + +#endif /* __cplusplus */ diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/cpm/include/cpm-jz4730.h --- a/pkg/devices/lib/cpm/include/cpm-jz4730.h Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/cpm/include/cpm-jz4730.h Sat Apr 27 23:46:28 2024 +0200 @@ -1,7 +1,8 @@ /* * CPM (clock and power management) support for the JZ4730. * - * Copyright (C) 2017, 2018, 2020, 2021, 2023 Paul Boddie + * Copyright (C) 2017, 2018, 2020, 2021, 2023, + * 2024 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -27,77 +28,39 @@ +/* JZ4730-specific clocks. */ + +enum Clock_jz4730_identifiers +{ + Clock_jz4730_identifier_base = Clock_specific_start, + + /* Actual clocks. */ + + Clock_lcd_pixel_in = Clock_specific_start, + Clock_msc_16MHz, + Clock_msc_24MHz, + Clock_pll_div_2, + Clock_pll_usb, + Clock_usb_phy_48MHz, + + /* Not a clock: limit for array definition. */ + + Clock_jz4730_identifier_count, +}; + + + #ifdef __cplusplus -#include -#include - -/* A simple abstraction for accessing the CPM registers. - * A proper device could inherit from Hw::Device and use an - * Int_property for _exclk_freq. */ - -class Cpm_jz4730_chip : public Cpm_chip_base -{ -private: - Hw::Register_block<32> _regs; - uint32_t _exclk_freq; - - // Utility methods. - - uint8_t _get_divider(uint32_t reg, uint32_t mask, uint8_t shift); - - // PLL status. - - int have_pll(); - int pll_enabled(); - int pll_bypassed(); - - // Clock control. - - uint32_t get_clock_gate_value(enum Clock_identifiers clock); - -public: - Cpm_jz4730_chip(l4_addr_t addr, uint32_t exclk_freq); - - // PLL configuration. +#include - uint16_t get_multiplier(); - uint8_t get_input_division(); - uint8_t get_output_division(); - - // Divider configuration. - - uint8_t get_cpu_divider(); - uint8_t get_hclock_divider(); - uint8_t get_pclock_divider(); - uint8_t get_memory_divider(); - uint8_t get_source_divider(); - uint16_t get_lcd_pixel_divider(); - - void set_lcd_device_divider(uint8_t division); - void set_lcd_pixel_divider(uint16_t division); - - // PLL frequency status. +class Cpm_jz4730_chip : public Cpm_chip +{ +public: + Cpm_jz4730_chip(l4_addr_t addr); +}; - uint32_t get_pll_frequency(); - uint32_t get_source_frequency(); - - // Clock frequency status. - - uint32_t get_cpu_frequency(); - uint32_t get_hclock_frequency(); - uint32_t get_pclock_frequency(); - uint32_t get_memory_frequency(); - - // Clock configuration. - - uint32_t get_frequency(enum Clock_identifiers clock); - void set_frequency(enum Clock_identifiers clock, uint32_t frequency); - - int have_clock(enum Clock_identifiers clock); - void start_clock(enum Clock_identifiers clock); - void stop_clock(enum Clock_identifiers clock); -}; +Cpm_chip *jz4730_cpm_chip(l4_addr_t cpm_base); #endif /* __cplusplus */ @@ -109,21 +72,25 @@ void *jz4730_cpm_init(l4_addr_t cpm_base); -int jz4730_cpm_have_pll(void *cpm); +const char *jz4730_cpm_clock_type(void *cpm, enum Clock_identifiers clock); int jz4730_cpm_have_clock(void *cpm, enum Clock_identifiers clock); void jz4730_cpm_start_clock(void *cpm, enum Clock_identifiers clock); void jz4730_cpm_stop_clock(void *cpm, enum Clock_identifiers clock); -uint16_t jz4730_cpm_get_lcd_pixel_divider(void *cpm); - -uint32_t jz4730_cpm_get_frequency(void *cpm, enum Clock_identifiers clock); -void jz4730_cpm_set_frequency(void *cpm, enum Clock_identifiers clock, uint32_t frequency); +int jz4730_cpm_get_parameters(void *cpm, enum Clock_identifiers clock, + uint32_t parameters[]); +int jz4730_cpm_set_parameters(void *cpm, enum Clock_identifiers clock, + int num_parameters, uint32_t parameters[]); -uint32_t jz4730_cpm_get_cpu_frequency(void *cpm); -uint32_t jz4730_cpm_get_hclock_frequency(void *cpm); -uint32_t jz4730_cpm_get_source_frequency(void *cpm); -uint32_t jz4730_cpm_get_pclock_frequency(void *cpm); -uint32_t jz4730_cpm_get_memory_frequency(void *cpm); +uint8_t jz4730_cpm_get_source(void *cpm, enum Clock_identifiers clock); +void jz4730_cpm_set_source(void *cpm, enum Clock_identifiers clock, uint8_t source); +enum Clock_identifiers jz4730_cpm_get_source_clock(void *cpm, enum Clock_identifiers clock); +void jz4730_cpm_set_source_clock(void *cpm, enum Clock_identifiers clock, enum Clock_identifiers source); + +uint64_t jz4730_cpm_get_source_frequency(void *cpm, enum Clock_identifiers clock); + +uint64_t jz4730_cpm_get_frequency(void *cpm, enum Clock_identifiers clock); +int jz4730_cpm_set_frequency(void *cpm, enum Clock_identifiers clock, uint64_t frequency); EXTERN_C_END diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/cpm/include/cpm-jz4740.h --- a/pkg/devices/lib/cpm/include/cpm-jz4740.h Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/cpm/include/cpm-jz4740.h Sat Apr 27 23:46:28 2024 +0200 @@ -1,7 +1,8 @@ /* * CPM (clock and power management) support for the JZ4740. * - * Copyright (C) 2017, 2018, 2020, 2021, 2023 Paul Boddie + * Copyright (C) 2017, 2018, 2020, 2021, 2023, + * 2024 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -29,7 +30,7 @@ #ifdef __cplusplus -#include +#include #include /* A simple abstraction for accessing the CPM registers. @@ -100,6 +101,8 @@ }; +// Cpm_chip *jz4740_cpm_chip(l4_addr_t cpm_base); + #endif /* __cplusplus */ diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/cpm/include/cpm-jz4780.h --- a/pkg/devices/lib/cpm/include/cpm-jz4780.h Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/cpm/include/cpm-jz4780.h Sat Apr 27 23:46:28 2024 +0200 @@ -1,7 +1,8 @@ /* * CPM (clock and power management) support for the JZ4780. * - * Copyright (C) 2017, 2018, 2020, 2021, 2023 Paul Boddie + * Copyright (C) 2017, 2018, 2020, 2021, 2023, + * 2024 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -43,7 +44,7 @@ #ifdef __cplusplus -#include +#include class Cpm_jz4780_chip : public Cpm_chip { @@ -51,6 +52,8 @@ explicit Cpm_jz4780_chip(l4_addr_t addr); }; +Cpm_chip *jz4780_cpm_chip(l4_addr_t cpm_base); + #endif /* __cplusplus */ diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/cpm/include/cpm-x1600.h --- a/pkg/devices/lib/cpm/include/cpm-x1600.h Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/cpm/include/cpm-x1600.h Sat Apr 27 23:46:28 2024 +0200 @@ -1,7 +1,8 @@ /* * CPM (clock and power management) support for the X1600. * - * Copyright (C) 2017, 2018, 2020, 2021, 2023 Paul Boddie + * Copyright (C) 2017, 2018, 2020, 2021, 2023, + * 2024 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -40,7 +41,7 @@ #ifdef __cplusplus -#include +#include class Cpm_x1600_chip : public Cpm_chip { @@ -48,6 +49,8 @@ explicit Cpm_x1600_chip(l4_addr_t addr); }; +Cpm_chip *x1600_cpm_chip(l4_addr_t cpm_base); + #endif /* __cplusplus */ diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/cpm/src/Makefile --- a/pkg/devices/lib/cpm/src/Makefile Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/cpm/src/Makefile Sat Apr 27 23:46:28 2024 +0200 @@ -4,7 +4,7 @@ TARGET = libcpm.o.a libcpm.o.so PC_FILENAME := libdrivers-cpm -SRC_CC := chip.cc common.cc jz4730.cc jz4740.cc jz4780.cc x1600.cc +SRC_CC := chip.cc common.cc generic.cc jz4730.cc jz4740.cc jz4780.cc x1600.cc PRIVATE_INCDIR += $(PKGDIR)/lib/cpm/include diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/cpm/src/chip.cc --- a/pkg/devices/lib/cpm/src/chip.cc Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/cpm/src/chip.cc Sat Apr 27 23:46:28 2024 +0200 @@ -1,7 +1,7 @@ /* * Common clock and power management functionality. * - * Copyright (C) 2023 Paul Boddie + * Copyright (C) 2023, 2024 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -19,8 +19,8 @@ * Boston, MA 02110-1301, USA */ -#include "cpm.h" #include "cpm-common.h" +#include "cpm-generic.h" diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/cpm/src/common.cc --- a/pkg/devices/lib/cpm/src/common.cc Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/cpm/src/common.cc Sat Apr 27 23:46:28 2024 +0200 @@ -63,7 +63,15 @@ Field::get_field(Cpm_regs ®s) { if (defined) - return regs.get_field(reg, mask, bit) + adjustment; + { + // With an encoding table, use the encoded value as index to obtain the + // genuine value. + + if (table != NULL) + return table[regs.get_field(reg, mask, bit)]; + else + return regs.get_field(reg, mask, bit) + adjustment; + } else return 0; } @@ -72,7 +80,18 @@ Field::set_field(Cpm_regs ®s, uint32_t value) { if (defined) - regs.set_field(reg, mask, bit, value >= adjustment ? value - adjustment : 0); + { + // With an encoding table, find the index of the presented value. + + if (table != NULL) + { + for (uint32_t i = 0; i < mask; i++) + if (table[i] == value) + regs.set_field(reg, mask, bit, i); + } + else + regs.set_field(reg, mask, bit, value >= adjustment ? value - adjustment : 0); + } } // Undefined field. diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/cpm/src/generic.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/cpm/src/generic.cc Sat Apr 27 23:46:28 2024 +0200 @@ -0,0 +1,57 @@ +/* + * Generic access to clock and power management functionality. + * + * Copyright (C) 2024 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include "cpm-generic.h" + +/* Function declarations reproduced here to avoid clock identifier conflicts in + the chip-specific headers. */ + +// NOTE: To be supported... +//extern Cpm_chip *jz4730_cpm_chip(l4_addr_t); +//extern Cpm_chip *jz4740_cpm_chip(l4_addr_t); +extern Cpm_chip *jz4780_cpm_chip(l4_addr_t); +extern Cpm_chip *x1600_cpm_chip(l4_addr_t); + +struct cpm_function +{ + const char *name; + Cpm_chip *(*function)(l4_addr_t); +}; + +static struct cpm_function functions[] = { + //{"jz4730", jz4730_cpm_chip}, + //{"jz4740", jz4740_cpm_chip}, + {"jz4780", jz4780_cpm_chip}, + {"x1600", x1600_cpm_chip}, + {NULL, NULL} +}; + +Cpm_chip *new_cpm_chip(const char *name, l4_addr_t cpm_base) +{ + for (struct cpm_function *f = functions; f->name != NULL; f++) + { + if (!strcmp(name, f->name)) + return f->function(cpm_base); + } + + return NULL; +} diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/cpm/src/jz4730.cc --- a/pkg/devices/lib/cpm/src/jz4730.cc Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/cpm/src/jz4730.cc Sat Apr 27 23:46:28 2024 +0200 @@ -3,7 +3,8 @@ * provided by the jz4730. The power management functionality could be exposed * using a separate driver. * - * Copyright (C) 2017, 2018, 2020, 2021, 2023 Paul Boddie + * Copyright (C) 2017, 2018, 2020, 2021, 2023, + * 2024 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -30,456 +31,369 @@ { Clock_control = 0x000, // CFCR (CPCCR in JZ4740) Pll_control = 0x010, // PLCR1 (CPPCR in JZ4740) + Exclk_oscillator = 0x01c, // OCR Clock_gate = 0x020, // MSCR (CLKGR in JZ4740) Sleep_control = 0x024, // SCR Lcd_divider = 0x060, // CFCR2 }; -enum Clock_bits : unsigned -{ - Clock_change_enable = 20, // UPE - Clock_memory_divider = 16, // MFR - Clock_lcd_divider = 12, // LFR - Clock_pclock_divider = 8, // PFR (slow APB peripherals) - Clock_hclock_divider = 4, // SFR (fast AHB peripherals) - Clock_cpu_divider = 0, // IFR -}; + + +// Encoded value tables. + +static const uint32_t dv[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 1, 1, 1, 1, 1, 1}; +static const uint32_t plldv[] = {1, 2, 2, 4}; + + + +// Register field definitions. -enum Pll_bits : unsigned -{ - Pll_multiplier = 23, // PLL1FD - Pll_input_division = 18, // PLL1RD - Pll_output_division = 16, // PLL1OD - Pll_stable = 10, // PLL1S - Pll_bypassed = 9, // PLL1BP - Pll_enabled = 8, // PLL1EN -}; +static Field Clock_source_ssi (Clock_control, 1, 31), // SCS + Clock_source_lcd (Clock_control, 1, 30), // LCS + Clock_source_i2s (Clock_control, 1, 29), // I2CS + Clock_source_usb (Clock_control, 1, 28), // UCS + Clock_source_msc (Clock_control, 1, 24), // MCS + Clock_source_rtc (Exclk_oscillator, 1, 8), // O2SE + + Clock_change_enable (Clock_control, 1, 20), // UPE + + Clock_divider_cpu (Clock_control, 0x0f, 0, dv), // CFR + Clock_divider_hclock (Clock_control, 0x0f, 4, dv), // HFR + Clock_divider_pclock (Clock_control, 0x0f, 8, dv), // PFR + Clock_divider_lcd (Clock_control, 0x0f, 12, false, 1), // LFR + Clock_divider_mclock (Clock_control, 0x0f, 16, dv), // MFR + Clock_divider_usb (Clock_control, 0x07, 25, false, 1), // UFR + Clock_divider_lcd_pixel (Lcd_divider, 0x1ff, 0), // PXFR -enum Clock_gate_bits : unsigned -{ - Clock_gate_uprt = 25, - Clock_gate_udc = 24, - Clock_gate_cim = 23, - Clock_gate_kbc = 22, - Clock_gate_emac = 21, - Clock_gate_uart3 = 20, - Clock_gate_aic_bitclk = 18, - Clock_gate_scc = 14, - Clock_gate_msc = 13, - Clock_gate_ssi = 12, - Clock_gate_pwm1 = 11, - Clock_gate_pwm0 = 10, - Clock_gate_aic_pclk = 9, - Clock_gate_i2c = 8, - Clock_gate_lcd = 7, - Clock_gate_uhc = 6, - Clock_gate_dmac = 5, - Clock_gate_timer = 3, - Clock_gate_uart2 = 2, - Clock_gate_uart1 = 1, - Clock_gate_uart0 = 0, -}; + Clock_gate_uprt (Clock_gate, 1, 25, true), + Clock_gate_udc (Clock_gate, 1, 24, true), + Clock_gate_cim (Clock_gate, 1, 23, true), + Clock_gate_kbc (Clock_gate, 1, 22, true), + Clock_gate_emac (Clock_gate, 1, 21, true), + Clock_gate_uart3 (Clock_gate, 1, 20, true), + Clock_gate_aic_bitclk (Clock_gate, 1, 18, true), + Clock_gate_scc (Clock_gate, 1, 14, true), + Clock_gate_msc (Clock_gate, 1, 13, true), + Clock_gate_ssi (Clock_gate, 1, 12, true), + Clock_gate_pwm1 (Clock_gate, 1, 11, true), + Clock_gate_pwm0 (Clock_gate, 1, 10, true), + Clock_gate_aic_pclk (Clock_gate, 1, 9, true), + Clock_gate_i2c (Clock_gate, 1, 8, true), + Clock_gate_lcd (Clock_gate, 1, 7, true), + Clock_gate_uhc (Clock_gate, 1, 6, true), + Clock_gate_dmac (Clock_gate, 1, 5, true), + Clock_gate_timer (Clock_gate, 1, 3, true), + Clock_gate_uart2 (Clock_gate, 1, 2, true), + Clock_gate_uart1 (Clock_gate, 1, 1, true), + Clock_gate_uart0 (Clock_gate, 1, 0, true), + Clock_gate_sdram (Clock_control, 1, 22), + + Pll_enable (Pll_control, 1, 8), // PLLEN + Pll_stable (Pll_control, 1, 10), // PLLS + Pll_bypass (Pll_control, 1, 9), // PLLBP + + // Multiplier and input divider yield 2-based values. -enum Lcd_divider_bits : unsigned -{ - Lcd_divider_value = 0, // PIXFR (in CFCR2) -}; + Pll_multiplier (Pll_control, 0x1ff, 23, false, 2), // PLLFD + Pll_input_division (Pll_control, 0x1f, 18, false, 2), // PLLRD + Pll_output_division (Pll_control, 0x03, 16, plldv); // PLLOD + + + +// Multiplexer instances. + +#define Clocks(...) ((enum Clock_identifiers []) {__VA_ARGS__}) +#define Specific(CLOCK) ((enum Clock_identifiers) (CLOCK)) + +static Mux mux_external (Clock_external), + + // Clocks being propagated to others. + + mux_core (Clock_pll), + mux_mclock (Clock_mclock), + mux_hclock (Clock_hclock0), + mux_pclock (Clock_pclock), + + // Clock selection. + + mux_i2s (2, Clocks(Clock_pll, Specific(Clock_pll_div_2))), + mux_lcd_pixel (2, Clocks(Clock_lcd_pixel0, Specific(Clock_lcd_pixel_in))), + mux_msc (2, Clocks(Specific(Clock_msc_16MHz), Specific(Clock_msc_24MHz))), + mux_rtc (2, Clocks(Clock_external_div, Clock_rtc_external)), + mux_ssi (2, Clocks(Clock_external, Clock_usb_phy)), + mux_usb (2, Clocks(Specific(Clock_pll_usb), Specific(Clock_usb_phy_48MHz))); -// If implemented as a Hw::Device, various properties would be -// initialised in the constructor and obtained from the device tree -// definitions. +// Clock instances. +// NOTE: Leaving the LCD pixel clock as a null clock. -Cpm_jz4730_chip::Cpm_jz4730_chip(l4_addr_t addr, uint32_t exclk_freq) -: _exclk_freq(exclk_freq) -{ - _regs = new Hw::Mmio_register_block<32>(addr); - - // add_cid("cpm"); - // add_cid("cpm-jz4730"); - // register_property("exclk_freq", &_exclk_freq); -} - -// Clock/timer control. +static Clock_null clock_none, + clock_lcd_pixel_in; -uint32_t -Cpm_jz4730_chip::get_clock_gate_value(enum Clock_identifiers clock) -{ - switch (clock) - { - case Clock_uprt: return (1 << Clock_gate_uprt); - case Clock_udc: return (1 << Clock_gate_udc); - case Clock_cim: return (1 << Clock_gate_cim); - case Clock_kbc: return (1 << Clock_gate_kbc); - case Clock_emac: return (1 << Clock_gate_emac); - case Clock_uart3: return (1 << Clock_gate_uart3); - case Clock_aic_bitclk: return (1 << Clock_gate_aic_bitclk); - case Clock_scc: return (1 << Clock_gate_scc); - case Clock_msc0: return (1 << Clock_gate_msc); - case Clock_ssi: return (1 << Clock_gate_ssi); - case Clock_pwm1: return (1 << Clock_gate_pwm1); - case Clock_pwm0: return (1 << Clock_gate_pwm0); - case Clock_aic_pclk: return (1 << Clock_gate_aic_pclk); - case Clock_i2c0: return (1 << Clock_gate_i2c); - case Clock_lcd: return (1 << Clock_gate_lcd); - case Clock_uhc: return (1 << Clock_gate_uhc); - case Clock_dma: return (1 << Clock_gate_dmac); - case Clock_timer: return (1 << Clock_gate_timer); - case Clock_uart2: return (1 << Clock_gate_uart2); - case Clock_uart1: return (1 << Clock_gate_uart1); - case Clock_uart0: return (1 << Clock_gate_uart0); - default: return 0; - } -} +static Clock_passive clock_external(3686400), + clock_mac(25000000), + clock_msc_16MHz(16000000), + clock_msc_24MHz(24000000), + clock_rtc_external(32768), + clock_usb_phy_48MHz(48000000); -int -Cpm_jz4730_chip::have_clock(enum Clock_identifiers clock) -{ - return !(_regs[Clock_gate] & get_clock_gate_value(clock)); -} +// Note the use of extra parentheses due to the annoying C++ "most vexing parse" +// problem. See: https://en.wikipedia.org/wiki/Most_vexing_parse -void -Cpm_jz4730_chip::start_clock(enum Clock_identifiers clock) -{ - _regs[Clock_gate] = _regs[Clock_gate] & ~get_clock_gate_value(clock); -} - -void -Cpm_jz4730_chip::stop_clock(enum Clock_identifiers clock) -{ - _regs[Clock_gate] = _regs[Clock_gate] | get_clock_gate_value(clock); -} - -// PLL control. - -// Return whether the PLL is stable. - -int -Cpm_jz4730_chip::have_pll() -{ - return _regs[Pll_control] & (1 << Pll_stable); -} +static Clock + clock_aic_bitclk((Source(mux_i2s)), Control(Clock_gate_aic_bitclk)), + clock_aic_pclk((Source(mux_i2s)), Control(Clock_gate_aic_pclk)), + clock_cim((Source(mux_hclock)), Control(Clock_gate_cim)), + clock_dma((Source(mux_external)), Control(Clock_gate_dmac)), + clock_emac((Source(mux_mclock)), Control(Clock_gate_emac)), + clock_i2c0((Source(mux_external)), Control(Clock_gate_i2c)), + clock_kbc((Source(mux_pclock)), Control(Clock_gate_kbc)), + clock_msc0((Source(mux_msc)), Control(Clock_gate_msc)), + clock_pwm0((Source(mux_external)), Control(Clock_gate_pwm0)), + clock_pwm1((Source(mux_external)), Control(Clock_gate_pwm1)), + clock_rtc((Source(mux_rtc))), + clock_scc((Source(mux_external)), Control(Clock_gate_scc)), + clock_sdram((Source(mux_mclock)), Control(Clock_gate_sdram)), + clock_ssi0((Source(mux_ssi)), Control(Clock_gate_ssi)), -int -Cpm_jz4730_chip::pll_enabled() -{ - return _regs[Pll_control] & (1 << Pll_enabled); -} - -int -Cpm_jz4730_chip::pll_bypassed() -{ - return _regs[Pll_control] & (1 << Pll_bypassed); -} - -// Feedback (9-bit) multiplier. - -uint16_t -Cpm_jz4730_chip::get_multiplier() -{ - return ((_regs[Pll_control] & (0x1ff << Pll_multiplier)) >> Pll_multiplier) + 2; -} - -// Input (5-bit) divider. - -uint8_t -Cpm_jz4730_chip::get_input_division() -{ - return ((_regs[Pll_control] & (0x1f << Pll_input_division)) >> Pll_input_division) + 2; -} - -// Output divider. - -static uint8_t od[4] = {1, 2, 2, 4}; + // Timer propagates pclock but OST may select external + // or rtc instead. -uint8_t -Cpm_jz4730_chip::get_output_division() -{ - return od[(_regs[Pll_control] & (0x03 << Pll_output_division)) >> Pll_output_division]; -} - -// General clock divider. - -static uint8_t cd[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; - -uint8_t -Cpm_jz4730_chip::_get_divider(uint32_t reg, uint32_t mask, uint8_t shift) -{ - uint8_t d = (_regs[reg] & mask) >> shift; - return (d < 10) ? cd[d] : 1; -} - -// CPU clock (CCLK) divider. - -uint8_t -Cpm_jz4730_chip::get_cpu_divider() -{ - return _get_divider(Clock_control, 0xf << Clock_cpu_divider, Clock_cpu_divider); -} - -// Fast peripheral clock (HCLK) divider. - -uint8_t -Cpm_jz4730_chip::get_hclock_divider() -{ - return _get_divider(Clock_control, 0xf << Clock_hclock_divider, Clock_hclock_divider); -} - -// Slow peripheral clock (PCLK) divider. - -uint8_t -Cpm_jz4730_chip::get_pclock_divider() -{ - return _get_divider(Clock_control, 0xf << Clock_pclock_divider, Clock_pclock_divider); -} - -// Memory clock (MCLK) divider. - -uint8_t -Cpm_jz4730_chip::get_memory_divider() -{ - return _get_divider(Clock_control, 0xf << Clock_memory_divider, Clock_memory_divider); -} - -// Clock source divider for MSC, I2S, LCD and USB. + clock_timer((Source(mux_pclock)), Control(Clock_gate_timer)), + clock_uart0((Source(mux_external)), Control(Clock_gate_uart0)), + clock_uart1((Source(mux_external)), Control(Clock_gate_uart1)), + clock_uart2((Source(mux_external)), Control(Clock_gate_uart2)), + clock_uart3((Source(mux_external)), Control(Clock_gate_uart3)), + clock_udc((Source(mux_usb)), Control(Clock_gate_udc)), + clock_uhc((Source(mux_usb)), Control(Clock_gate_uhc)), + clock_uprt((Source(mux_external)), Control(Clock_gate_uprt)), + clock_usb_phy((Source(mux_usb))); -uint8_t -Cpm_jz4730_chip::get_source_divider() -{ - return 1; -} - -// LCD device clock divider. - -void -Cpm_jz4730_chip::set_lcd_device_divider(uint8_t division) -{ - if (division == 0) - division = 1; - - // NOTE: The vendor code (clock.c) bounds the divider at 16, but maybe this is - // NOTE: confused with the width of the bitfield which actually contains an - // NOTE: index for the clock divider value array (cd). - - else if (division > 16) - division = 16; - - // Obtain the divider or closest higher divider. - - int i; - - for (i = 0; i < 10; i++) - if (cd[i] >= division) break; - - _regs[Clock_control] = _regs[Clock_control] | (1 << Clock_change_enable); +static Clock_divided + clock_cpu(Source(mux_core), + Control(Field::undefined, Clock_change_enable), + Divider(Clock_divider_cpu)), + clock_hclock(Source(mux_core), + Control(Field::undefined, Clock_change_enable), + Divider(Clock_divider_hclock)), + clock_lcd(Source(mux_core), + Control(Clock_gate_lcd, Clock_change_enable), + Divider(Clock_divider_lcd)), + clock_lcd_pixel(Source(mux_core), + Control(Field::undefined, Clock_change_enable), + Divider(Clock_divider_lcd_pixel)), + clock_mclock(Source(mux_core), + Control(Field::undefined, Clock_change_enable), + Divider(Clock_divider_mclock)), + clock_pclock(Source(mux_core), + Control(Field::undefined, Clock_change_enable), + Divider(Clock_divider_pclock)), + clock_pll_usb(Source(mux_core), + Control(Field::undefined, Clock_change_enable), + Divider(Clock_divider_usb)); - _regs[Clock_control] = (_regs[Clock_control] & ~(0xf << Clock_lcd_divider)) | - (cd[i] << Clock_lcd_divider); - - _regs[Clock_control] = _regs[Clock_control] & ~(1 << Clock_change_enable); -} - -// LCD pixel clock divider. - -uint16_t -Cpm_jz4730_chip::get_lcd_pixel_divider() -{ - return (_regs[Lcd_divider] >> Lcd_divider_value) + 1; -} +static Clock_divided_fixed + clock_external_div((Source(mux_external)), (Divider_fixed(128))), + clock_pll_div_2((Source(mux_core)), (Divider_fixed(2))); -void -Cpm_jz4730_chip::set_lcd_pixel_divider(uint16_t division) -{ - if (division == 0) - division = 1; - else if (division > 512) - division = 512; +const double jz4730_pll_intermediate_min = 100000000, + jz4730_pll_intermediate_max = 500000000; - _regs[Clock_control] = _regs[Clock_control] | (1 << Clock_change_enable); - - _regs[Lcd_divider] = (_regs[Lcd_divider] & ~(0x1ff << Lcd_divider_value)) | - ((division - 1) << Lcd_divider_value); - - _regs[Clock_control] = _regs[Clock_control] & ~(1 << Clock_change_enable); -} +static Pll clock_pll(Source(mux_external), + Control_pll(Pll_enable, Pll_stable, Pll_bypass), + Divider_pll(Pll_multiplier, Pll_input_division, + Pll_output_division, + jz4730_pll_intermediate_min, jz4730_pll_intermediate_max)); -uint32_t -Cpm_jz4730_chip::get_frequency(enum Clock_identifiers clock) -{ - if (clock == Clock_lcd_pixel0) - return get_source_frequency() / get_lcd_pixel_divider(); +// Clock register. - // NOTE: Consider a better error result. - return 0; -} - -void -Cpm_jz4730_chip::set_frequency(enum Clock_identifiers clock, uint32_t frequency) -{ - uint32_t out = get_source_frequency(); +static Clock_base *clocks[Clock_jz4730_identifier_count] = { + &clock_none, - switch (clock) - { - // Limit the device frequency to 150MHz. + &clock_none, // Clock_aic + &clock_aic_bitclk, + &clock_aic_pclk, + &clock_none, // Clock_can0 + &clock_none, // Clock_can1 + &clock_none, // Clock_cdbus + &clock_cim, + &clock_cpu, + &clock_sdram, // Clock_ddr + &clock_dma, + &clock_emac, + &clock_external, + &clock_external_div, + &clock_hclock, // Clock_hclock0 + &clock_none, // Clock_hclock2 + &clock_none, // Clock_hclock2_pclock + &clock_none, // Clock_hdmi + &clock_i2c0, + &clock_none, // Clock_i2c1 + &clock_none, // Clock_i2c2 + &clock_none, // Clock_i2c3 + &clock_none, // Clock_i2c4 + &clock_none, // Clock_i2s0 + &clock_none, // Clock_i2s0_rx + &clock_none, // Clock_i2s0_tx + &clock_none, // Clock_i2s1 + &clock_none, // Clock_i2s1_rx + &clock_none, // Clock_i2s1_tx + &clock_none, // Clock_kbc + &clock_none, // Clock_l2cache + &clock_lcd, + &clock_lcd_pixel, // Clock_lcd_pixel0 + &clock_none, // Clock_lcd_pixel1 + &clock_mac, + &clock_none, // Clock_main + &clock_none, // Clock_mipi_csi + &clock_none, // Clock_msc + &clock_msc0, + &clock_none, // Clock_msc1 + &clock_none, // Clock_msc2 + &clock_none, // Clock_nemc + &clock_none, // Clock_otg0 + &clock_none, // Clock_otg1 + &clock_pclock, + &clock_none, // Clock_pcm + &clock_pll, + &clock_none, // Clock_pll_A + &clock_none, // Clock_pll_E + &clock_none, // Clock_pll_M + &clock_none, // Clock_pll_V + &clock_pwm0, + &clock_pwm1, + &clock_rtc, + &clock_rtc_external, + &clock_none, // Clock_sadc + &clock_scc, + &clock_none, // Clock_sfc + &clock_none, // Clock_ssi + &clock_ssi0, + &clock_none, // Clock_ssi1 + &clock_none, // Clock_ssi2 + &clock_none, // Clock_timer + &clock_uart0, + &clock_uart1, + &clock_uart2, + &clock_uart3, + &clock_none, // Clock_uart4 + &clock_none, // Clock_udc + &clock_uhc, + &clock_uprt, + &clock_usb_phy, + &clock_none, // Clock_vpu - case Clock_lcd: - if (frequency > 150000000) - frequency = 150000000; - set_lcd_device_divider(out / frequency); - break; + /* JZ4730-specific clocks. */ - case Clock_lcd_pixel0: - set_lcd_pixel_divider(out / frequency); - break; - - default: - break; - } -} + &clock_lcd_pixel_in, + &clock_msc_16MHz, + &clock_msc_24MHz, + &clock_pll_div_2, + &clock_pll_usb, + &clock_usb_phy_48MHz, +}; - -uint32_t -Cpm_jz4730_chip::get_pll_frequency() -{ - // Test for PLL enable and not PLL bypass. +// Peripheral abstraction. - if (pll_enabled() && !pll_bypassed()) - return (_exclk_freq * get_multiplier()) / - (get_input_division() * get_output_division()); - else - return _exclk_freq; +Cpm_jz4730_chip::Cpm_jz4730_chip(l4_addr_t addr) +: Cpm_chip(addr, clocks) +{ } -// Clock frequency for MSC, I2S, LCD and USB. - -uint32_t -Cpm_jz4730_chip::get_source_frequency() -{ - return get_pll_frequency() / get_source_divider(); -} - -// Clock frequency for the CPU. - -uint32_t Cpm_jz4730_chip::get_cpu_frequency() -{ - if (pll_enabled()) - return get_pll_frequency() / get_cpu_divider(); - else - return _exclk_freq; -} - -// Clock frequency for fast peripherals. - -uint32_t -Cpm_jz4730_chip::get_hclock_frequency() +Cpm_chip * +jz4730_cpm_chip(l4_addr_t cpm_base) { - if (pll_enabled()) - return get_pll_frequency() / get_hclock_divider(); - else - return _exclk_freq; -} - -// Clock frequency for slow peripherals. - -uint32_t -Cpm_jz4730_chip::get_pclock_frequency() -{ - if (pll_enabled()) - return get_pll_frequency() / get_pclock_divider(); - else - return _exclk_freq; -} - -// Clock frequency for the memory. - -uint32_t -Cpm_jz4730_chip::get_memory_frequency() -{ - if (pll_enabled()) - return get_pll_frequency() / get_memory_divider(); - else - return _exclk_freq; + return new Cpm_jz4730_chip(cpm_base); } // C language interface functions. -void -*jz4730_cpm_init(l4_addr_t cpm_base) +void * +jz4730_cpm_init(l4_addr_t cpm_base) { - /* Initialise the clock and power management peripheral with the - register memory region and a 3.6864 MHz EXCLK frequency. */ + return (void *) jz4730_cpm_chip(cpm_base); +} - return (void *) new Cpm_jz4730_chip(cpm_base, 3686400); +const char * +jz4730_cpm_clock_type(void *cpm, enum Clock_identifiers clock) +{ + return static_cast(cpm)->clock_type(clock); } int jz4730_cpm_have_clock(void *cpm, enum Clock_identifiers clock) { - return static_cast(cpm)->have_clock(clock); + return static_cast(cpm)->have_clock(clock); } void jz4730_cpm_start_clock(void *cpm, enum Clock_identifiers clock) { - static_cast(cpm)->start_clock(clock); + static_cast(cpm)->start_clock(clock); } void jz4730_cpm_stop_clock(void *cpm, enum Clock_identifiers clock) { - static_cast(cpm)->stop_clock(clock); -} - -uint32_t -jz4730_cpm_get_cpu_frequency(void *cpm) -{ - return static_cast(cpm)->get_cpu_frequency(); + static_cast(cpm)->stop_clock(clock); } -uint32_t -jz4730_cpm_get_hclock_frequency(void *cpm) -{ - return static_cast(cpm)->get_hclock_frequency(); -} - -uint32_t -jz4730_cpm_get_source_frequency(void *cpm) -{ - return static_cast(cpm)->get_source_frequency(); +int +jz4730_cpm_get_parameters(void *cpm, enum Clock_identifiers clock, uint32_t parameters[]) +{ + return static_cast(cpm)->get_parameters(clock, parameters); } -uint32_t -jz4730_cpm_get_pclock_frequency(void *cpm) -{ - return static_cast(cpm)->get_pclock_frequency(); +int +jz4730_cpm_set_parameters(void *cpm, enum Clock_identifiers clock, int num_parameters, uint32_t parameters[]) +{ + return static_cast(cpm)->set_parameters(clock, num_parameters, parameters); } -uint32_t -jz4730_cpm_get_memory_frequency(void *cpm) -{ - return static_cast(cpm)->get_memory_frequency(); -} - -uint16_t -jz4730_cpm_get_lcd_pixel_divider(void *cpm) -{ - return static_cast(cpm)->get_lcd_pixel_divider(); -} - -uint32_t -jz4730_cpm_get_frequency(void *cpm, enum Clock_identifiers clock) -{ - return static_cast(cpm)->get_frequency(clock); +uint8_t +jz4730_cpm_get_source(void *cpm, enum Clock_identifiers clock) +{ + return static_cast(cpm)->get_source(clock); } void -jz4730_cpm_set_frequency(void *cpm, enum Clock_identifiers clock, uint32_t frequency) +jz4730_cpm_set_source(void *cpm, enum Clock_identifiers clock, uint8_t source) +{ + static_cast(cpm)->set_source(clock, source); +} + +enum Clock_identifiers +jz4730_cpm_get_source_clock(void *cpm, enum Clock_identifiers clock) +{ + return static_cast(cpm)->get_source_clock(clock); +} + +void +jz4730_cpm_set_source_clock(void *cpm, enum Clock_identifiers clock, enum Clock_identifiers source) +{ + static_cast(cpm)->set_source_clock(clock, source); +} + +uint64_t +jz4730_cpm_get_source_frequency(void *cpm, enum Clock_identifiers clock) +{ + return static_cast(cpm)->get_source_frequency(clock); +} + +uint64_t +jz4730_cpm_get_frequency(void *cpm, enum Clock_identifiers clock) +{ + return static_cast(cpm)->get_frequency(clock); +} + +int +jz4730_cpm_set_frequency(void *cpm, enum Clock_identifiers clock, uint64_t frequency) { - static_cast(cpm)->set_frequency(clock, frequency); + return static_cast(cpm)->set_frequency(clock, frequency); } diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/cpm/src/jz4740.cc --- a/pkg/devices/lib/cpm/src/jz4740.cc Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/cpm/src/jz4740.cc Sat Apr 27 23:46:28 2024 +0200 @@ -3,7 +3,7 @@ * provided by the jz4740 and related SoCs. The power management * functionality could be exposed using a separate driver. * - * Copyright (C) 2017, 2018, 2021, 2023 Paul Boddie + * Copyright (C) 2017, 2018, 2021, 2023, 2024 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -347,15 +347,25 @@ return get_pll_frequency() / get_memory_divider(); } +#if 0 +Cpm_chip * +jz4740_cpm_chip(l4_addr_t cpm_base) +{ + /* Initialise the clock and power management peripheral with the + register memory region and a 12MHz EXCLK frequency. */ + + return new Cpm_jz4740_chip(cpm_base, 12000000); +} +#endif + // C language interface functions. -void -*jz4740_cpm_init(l4_addr_t cpm_base) +void * +jz4740_cpm_init(l4_addr_t cpm_base) { - /* Initialise the clock and power management peripheral with the - register memory region and a 12MHz EXCLK frequency. */ + // NOTE: To call jz4740_cpm_chip instead. return (void *) new Cpm_jz4740_chip(cpm_base, 12000000); } diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/cpm/src/jz4780.cc --- a/pkg/devices/lib/cpm/src/jz4780.cc Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/cpm/src/jz4780.cc Sat Apr 27 23:46:28 2024 +0200 @@ -451,7 +451,7 @@ Divider(Clock_divider_vpu)); static Clock_divided_fixed - clock_external_div_512((Source(mux_external)), (Divider_fixed(512))); + clock_external_div((Source(mux_external)), (Divider_fixed(512))); const double jz4780_pll_intermediate_min = 300000000, jz4780_pll_intermediate_max = 1500000000; @@ -499,7 +499,7 @@ &clock_dma, &clock_none, // Clock_emac &clock_external, - &clock_external_div_512, + &clock_external_div, &clock_hclock0, &clock_hclock2, &clock_hclock2_pclock, @@ -522,6 +522,7 @@ &clock_lcd_pixel1, &clock_mac, &clock_main, + &clock_none, // Clock_mclock &clock_none, // Clock_mipi_csi &clock_msc, &clock_msc0, @@ -532,13 +533,14 @@ &clock_otg1, &clock_pclock, &clock_pcm, + &clock_none, // Clock_pll &clock_pll_A, &clock_pll_E, &clock_pll_M, &clock_pll_V, &clock_none, // Clock_pwm0 &clock_none, // Clock_pwm1 - &clock_external_div_512,// Clock_rtc + &clock_external_div, // Clock_rtc &clock_rtc_external, &clock_sadc, &clock_scc, @@ -576,90 +578,96 @@ { } +Cpm_chip * +jz4780_cpm_chip(l4_addr_t cpm_base) +{ + return new Cpm_jz4780_chip(cpm_base); +} + // C language interface functions. -void -*jz4780_cpm_init(l4_addr_t cpm_base) +void * +jz4780_cpm_init(l4_addr_t cpm_base) { - return (void *) new Cpm_jz4780_chip(cpm_base); + return (void *) jz4780_cpm_chip(cpm_base); } const char * jz4780_cpm_clock_type(void *cpm, enum Clock_identifiers clock) { - return static_cast(cpm)->clock_type(clock); + return static_cast(cpm)->clock_type(clock); } int jz4780_cpm_have_clock(void *cpm, enum Clock_identifiers clock) { - return static_cast(cpm)->have_clock(clock); + return static_cast(cpm)->have_clock(clock); } void jz4780_cpm_start_clock(void *cpm, enum Clock_identifiers clock) { - static_cast(cpm)->start_clock(clock); + static_cast(cpm)->start_clock(clock); } void jz4780_cpm_stop_clock(void *cpm, enum Clock_identifiers clock) { - static_cast(cpm)->stop_clock(clock); + static_cast(cpm)->stop_clock(clock); } int jz4780_cpm_get_parameters(void *cpm, enum Clock_identifiers clock, uint32_t parameters[]) { - return static_cast(cpm)->get_parameters(clock, parameters); + return static_cast(cpm)->get_parameters(clock, parameters); } int jz4780_cpm_set_parameters(void *cpm, enum Clock_identifiers clock, int num_parameters, uint32_t parameters[]) { - return static_cast(cpm)->set_parameters(clock, num_parameters, parameters); + return static_cast(cpm)->set_parameters(clock, num_parameters, parameters); } uint8_t jz4780_cpm_get_source(void *cpm, enum Clock_identifiers clock) { - return static_cast(cpm)->get_source(clock); + return static_cast(cpm)->get_source(clock); } void jz4780_cpm_set_source(void *cpm, enum Clock_identifiers clock, uint8_t source) { - static_cast(cpm)->set_source(clock, source); + static_cast(cpm)->set_source(clock, source); } enum Clock_identifiers jz4780_cpm_get_source_clock(void *cpm, enum Clock_identifiers clock) { - return static_cast(cpm)->get_source_clock(clock); + return static_cast(cpm)->get_source_clock(clock); } void jz4780_cpm_set_source_clock(void *cpm, enum Clock_identifiers clock, enum Clock_identifiers source) { - static_cast(cpm)->set_source_clock(clock, source); + static_cast(cpm)->set_source_clock(clock, source); } uint64_t jz4780_cpm_get_source_frequency(void *cpm, enum Clock_identifiers clock) { - return static_cast(cpm)->get_source_frequency(clock); + return static_cast(cpm)->get_source_frequency(clock); } uint64_t jz4780_cpm_get_frequency(void *cpm, enum Clock_identifiers clock) { - return static_cast(cpm)->get_frequency(clock); + return static_cast(cpm)->get_frequency(clock); } int jz4780_cpm_set_frequency(void *cpm, enum Clock_identifiers clock, uint64_t frequency) { - return static_cast(cpm)->set_frequency(clock, frequency); + return static_cast(cpm)->set_frequency(clock, frequency); } diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/cpm/src/x1600.cc --- a/pkg/devices/lib/cpm/src/x1600.cc Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/cpm/src/x1600.cc Sat Apr 27 23:46:28 2024 +0200 @@ -273,7 +273,7 @@ mux_dev (3, Clocks(Clock_main, Clock_pll_M, Clock_pll_E)), mux_main (3, Clocks(Clock_none, Clock_external, Clock_pll_A)), mux_i2s (2, Clocks(Clock_main, Clock_pll_E)), - mux_rtc (2, Clocks(Clock_external_div_512, Clock_rtc_external)); + mux_rtc (2, Clocks(Clock_external_div, Clock_rtc_external)); @@ -410,7 +410,7 @@ Divider(Clock_divider_ssi)); static Clock_divided_fixed - clock_external_div_512((Source(mux_external)), (Divider_fixed(512))); + clock_external_div((Source(mux_external)), (Divider_fixed(512))); static Clock_divided_i2s clock_i2s0_rx(Source(mux_i2s0_rx), @@ -465,7 +465,7 @@ &clock_dma, &clock_none, // Clock_emac &clock_external, - &clock_external_div_512, + &clock_external_div, &clock_hclock0, &clock_hclock2, &clock_hclock2_pclock, @@ -488,6 +488,7 @@ &clock_none, // Clock_lcd_pixel1 &clock_mac, &clock_main, + &clock_none, // Clock_mclock &clock_mipi_csi, &clock_none, // Clock_msc &clock_msc0, @@ -498,6 +499,7 @@ &clock_none, // Clock_otg1 &clock_pclock, &clock_none, // Clock_pcm + &clock_none, // Clock_pll &clock_pll_A, &clock_pll_E, &clock_pll_M, @@ -539,6 +541,12 @@ { } +Cpm_chip * +x1600_cpm_chip(l4_addr_t cpm_base) +{ + return new Cpm_x1600_chip(cpm_base); +} + // C language interface functions. @@ -552,77 +560,77 @@ const char * x1600_cpm_clock_type(void *cpm, enum Clock_identifiers clock) { - return static_cast(cpm)->clock_type(clock); + return static_cast(cpm)->clock_type(clock); } int x1600_cpm_have_clock(void *cpm, enum Clock_identifiers clock) { - return static_cast(cpm)->have_clock(clock); + return static_cast(cpm)->have_clock(clock); } void x1600_cpm_start_clock(void *cpm, enum Clock_identifiers clock) { - static_cast(cpm)->start_clock(clock); + static_cast(cpm)->start_clock(clock); } void x1600_cpm_stop_clock(void *cpm, enum Clock_identifiers clock) { - static_cast(cpm)->stop_clock(clock); + static_cast(cpm)->stop_clock(clock); } int x1600_cpm_get_parameters(void *cpm, enum Clock_identifiers clock, uint32_t parameters[]) { - return static_cast(cpm)->get_parameters(clock, parameters); + return static_cast(cpm)->get_parameters(clock, parameters); } int x1600_cpm_set_parameters(void *cpm, enum Clock_identifiers clock, int num_parameters, uint32_t parameters[]) { - return static_cast(cpm)->set_parameters(clock, num_parameters, parameters); + return static_cast(cpm)->set_parameters(clock, num_parameters, parameters); } uint8_t x1600_cpm_get_source(void *cpm, enum Clock_identifiers clock) { - return static_cast(cpm)->get_source(clock); + return static_cast(cpm)->get_source(clock); } void x1600_cpm_set_source(void *cpm, enum Clock_identifiers clock, uint8_t source) { - static_cast(cpm)->set_source(clock, source); + static_cast(cpm)->set_source(clock, source); } enum Clock_identifiers x1600_cpm_get_source_clock(void *cpm, enum Clock_identifiers clock) { - return static_cast(cpm)->get_source_clock(clock); + return static_cast(cpm)->get_source_clock(clock); } void x1600_cpm_set_source_clock(void *cpm, enum Clock_identifiers clock, enum Clock_identifiers source) { - static_cast(cpm)->set_source_clock(clock, source); + static_cast(cpm)->set_source_clock(clock, source); } uint64_t x1600_cpm_get_source_frequency(void *cpm, enum Clock_identifiers clock) { - return static_cast(cpm)->get_source_frequency(clock); + return static_cast(cpm)->get_source_frequency(clock); } uint64_t x1600_cpm_get_frequency(void *cpm, enum Clock_identifiers clock) { - return static_cast(cpm)->get_frequency(clock); + return static_cast(cpm)->get_frequency(clock); } int x1600_cpm_set_frequency(void *cpm, enum Clock_identifiers clock, uint64_t frequency) { - return static_cast(cpm)->set_frequency(clock, frequency); + return static_cast(cpm)->set_frequency(clock, frequency); } diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/dma/include/dma-generic.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/dma/include/dma-generic.h Sat Apr 27 23:46:28 2024 +0200 @@ -0,0 +1,91 @@ +/* + * Generic DMA support. + * + * Copyright (C) 2024 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include + + + +#ifdef __cplusplus + +#include +#include + +// DMA channel. + +class Dma_channel +{ +public: + virtual unsigned int transfer(uint32_t source, uint32_t destination, + unsigned int count, + bool source_increment, bool destination_increment, + uint8_t source_width, uint8_t destination_width, + uint8_t transfer_unit_size, + int type, + l4_addr_t desc_vaddr = 0, + l4re_dma_space_dma_addr_t desc_paddr = 0) = 0; + + virtual unsigned int wait() = 0; +}; + +// DMA device control. + +class Dma_chip +{ +public: + virtual void disable() = 0; + + virtual void enable() = 0; + + virtual Dma_channel *get_channel(uint8_t channel, l4_cap_idx_t irq) = 0; + + // Transaction control. + + virtual void ack_irq(uint8_t channel) + { + (void) channel; + } + + virtual bool error() + { + return false; + } + + virtual bool halted() + { + return false; + } + + virtual void commit_descriptor(uint8_t channel) + { + (void) channel; + } + + virtual bool have_interrupt(uint8_t channel) = 0; +}; + +// Generic access to the DMA abstraction. + +Dma_chip *new_dma_chip(const char *name, l4_addr_t start, l4_addr_t end, Cpm_chip *cpm); + +#endif /* __cplusplus */ diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/dma/include/dma-jz4730.h --- a/pkg/devices/lib/dma/include/dma-jz4730.h Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/dma/include/dma-jz4730.h Sat Apr 27 23:46:28 2024 +0200 @@ -1,7 +1,7 @@ /* * DMA support for the JZ4730. * - * Copyright (C) 2021, 2023 Paul Boddie + * Copyright (C) 2021, 2023, 2024 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -77,7 +77,7 @@ #ifdef __cplusplus -#include +#include #include // Forward declaration. @@ -88,11 +88,11 @@ // DMA channel. -class Dma_jz4730_channel +class Dma_jz4730_channel : public Dma_channel { private: Hw::Register_block<32> _regs; - Dma_jz4730_chip *_chip; + Dma_chip *_chip; uint8_t _channel; l4_cap_idx_t _irq = L4_INVALID_CAP; @@ -104,14 +104,16 @@ enum Dma_jz4730_ext_req_detect_mode _ext_req_detect_mode = Dma_ext_req_detect_mode_high_level; public: - Dma_jz4730_channel(Dma_jz4730_chip *chip, uint8_t channel, l4_addr_t start, l4_cap_idx_t irq); + Dma_jz4730_channel(Dma_chip *chip, uint8_t channel, l4_addr_t start, l4_cap_idx_t irq); unsigned int transfer(uint32_t source, uint32_t destination, unsigned int count, bool source_increment, bool destination_increment, uint8_t source_width, uint8_t destination_width, uint8_t transfer_unit_size, - enum Dma_jz4730_request_type type=Dma_request_auto); + int type=Dma_request_auto, + l4_addr_t desc_vaddr = 0, + l4re_dma_space_dma_addr_t desc_paddr = 0); unsigned int wait(); @@ -159,25 +161,27 @@ // DMA device control. -class Dma_jz4730_chip +class Dma_jz4730_chip : public Dma_chip { private: Hw::Register_block<32> _regs; l4_addr_t _start, _end; - Cpm_jz4730_chip *_cpm; + Cpm_chip *_cpm; public: - Dma_jz4730_chip(l4_addr_t start, l4_addr_t end, Cpm_jz4730_chip *cpm); + Dma_jz4730_chip(l4_addr_t start, l4_addr_t end, Cpm_chip *cpm); void disable(); void enable(); - Dma_jz4730_channel *get_channel(uint8_t channel, l4_cap_idx_t irq); + Dma_channel *get_channel(uint8_t channel, l4_cap_idx_t irq); bool have_interrupt(uint8_t channel); }; +Dma_chip *jz4730_dma_chip(l4_addr_t start, l4_addr_t end, Cpm_chip *cpm); + #endif /* __cplusplus */ diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/dma/include/dma-jz4780.h --- a/pkg/devices/lib/dma/include/dma-jz4780.h Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/dma/include/dma-jz4780.h Sat Apr 27 23:46:28 2024 +0200 @@ -21,7 +21,6 @@ #pragma once -#include #include #include @@ -85,7 +84,7 @@ #ifdef __cplusplus -#include +#include #include // Forward declaration. @@ -96,16 +95,16 @@ // DMA channel. -class Dma_jz4780_channel +class Dma_jz4780_channel : public Dma_channel { private: Hw::Register_block<32> _regs; - Dma_jz4780_chip *_chip; + Dma_chip *_chip; uint8_t _channel; l4_cap_idx_t _irq = L4_INVALID_CAP; public: - Dma_jz4780_channel(Dma_jz4780_chip *chip, uint8_t channel, l4_addr_t start, + Dma_jz4780_channel(Dma_chip *chip, uint8_t channel, l4_addr_t start, l4_cap_idx_t irq = L4_INVALID_CAP); unsigned int transfer(uint32_t source, uint32_t destination, @@ -113,7 +112,7 @@ bool source_increment, bool destination_increment, uint8_t source_width, uint8_t destination_width, uint8_t transfer_unit_size, - enum Dma_jz4780_request_type type=Dma_request_auto, + int type=Dma_request_auto, l4_addr_t desc_vaddr = 0, l4re_dma_space_dma_addr_t desc_paddr = 0); @@ -147,21 +146,21 @@ // DMA device control. -class Dma_jz4780_chip +class Dma_jz4780_chip : public Dma_chip { private: Hw::Register_block<32> _regs; l4_addr_t _start, _end; - Cpm_jz4780_chip *_cpm; + Cpm_chip *_cpm; public: - Dma_jz4780_chip(l4_addr_t start, l4_addr_t end, Cpm_jz4780_chip *cpm); + Dma_jz4780_chip(l4_addr_t start, l4_addr_t end, Cpm_chip *cpm); void disable(); void enable(); - Dma_jz4780_channel *get_channel(uint8_t channel, + Dma_channel *get_channel(uint8_t channel, l4_cap_idx_t irq = L4_INVALID_CAP); // Transaction control. @@ -179,6 +178,8 @@ void commit_descriptor(uint8_t channel); }; +Dma_chip *jz4780_dma_chip(l4_addr_t start, l4_addr_t end, Cpm_chip *cpm); + #endif /* __cplusplus */ diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/dma/include/dma-x1600.h --- a/pkg/devices/lib/dma/include/dma-x1600.h Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/dma/include/dma-x1600.h Sat Apr 27 23:46:28 2024 +0200 @@ -69,11 +69,19 @@ Dma_request_aic_in = 63, }; +/* Descriptor structure. */ + +struct x1600_dma_descriptor +{ + uint32_t command, source, destination, transfer_count, + stride, request_source, reserved0, reserved1; +}; + #ifdef __cplusplus -#include +#include #include // Forward declaration. @@ -84,23 +92,25 @@ // DMA channel. -class Dma_x1600_channel +class Dma_x1600_channel : public Dma_channel { private: Hw::Register_block<32> _regs; - Dma_x1600_chip *_chip; + Dma_chip *_chip; uint8_t _channel; l4_cap_idx_t _irq = L4_INVALID_CAP; public: - Dma_x1600_channel(Dma_x1600_chip *chip, uint8_t channel, l4_addr_t start, l4_cap_idx_t irq); + Dma_x1600_channel(Dma_chip *chip, uint8_t channel, l4_addr_t start, l4_cap_idx_t irq); unsigned int transfer(uint32_t source, uint32_t destination, unsigned int count, bool source_increment, bool destination_increment, uint8_t source_width, uint8_t destination_width, uint8_t transfer_unit_size, - enum Dma_x1600_request_type type=Dma_request_auto); + int type=Dma_request_auto, + l4_addr_t desc_vaddr = 0, + l4re_dma_space_dma_addr_t desc_paddr = 0); unsigned int wait(); @@ -132,21 +142,21 @@ // DMA device control. -class Dma_x1600_chip +class Dma_x1600_chip : public Dma_chip { private: Hw::Register_block<32> _regs; l4_addr_t _start, _end; - Cpm_x1600_chip *_cpm; + Cpm_chip *_cpm; public: - Dma_x1600_chip(l4_addr_t start, l4_addr_t end, Cpm_x1600_chip *cpm); + Dma_x1600_chip(l4_addr_t start, l4_addr_t end, Cpm_chip *cpm); void disable(); void enable(); - Dma_x1600_channel *get_channel(uint8_t channel, l4_cap_idx_t irq); + Dma_channel *get_channel(uint8_t channel, l4_cap_idx_t irq); // Transaction control. @@ -157,8 +167,14 @@ bool halted(); bool have_interrupt(uint8_t channel); + + // Descriptor operations. + + void commit_descriptor(uint8_t channel); }; +Dma_chip *x1600_dma_chip(l4_addr_t start, l4_addr_t end, Cpm_chip *cpm); + #endif /* __cplusplus */ diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/dma/src/Makefile --- a/pkg/devices/lib/dma/src/Makefile Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/dma/src/Makefile Sat Apr 27 23:46:28 2024 +0200 @@ -4,7 +4,7 @@ TARGET = libdma.o.a libdma.o.so PC_FILENAME := libdrivers-dma -SRC_CC := jz4730.cc jz4780.cc x1600.cc +SRC_CC := generic.cc jz4730.cc jz4780.cc x1600.cc PRIVATE_INCDIR += $(PKGDIR)/lib/dma/include diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/dma/src/generic.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/dma/src/generic.cc Sat Apr 27 23:46:28 2024 +0200 @@ -0,0 +1,56 @@ +/* + * Generic access to direct memory access functionality. + * + * Copyright (C) 2024 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include "dma-generic.h" + +/* Function declarations reproduced here to avoid clock identifier conflicts in + the chip-specific headers. */ + +extern Dma_chip *jz4730_dma_chip(l4_addr_t, l4_addr_t, Cpm_chip *); +//extern Dma_chip *jz4740_dma_chip(l4_addr_t, l4_addr_t, Cpm_chip *); +extern Dma_chip *jz4780_dma_chip(l4_addr_t, l4_addr_t, Cpm_chip *); +extern Dma_chip *x1600_dma_chip(l4_addr_t, l4_addr_t, Cpm_chip *); + +struct dma_function +{ + const char *name; + Dma_chip *(*function)(l4_addr_t, l4_addr_t, Cpm_chip *); +}; + +static struct dma_function functions[] = { + {"jz4730", jz4730_dma_chip}, + //{"jz4740", jz4740_dma_chip}, + {"jz4780", jz4780_dma_chip}, + {"x1600", x1600_dma_chip}, + {NULL, NULL} +}; + +Dma_chip *new_dma_chip(const char *name, l4_addr_t start, l4_addr_t end, Cpm_chip *cpm) +{ + for (struct dma_function *f = functions; f->name != NULL; f++) + { + if (!strcmp(name, f->name)) + return f->function(start, end, cpm); + } + + return NULL; +} diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/dma/src/jz4730.cc --- a/pkg/devices/lib/dma/src/jz4730.cc Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/dma/src/jz4730.cc Sat Apr 27 23:46:28 2024 +0200 @@ -19,6 +19,7 @@ * Boston, MA 02110-1301, USA */ +#include #include #include @@ -134,7 +135,7 @@ // Initialise a channel. -Dma_jz4730_channel::Dma_jz4730_channel(Dma_jz4730_chip *chip, uint8_t channel, +Dma_jz4730_channel::Dma_jz4730_channel(Dma_chip *chip, uint8_t channel, l4_addr_t start, l4_cap_idx_t irq) : _chip(chip), _channel(channel), _irq(irq) { @@ -239,8 +240,14 @@ bool source_increment, bool destination_increment, uint8_t source_width, uint8_t destination_width, uint8_t transfer_unit_size, - enum Dma_jz4730_request_type type) + int type, + l4_addr_t desc_vaddr, + l4re_dma_space_dma_addr_t desc_paddr) { + // Descriptor-based transfers are not supported. + + (void) desc_vaddr; (void) desc_paddr; + // Ensure an absence of address error and halt conditions globally and in this channel. if (error() || halted()) @@ -281,7 +288,7 @@ * transfer mode (currently left as single) */ - _regs[Dma_control_status] = encode_external_transfer(type) | + _regs[Dma_control_status] = encode_external_transfer((enum Dma_jz4730_request_type) type) | (source_increment ? Dma_source_address_incr : Dma_source_address_no_incr) | (destination_increment ? Dma_dest_address_incr : Dma_dest_address_no_incr) | encode_source_port_width(source_width) | @@ -393,7 +400,7 @@ // Initialise the I2C controller. Dma_jz4730_chip::Dma_jz4730_chip(l4_addr_t start, l4_addr_t end, - Cpm_jz4730_chip *cpm) + Cpm_chip *cpm) : _start(start), _end(end), _cpm(cpm) { _regs = new Hw::Mmio_register_block<32>(start); @@ -426,7 +433,7 @@ // Obtain a channel object. -Dma_jz4730_channel * +Dma_channel * Dma_jz4730_chip::get_channel(uint8_t channel, l4_cap_idx_t irq) { if (channel < 6) @@ -443,28 +450,33 @@ return _regs[Dma_irq_pending] & (1 << (Dma_irq_pending_ch0 - channel)) ? true : false; } +Dma_chip *jz4730_dma_chip(l4_addr_t start, l4_addr_t end, Cpm_chip *cpm) +{ + return new Dma_jz4730_chip(start, end, cpm); +} + // C language interface functions. void *jz4730_dma_init(l4_addr_t start, l4_addr_t end, void *cpm) { - return (void *) new Dma_jz4730_chip(start, end, static_cast(cpm)); + return (void *) jz4730_dma_chip(start, end, static_cast(cpm)); } void jz4730_dma_disable(void *dma_chip) { - static_cast(dma_chip)->disable(); + static_cast(dma_chip)->disable(); } void jz4730_dma_enable(void *dma_chip) { - static_cast(dma_chip)->enable(); + static_cast(dma_chip)->enable(); } void *jz4730_dma_get_channel(void *dma, uint8_t channel, l4_cap_idx_t irq) { - return static_cast(dma)->get_channel(channel, irq); + return static_cast(dma)->get_channel(channel, irq); } void jz4730_dma_set_output_polarity(void *dma_channel, enum Dma_jz4730_ext_level polarity) diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/dma/src/jz4780.cc --- a/pkg/devices/lib/dma/src/jz4780.cc Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/dma/src/jz4780.cc Sat Apr 27 23:46:28 2024 +0200 @@ -20,6 +20,7 @@ * Boston, MA 02110-1301, USA */ +#include #include #include @@ -156,7 +157,7 @@ // Initialise a channel. -Dma_jz4780_channel::Dma_jz4780_channel(Dma_jz4780_chip *chip, uint8_t channel, +Dma_jz4780_channel::Dma_jz4780_channel(Dma_chip *chip, uint8_t channel, l4_addr_t start, l4_cap_idx_t irq) : _chip(chip), _channel(channel), _irq(irq) { @@ -267,7 +268,7 @@ bool source_increment, bool destination_increment, uint8_t source_width, uint8_t destination_width, uint8_t transfer_unit_size, - enum Dma_jz4780_request_type type, + int type, l4_addr_t desc_vaddr, l4re_dma_space_dma_addr_t desc_paddr) { @@ -321,7 +322,7 @@ desc->destination = destination; desc->transfer_count = (units & Dma_transfer_count_mask) | (descriptor_offset << Dma_descriptor_offset_shift); - desc->request_source = type; + desc->request_source = (enum Dma_jz4780_request_type) type; // NOTE: Stride not supported yet. @@ -459,8 +460,7 @@ // Initialise the I2C controller. -Dma_jz4780_chip::Dma_jz4780_chip(l4_addr_t start, l4_addr_t end, - Cpm_jz4780_chip *cpm) +Dma_jz4780_chip::Dma_jz4780_chip(l4_addr_t start, l4_addr_t end, Cpm_chip *cpm) : _start(start), _end(end), _cpm(cpm) { _regs = new Hw::Mmio_register_block<32>(start); @@ -490,7 +490,7 @@ // Obtain a channel object. -Dma_jz4780_channel * +Dma_channel * Dma_jz4780_chip::get_channel(uint8_t channel, l4_cap_idx_t irq) { if (channel < 32) @@ -537,28 +537,33 @@ _regs[Dma_doorbell_set] = (1 << channel); } +Dma_chip *jz4780_dma_chip(l4_addr_t start, l4_addr_t end, Cpm_chip *cpm) +{ + return new Dma_jz4780_chip(start, end, cpm); +} + // C language interface functions. void *jz4780_dma_init(l4_addr_t start, l4_addr_t end, void *cpm) { - return (void *) new Dma_jz4780_chip(start, end, static_cast(cpm)); + return (void *) jz4780_dma_chip(start, end, static_cast(cpm)); } void jz4780_dma_disable(void *dma_chip) { - static_cast(dma_chip)->disable(); + static_cast(dma_chip)->disable(); } void jz4780_dma_enable(void *dma_chip) { - static_cast(dma_chip)->enable(); + static_cast(dma_chip)->enable(); } void *jz4780_dma_get_channel(void *dma, uint8_t channel, l4_cap_idx_t irq) { - return static_cast(dma)->get_channel(channel, irq); + return static_cast(dma)->get_channel(channel, irq); } unsigned int jz4780_dma_transfer(void *dma_channel, diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/dma/src/x1600.cc --- a/pkg/devices/lib/dma/src/x1600.cc Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/dma/src/x1600.cc Sat Apr 27 23:46:28 2024 +0200 @@ -19,9 +19,11 @@ * Boston, MA 02110-1301, USA */ +#include #include #include +#include #include #include #include @@ -37,6 +39,8 @@ { Dma_control = 0x1000, // DMAC Dma_irq_pending = 0x1004, // DIRQP + Dma_doorbell = 0x1008, // DDB + Dma_doorbell_set = 0x100c, // DDS }; enum Channel_regs @@ -65,7 +69,10 @@ enum Dma_transfer_count_bits : unsigned { + Dma_descriptor_offset_mask = 0xff000000, // DOA (in DES3) + Dma_transfer_count_mask = 0x00ffffff, + Dma_descriptor_offset_shift = 24, }; enum Dma_request_source_bits : unsigned @@ -133,8 +140,8 @@ // Initialise a channel. -Dma_x1600_channel::Dma_x1600_channel(Dma_x1600_chip *chip, uint8_t channel, - l4_addr_t start, l4_cap_idx_t irq) +Dma_x1600_channel::Dma_x1600_channel(Dma_chip *chip, uint8_t channel, + l4_addr_t start, l4_cap_idx_t irq) : _chip(chip), _channel(channel), _irq(irq) { _regs = new Hw::Mmio_register_block<32>(start); @@ -245,7 +252,9 @@ bool source_increment, bool destination_increment, uint8_t source_width, uint8_t destination_width, uint8_t transfer_unit_size, - enum Dma_x1600_request_type type) + int type, + l4_addr_t desc_vaddr, + l4re_dma_space_dma_addr_t desc_paddr) { // Ensure an absence of address error and halt conditions globally and in this channel. @@ -261,41 +270,71 @@ _regs[Dma_control_status] = _regs[Dma_control_status] & ~Dma_channel_enable; - // Set addresses. - - _regs[Dma_source] = source; - _regs[Dma_destination] = destination; - // Set transfer count to the number of units. unsigned int units = count < Dma_transfer_count_mask ? count : Dma_transfer_count_mask; - _regs[Dma_transfer_count] = units; + // NOTE: Request detection interval length (for autonomous mode) not considered. - // Set auto-request for memory-to-memory transfers. Otherwise, set the - // indicated request type. + uint32_t command = (source_increment ? Dma_source_address_increment + : Dma_source_address_no_increment) | + (destination_increment ? Dma_destination_address_increment + : Dma_destination_address_no_increment) | + encode_source_port_width(source_width) | + encode_destination_port_width(destination_width) | + encode_transfer_unit_size(transfer_unit_size) | + Dma_transfer_irq_enable; + + // Populate the descriptor, largely corresponding to the population of + // registers when descriptors are not being used. - _regs[Dma_request_source] = type; + if (desc_vaddr) + { + // For a descriptor, the descriptor address would be set and the doorbell + // register field for the channel set. - // For a descriptor, the actual fields would be populated instead of the - // command register, descriptor transfer would be indicated in the control/ - // status register along with the appropriate descriptor size indicator. + // For a descriptor, the actual fields would be populated instead of the + // command register, descriptor transfer would be indicated in the control/ + // status register along with the appropriate descriptor size indicator. + + struct x1600_dma_descriptor *desc = (struct x1600_dma_descriptor *) desc_vaddr; + + // NOTE: Linking to the same descriptor. + + uint32_t descriptor_offset = 0; - /* NOTE: To be considered... - * request detection interval length (for autonomous mode) - */ + desc->command = command | Dma_descriptor_link_enable; + desc->source = source; + desc->destination = destination; + desc->transfer_count = (units & Dma_transfer_count_mask) | + (descriptor_offset << Dma_descriptor_offset_shift); + desc->request_source = (enum Dma_x1600_request_type) type; + + // NOTE: Stride not supported yet. + + l4_cache_clean_data((unsigned long) desc_vaddr, + (unsigned long) desc_vaddr + sizeof(*desc)); + + // Commit the descriptor. - _regs[Dma_command] = (source_increment ? Dma_source_address_increment : Dma_source_address_no_increment) | - (destination_increment ? Dma_destination_address_increment : Dma_destination_address_no_increment) | - encode_source_port_width(source_width) | - encode_destination_port_width(destination_width) | - encode_transfer_unit_size(transfer_unit_size) | - Dma_transfer_irq_enable; + _regs[Dma_descriptor_address] = desc_paddr; + _chip->commit_descriptor(_channel); + } + + // Otherwise, populate the registers for a one-off transfer. - // For a descriptor, the descriptor address would be set and the doorbell - // register field for the channel set. + else + { + // Set addresses and transfer count. - // Enable the channel (and peripheral). + _regs[Dma_source] = source; + _regs[Dma_destination] = destination; + _regs[Dma_transfer_count] = units; + _regs[Dma_request_source] = (enum Dma_x1600_request_type) type; + _regs[Dma_command] = command; + } + + // Enable the channel with descriptor transfer configured if appropriate. _regs[Dma_control_status] = Dma_no_descriptor_transfer | Dma_channel_enable; @@ -398,8 +437,7 @@ // Initialise the I2C controller. -Dma_x1600_chip::Dma_x1600_chip(l4_addr_t start, l4_addr_t end, - Cpm_x1600_chip *cpm) +Dma_x1600_chip::Dma_x1600_chip(l4_addr_t start, l4_addr_t end, Cpm_chip *cpm) : _start(start), _end(end), _cpm(cpm) { _regs = new Hw::Mmio_register_block<32>(start); @@ -429,7 +467,7 @@ // Obtain a channel object. -Dma_x1600_channel * +Dma_channel * Dma_x1600_chip::get_channel(uint8_t channel, l4_cap_idx_t irq) { if (channel < 32) @@ -470,28 +508,39 @@ return _regs[Dma_control] & Dma_control_trans_halted ? true : false; } +void +Dma_x1600_chip::commit_descriptor(uint8_t channel) +{ + _regs[Dma_doorbell_set] = (1 << channel); +} + +Dma_chip *x1600_dma_chip(l4_addr_t start, l4_addr_t end, Cpm_chip *cpm) +{ + return new Dma_x1600_chip(start, end, cpm); +} + // C language interface functions. void *x1600_dma_init(l4_addr_t start, l4_addr_t end, void *cpm) { - return (void *) new Dma_x1600_chip(start, end, static_cast(cpm)); + return (void *) x1600_dma_chip(start, end, static_cast(cpm)); } void x1600_dma_disable(void *dma_chip) { - static_cast(dma_chip)->disable(); + static_cast(dma_chip)->disable(); } void x1600_dma_enable(void *dma_chip) { - static_cast(dma_chip)->enable(); + static_cast(dma_chip)->enable(); } void *x1600_dma_get_channel(void *dma, uint8_t channel, l4_cap_idx_t irq) { - return static_cast(dma)->get_channel(channel, irq); + return static_cast(dma)->get_channel(channel, irq); } unsigned int x1600_dma_transfer(void *dma_channel, diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/i2c/include/i2c-common.h --- a/pkg/devices/lib/i2c/include/i2c-common.h Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/i2c/include/i2c-common.h Sat Apr 27 23:46:28 2024 +0200 @@ -1,7 +1,7 @@ /* * I2C support for the JZ4780 and X1600. * - * Copyright (C) 2017, 2018, 2019, 2023 Paul Boddie + * Copyright (C) 2017, 2018, 2019, 2023, 2024 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -28,7 +28,7 @@ #ifdef __cplusplus -#include +#include #include // I2C channel. diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/msc/include/msc-defs.h --- a/pkg/devices/lib/msc/include/msc-defs.h Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/msc/include/msc-defs.h Sat Apr 27 23:46:28 2024 +0200 @@ -21,7 +21,7 @@ #pragma once -#include +#include diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/msc/include/msc-generic.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/msc/include/msc-generic.h Sat Apr 27 23:46:28 2024 +0200 @@ -0,0 +1,164 @@ +/* + * MSC (MMC/SD controller) peripheral support. + * + * Copyright (C) 2024 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + + + +#ifdef __cplusplus + +#include + + + +// MMC/SD controller channel. + +class Msc_channel +{ +protected: + l4_addr_t _msc_start; + Hw::Register_block<32> _regs; + l4_cap_idx_t _irq; + Cpm_chip *_cpm; + enum Clock_identifiers _clock; + + // Support eight cards. + + struct msc_card _cards[8]; + uint8_t _num_cards; + int _card; + + // Utility methods. + + uint32_t get_field(uint32_t reg, uint32_t mask, uint8_t shift); + void set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value); + + // Low-level operations. + + void ack_irq(uint32_t flags); + void unmask_irq(uint32_t flags); + + virtual void reset(); + + bool set_clock_frequency(uint64_t frequency); + void start_clock(); + void stop_clock(); + + // Hardware properties. + + virtual bool have_dma_enable_in_command(); + virtual bool have_dma_selection(); + + // Command properties. + + bool command_will_write(uint8_t index); + bool command_with_data(uint8_t index); + bool command_uses_busy(uint8_t index); + uint8_t get_response_format(uint8_t index); + + bool app_command_will_write(uint8_t index); + bool app_command_with_data(uint8_t index); + bool app_command_uses_busy(uint8_t index); + uint8_t get_app_response_format(uint8_t index); + + // Command initiation. + + bool send_app_command(uint8_t index, uint32_t arg); + bool send_command(uint8_t index, uint32_t arg); + bool send_command(uint8_t index, uint32_t arg, uint8_t response_format, + bool data, bool write, bool busy); + + // Response handling. + + bool have_response(); + void read_response(uint16_t *buffer, uint8_t units); + bool wait_for_irq(uint32_t flags); + bool wait_for_irq(uint32_t flags, unsigned int timeout); + + // Initialisation operations. + + bool check_sd(); + void init_sdio(); + void init_sdmem(); + void init_mmc(); + void identify_cards(); + void query_cards(); + + // Transfer operations. + + uint32_t recv_data(struct dma_region *region, uint32_t count); + uint32_t send_data(struct dma_region *region, uint32_t count); + + virtual uint32_t transfer(l4re_dma_space_dma_addr_t from_paddr, + l4re_dma_space_dma_addr_t to_paddr, + bool recv, uint32_t count) = 0; + +public: + explicit Msc_channel(l4_addr_t msc_start, l4_addr_t start, l4_cap_idx_t irq, + Cpm_chip *cpm, enum Clock_identifiers clock); + + virtual ~Msc_channel(); + + void enable(); + + msc_card *get_cards(); + + uint8_t num_cards(); + + uint32_t read(uint8_t card, struct dma_region *region, + uint32_t address, uint32_t count); + + uint32_t read_blocks(uint8_t card, struct dma_region *region, + uint32_t block_address, uint32_t block_count); +}; + + + +// MMC/SD controller device control. + +class Msc_chip +{ +protected: + l4_addr_t _msc_start, _start, _end; + Cpm_chip *_cpm; + + virtual unsigned int num_channels() = 0; + +public: + explicit Msc_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, + Cpm_chip *cpm); + + virtual Msc_channel *get_channel(uint8_t channel, l4_cap_idx_t irq, + Dma_channel *dma) = 0; +}; + +Msc_chip *new_msc_chip(const char *name, l4_addr_t msc_start, l4_addr_t start, + l4_addr_t end, Cpm_chip *cpm); + +#endif /* __cplusplus */ diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/msc/include/msc-jz4780.h --- a/pkg/devices/lib/msc/include/msc-jz4780.h Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/msc/include/msc-jz4780.h Sat Apr 27 23:46:28 2024 +0200 @@ -21,7 +21,7 @@ #pragma once -#include +#include #include #include @@ -36,14 +36,14 @@ class Msc_jz4780_channel : public Msc_channel { protected: - Dma_jz4780_channel *_dma; + Dma_channel *_dma; enum Dma_jz4780_request_type _request_type_in, _request_type_out; public: explicit Msc_jz4780_channel(l4_addr_t msc_start, l4_addr_t addr, l4_cap_idx_t irq, Cpm_chip *cpm, enum Clock_identifiers clock, - Dma_jz4780_channel *dma, + Dma_channel *dma, enum Dma_jz4780_request_type request_type_in, enum Dma_jz4780_request_type request_type_out); @@ -76,9 +76,12 @@ Cpm_chip *cpm); Msc_channel *get_channel(uint8_t channel, l4_cap_idx_t irq, - Dma_jz4780_channel *dma); + Dma_channel *dma); }; +Msc_chip *jz4780_msc_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, + Cpm_chip *cpm); + #endif /* __cplusplus */ /* C language interface. */ diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/msc/include/msc-x1600.h --- a/pkg/devices/lib/msc/include/msc-x1600.h Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/msc/include/msc-x1600.h Sat Apr 27 23:46:28 2024 +0200 @@ -21,7 +21,7 @@ #pragma once -#include +#include #include #include @@ -36,7 +36,7 @@ class Msc_x1600_channel : public Msc_channel { protected: - Dma_x1600_channel *_dma; + Dma_channel *_dma; enum Dma_x1600_request_type _request_type_in, _request_type_out; // Special overridden method. @@ -47,7 +47,7 @@ explicit Msc_x1600_channel(l4_addr_t msc_start, l4_addr_t addr, l4_cap_idx_t irq, Cpm_chip *cpm, enum Clock_identifiers clock, - Dma_x1600_channel *dma, + Dma_channel *dma, enum Dma_x1600_request_type request_type_in, enum Dma_x1600_request_type request_type_out); @@ -78,9 +78,12 @@ Cpm_chip *cpm); Msc_channel *get_channel(uint8_t channel, l4_cap_idx_t irq, - Dma_x1600_channel *dma); + Dma_channel *dma); }; +Msc_chip *x1600_msc_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, + Cpm_chip *cpm); + #endif /* __cplusplus */ /* C language interface. */ diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/msc/src/Makefile --- a/pkg/devices/lib/msc/src/Makefile Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/msc/src/Makefile Sat Apr 27 23:46:28 2024 +0200 @@ -4,7 +4,7 @@ TARGET = libmsc.o.a libmsc.o.so PC_FILENAME := libdrivers-msc -SRC_CC := common.cc jz4780.cc x1600.cc +SRC_CC := common.cc generic.cc jz4780.cc x1600.cc PRIVATE_INCDIR += $(PKGDIR)/lib/msc/include diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/msc/src/common.cc --- a/pkg/devices/lib/msc/src/common.cc Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/msc/src/common.cc Sat Apr 27 23:46:28 2024 +0200 @@ -29,8 +29,8 @@ #include #include -#include "msc-common.h" #include "msc-defs.h" +#include "msc-generic.h" diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/msc/src/generic.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/msc/src/generic.cc Sat Apr 27 23:46:28 2024 +0200 @@ -0,0 +1,57 @@ +/* + * Generic access to memory card functionality. + * + * Copyright (C) 2024 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include "msc-generic.h" + +/* Function declarations reproduced here to avoid clock identifier conflicts in + the chip-specific headers. */ + +//extern Msc_chip *jz4730_msc_chip(l4_addr_t, l4_addr_t, l4_addr_t, Cpm_chip *); +//extern Msc_chip *jz4740_msc_chip(l4_addr_t, l4_addr_t, l4_addr_t, Cpm_chip *); +extern Msc_chip *jz4780_msc_chip(l4_addr_t, l4_addr_t, l4_addr_t, Cpm_chip *); +extern Msc_chip *x1600_msc_chip(l4_addr_t, l4_addr_t, l4_addr_t, Cpm_chip *); + +struct msc_function +{ + const char *name; + Msc_chip *(*function)(l4_addr_t, l4_addr_t, l4_addr_t, Cpm_chip *); +}; + +static struct msc_function functions[] = { + //{"jz4730", jz4730_msc_chip}, + //{"jz4740", jz4740_msc_chip}, + {"jz4780", jz4780_msc_chip}, + {"x1600", x1600_msc_chip}, + {NULL, NULL} +}; + +Msc_chip *new_msc_chip(const char *name, l4_addr_t msc_start, l4_addr_t start, + l4_addr_t end, Cpm_chip *cpm) +{ + for (struct msc_function *f = functions; f->name != NULL; f++) + { + if (!strcmp(name, f->name)) + return f->function(msc_start, start, end, cpm); + } + + return NULL; +} diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/msc/src/jz4780.cc --- a/pkg/devices/lib/msc/src/jz4780.cc Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/msc/src/jz4780.cc Sat Apr 27 23:46:28 2024 +0200 @@ -31,7 +31,7 @@ Msc_jz4780_channel::Msc_jz4780_channel(l4_addr_t msc_start, l4_addr_t addr, l4_cap_idx_t irq, Cpm_chip *cpm, enum Clock_identifiers clock, - Dma_jz4780_channel *dma, + Dma_channel *dma, enum Dma_jz4780_request_type request_type_in, enum Dma_jz4780_request_type request_type_out) : Msc_channel(msc_start, addr, irq, cpm, clock), @@ -60,7 +60,7 @@ recv ? false : true, // increment source if sending recv ? true : false, // increment destination if receiving 4, 4, unit_size, - recv ? _request_type_in : _request_type_out); + (int) (recv ? _request_type_in : _request_type_out)); return to_transfer * unit_size; } @@ -76,7 +76,7 @@ } Msc_channel *Msc_jz4780_chip::get_channel(uint8_t channel, l4_cap_idx_t irq, - Dma_jz4780_channel *dma) + Dma_channel *dma) { if (channel < num_channels()) return new Msc_jz4780_channel(_msc_start + channel * Msc_channel_offset, @@ -87,6 +87,12 @@ throw -L4_EINVAL; } +Msc_chip *jz4780_msc_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, + Cpm_chip *cpm) +{ + return new Msc_jz4780_chip(msc_start, start, end, cpm); +} + // C language interface functions. @@ -94,15 +100,15 @@ void *jz4780_msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, void *cpm) { - return (void *) new Msc_jz4780_chip(msc_start, start, end, - static_cast(cpm)); + return (void *) jz4780_msc_chip(msc_start, start, end, + static_cast(cpm)); } void *jz4780_msc_get_channel(void *msc, uint8_t channel, l4_cap_idx_t irq, void *dma) { - return static_cast(msc)->get_channel(channel, irq, - static_cast(dma)); + return static_cast(msc)->get_channel(channel, irq, + static_cast(dma)); } struct msc_card *jz4780_msc_get_cards(void *msc_channel) diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/msc/src/x1600.cc --- a/pkg/devices/lib/msc/src/x1600.cc Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/msc/src/x1600.cc Sat Apr 27 23:46:28 2024 +0200 @@ -31,7 +31,7 @@ Msc_x1600_channel::Msc_x1600_channel(l4_addr_t msc_start, l4_addr_t addr, l4_cap_idx_t irq, Cpm_chip *cpm, enum Clock_identifiers clock, - Dma_x1600_channel *dma, + Dma_channel *dma, enum Dma_x1600_request_type request_type_in, enum Dma_x1600_request_type request_type_out) : Msc_channel(msc_start, addr, irq, cpm, clock), @@ -77,7 +77,7 @@ recv ? false : true, // increment source if sending recv ? true : false, // increment destination if receiving 4, 4, unit_size, - recv ? _request_type_in : _request_type_out); + (int) (recv ? _request_type_in : _request_type_out)); return to_transfer * unit_size; } @@ -93,7 +93,7 @@ } Msc_channel *Msc_x1600_chip::get_channel(uint8_t channel, l4_cap_idx_t irq, - Dma_x1600_channel *dma) + Dma_channel *dma) { if (channel < num_channels()) return new Msc_x1600_channel(_msc_start + channel * Msc_channel_offset, @@ -104,6 +104,12 @@ throw -L4_EINVAL; } +Msc_chip *x1600_msc_chip(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, + Cpm_chip *cpm) +{ + return new Msc_x1600_chip(msc_start, start, end, cpm); +} + // C language interface functions. @@ -111,15 +117,15 @@ void *x1600_msc_init(l4_addr_t msc_start, l4_addr_t start, l4_addr_t end, void *cpm) { - return (void *) new Msc_x1600_chip(msc_start, start, end, - static_cast(cpm)); + return (void *) x1600_msc_chip(msc_start, start, end, + static_cast(cpm)); } void *x1600_msc_get_channel(void *msc, uint8_t channel, l4_cap_idx_t irq, void *dma) { - return static_cast(msc)->get_channel(channel, irq, - static_cast(dma)); + return static_cast(msc)->get_channel(channel, irq, + static_cast(dma)); } struct msc_card *x1600_msc_get_cards(void *msc_channel) diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/spi/include/spi-jz4780.h --- a/pkg/devices/lib/spi/include/spi-jz4780.h Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/spi/include/spi-jz4780.h Sat Apr 27 23:46:28 2024 +0200 @@ -44,8 +44,8 @@ l4_addr_t _spi_start; enum Clock_identifiers _clock; - Cpm_jz4780_chip *_cpm; - Dma_jz4780_channel *_dma; + Cpm_chip *_cpm; + Dma_channel *_dma; enum Dma_jz4780_request_type _request_type; uint64_t _frequency; @@ -58,8 +58,8 @@ public: explicit Spi_jz4780_channel(l4_addr_t spi_start, l4_addr_t start, enum Clock_identifiers clock, - Cpm_jz4780_chip *cpm, - Dma_jz4780_channel *dma, + Cpm_chip *cpm, + Dma_channel *dma, enum Dma_jz4780_request_type request_type, uint64_t frequency); @@ -87,12 +87,12 @@ { private: l4_addr_t _spi_start, _start, _end; - Cpm_jz4780_chip *_cpm; + Cpm_chip *_cpm; public: - explicit Spi_jz4780_chip(l4_addr_t spi_start, l4_addr_t start, l4_addr_t end, Cpm_jz4780_chip *cpm); + explicit Spi_jz4780_chip(l4_addr_t spi_start, l4_addr_t start, l4_addr_t end, Cpm_chip *cpm); - Spi_jz4780_channel *get_channel(uint8_t channel, Dma_jz4780_channel *dma, uint64_t frequency); + Spi_jz4780_channel *get_channel(uint8_t channel, Dma_channel *dma, uint64_t frequency); }; #endif /* __cplusplus */ diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/devices/lib/spi/src/jz4780.cc --- a/pkg/devices/lib/spi/src/jz4780.cc Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/devices/lib/spi/src/jz4780.cc Sat Apr 27 23:46:28 2024 +0200 @@ -206,8 +206,8 @@ Spi_jz4780_channel::Spi_jz4780_channel(l4_addr_t spi_start, l4_addr_t start, enum Clock_identifiers clock, - Cpm_jz4780_chip *cpm, - Dma_jz4780_channel *dma, + Cpm_chip *cpm, + Dma_channel *dma, enum Dma_jz4780_request_type request_type, uint64_t frequency) : _spi_start(spi_start), _clock(clock), _cpm(cpm), _dma(dma), @@ -416,13 +416,13 @@ /* Initialise the peripheral abstraction. */ Spi_jz4780_chip::Spi_jz4780_chip(l4_addr_t spi_start, l4_addr_t start, - l4_addr_t end, Cpm_jz4780_chip *cpm) + l4_addr_t end, Cpm_chip *cpm) : _spi_start(spi_start), _start(start), _end(end), _cpm(cpm) { } Spi_jz4780_channel * -Spi_jz4780_chip::get_channel(uint8_t channel, Dma_jz4780_channel *dma, +Spi_jz4780_chip::get_channel(uint8_t channel, Dma_channel *dma, uint64_t frequency) { // NOTE: Only sending is supported. @@ -445,13 +445,13 @@ void *jz4780_spi_init(l4_addr_t spi_start, l4_addr_t start, l4_addr_t end, void *cpm) { - return new Spi_jz4780_chip(spi_start, start, end, static_cast(cpm)); + return new Spi_jz4780_chip(spi_start, start, end, static_cast(cpm)); } void *jz4780_spi_get_channel(void *spi, uint8_t channel, void *dma, uint64_t frequency) { return static_cast(spi)->get_channel(channel, - static_cast(dma), frequency); + static_cast(dma), frequency); } uint32_t jz4780_spi_send(void *channel, uint32_t bytes, const uint8_t data[]) diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/landfall-examples/hw_info/jz4780.c --- a/pkg/landfall-examples/hw_info/jz4780.c Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/landfall-examples/hw_info/jz4780.c Sat Apr 27 23:46:28 2024 +0200 @@ -659,7 +659,7 @@ struct clock_info clocks[] = { {"ext", Clock_external, "EXCLK"}, - {"ext_512", Clock_external_div_512, "EXCLK/512"}, + {"ext_512", Clock_external_div, "EXCLK/512"}, {"rtc_ext", Clock_rtc_external, "RTCLK"}, {"plla", Clock_pll_A, "PLL A"}, {"plle", Clock_pll_E, "PLL E"}, diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/landfall-examples/hw_info/x1600.c --- a/pkg/landfall-examples/hw_info/x1600.c Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/landfall-examples/hw_info/x1600.c Sat Apr 27 23:46:28 2024 +0200 @@ -645,7 +645,7 @@ struct clock_info clocks[] = { {"ext", Clock_external, "EXCLK"}, - {"ext_512", Clock_external_div_512, "EXCLK/512"}, + {"ext_512", Clock_external_div, "EXCLK/512"}, {"rtc_ext", Clock_rtc_external, "RTCLK"}, {"plla", Clock_pll_A, "PLL A"}, {"plle", Clock_pll_E, "PLL E"}, diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/landfall-examples/msc_block_server/msc_block_server.cc --- a/pkg/landfall-examples/msc_block_server/msc_block_server.cc Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/landfall-examples/msc_block_server/msc_block_server.cc Sat Apr 27 23:46:28 2024 +0200 @@ -19,11 +19,10 @@ * Boston, MA 02110-1301, USA */ -#include -#include -#include +#include +#include #include -#include +#include #include #include @@ -37,6 +36,7 @@ #include #include +#include #include #include @@ -102,16 +102,18 @@ /* Peripheral resources. */ -static Cpm_x1600_chip *cpm; -static Dma_x1600_chip *dma; -static Msc_x1600_chip *msc; +static Cpm_chip *cpm; +static Dma_chip *dma; +static Msc_chip *msc; /* Obtain an abstraction for the memory card. */ -static MscRegionOperations *get_msc_region_operations(int msc_channel_num, +static MscRegionOperations *get_msc_region_operations(const char *machine, + int msc_channel_num, int dma_channel_num, int card) { + char resource[strlen(machine) + 8]; l4_addr_t cpm_base = 0, cpm_base_end = 0; l4_addr_t dma_base = 0, dma_base_end = 0; l4_addr_t msc_base = 0, msc_base_end = 0; @@ -123,17 +125,21 @@ /* Obtain resource details describing I/O memory. */ - if (get_memory("x1600-cpm", &cpm_base, &cpm_base_end) < 0) + sprintf(resource, "%s-cpm", machine); + + if (get_memory(resource, &cpm_base, &cpm_base_end) < 0) return NULL; - cpm = new Cpm_x1600_chip(cpm_base); + cpm = new_cpm_chip(machine, cpm_base); - if (get_memory("x1600-dma", &dma_base, &dma_base_end) < 0) + sprintf(resource, "%s-dma", machine); + + if (get_memory(resource, &dma_base, &dma_base_end) < 0) return NULL; - dma = new Dma_x1600_chip(dma_base, dma_base_end, cpm); + dma = new_dma_chip(machine, dma_base, dma_base_end, cpm); - if (get_irq("x1600-dma", &dma_irq_start, &dma_irq_end) < 0) + if (get_irq(resource, &dma_irq_start, &dma_irq_end) < 0) return NULL; l4_cap_idx_t dma_irq = l4re_util_cap_alloc(); @@ -143,13 +149,15 @@ dma->enable(); - if (get_memory_complete("x1600-msc", &msc_base, &msc_base_end, + sprintf(resource, "%s-msc", machine); + + if (get_memory_complete(resource, &msc_base, &msc_base_end, &msc_phys_base, &msc_phys_base_end) < 0) return NULL; - msc = new Msc_x1600_chip(msc_phys_base, msc_base, msc_base_end, cpm); + msc = new_msc_chip(machine, msc_phys_base, msc_base, msc_base_end, cpm); - if (get_irq("x1600-msc", &msc_irq_start, &msc_irq_end) < 0) + if (get_irq(resource, &msc_irq_start, &msc_irq_end) < 0) return NULL; l4_cap_idx_t msc_irq = l4re_util_cap_alloc(); @@ -157,7 +165,7 @@ if (init_irq(msc_channel_num, msc_irq, msc_irq_start, msc_irq_end)) return NULL; - Dma_x1600_channel *dma_channel = dma->get_channel(dma_channel_num, dma_irq); + Dma_channel *dma_channel = dma->get_channel(dma_channel_num, dma_irq); Msc_channel *msc_channel = msc->get_channel(msc_channel_num, msc_irq, dma_channel); msc_channel->enable(); @@ -198,26 +206,30 @@ return 1; } - if (argc < 4) + if (argc < 5) { - printf("Need a MSC channel/peripheral number, a DMA channel number, " \ - "and a card number.\n\n" \ + printf("Need the following:\n\n" \ + "A machine indicator such as jz4780 or x1600.\n" \ + "An MSC channel/peripheral number.\n" \ + "A DMA channel number.\n" \ + "A card number.\n\n" \ "A number of memory pages can be indicated for the use of the " \ "server.\n\n" \ "A named capability from the environment can be specified.\n"); return 1; } - int msc_channel_num = atoi(argv[1]); - int dma_channel_num = atoi(argv[2]); - int card = atoi(argv[3]); + char *machine = argv[1]; + int msc_channel_num = atoi(argv[2]); + int dma_channel_num = atoi(argv[3]); + int card = atoi(argv[4]); unsigned int memory_pages = MEMORY_PAGES; - if (argc > 4) - memory_pages = atoi(argv[4]); + if (argc > 5) + memory_pages = atoi(argv[5]); - const char *server_name = (argc > 5) ? argv[5] : ENV_FILESYSTEM_SERVER_NAME; + const char *server_name = (argc > 6) ? argv[6] : ENV_FILESYSTEM_SERVER_NAME; /* Obtain a DMA space for associating allocated memory with physical addresses. */ @@ -232,7 +244,8 @@ return 1; } - MscRegionOperations *ops = get_msc_region_operations(msc_channel_num, + MscRegionOperations *ops = get_msc_region_operations(machine, + msc_channel_num, dma_channel_num, card); diff -r 8aead0ac0492 -r e7c6fdf89706 pkg/landfall-examples/msc_block_server/msc_region_operations.h --- a/pkg/landfall-examples/msc_block_server/msc_region_operations.h Wed Apr 24 00:47:34 2024 +0200 +++ b/pkg/landfall-examples/msc_block_server/msc_region_operations.h Sat Apr 27 23:46:28 2024 +0200 @@ -25,7 +25,7 @@ #include #include -#include +#include #include