sonata: Added a driver for the pinmux
diff --git a/sdk/include/platform/sunburst/platform-pinmux.hh b/sdk/include/platform/sunburst/platform-pinmux.hh
new file mode 100644
index 0000000..3a1017e
--- /dev/null
+++ b/sdk/include/platform/sunburst/platform-pinmux.hh
@@ -0,0 +1,421 @@
+/**
+ * SPDX-FileCopyrightText: lowRISC contributors
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * This file is generated by ./util/topgen.py
+ * in https://github.com/lowRISC/sonata-system
+ */
+
+#pragma once
+#include <cheri.hh>
+#include <debug.hh>
+#include <stdint.h>
+#include <utils.hh>
+
+namespace SonataPinmux
+{
+	/// The number of pin sinks (pin outputs)
+	static constexpr size_t NumPinSinks = 85;
+
+	/// The number of block sinks (block inputs)
+	static constexpr size_t NumBlockSinks = 70;
+
+	/// Flag to set when debugging the driver for UART log messages.
+	static constexpr bool DebugDriver = false;
+
+	/// Helper for conditional debug logs and assertions.
+	using Debug = ConditionalDebug<DebugDriver, "Pinmux">;
+
+	/// The disable bit that disables a sink
+	constexpr uint8_t SourceDisabled = 0;
+
+	/// The bit that resets a sink to it's default value
+	constexpr uint8_t SourceDefault = 1;
+
+	/**
+	 * Each pin sink is configured by an 8-bit register. This enum maps pin sink
+	 * names to the offset of their configuration registers. The offsets are
+	 * relative to the first pin sink register.
+	 *
+	 * Documentation sources:
+	 * 1. https://lowrisc.github.io/sonata-system/doc/ip/pinmux/
+	 * 2.
+	 * https://github.com/lowRISC/sonata-system/blob/v1.0/data/pins_sonata.xdc
+	 * 3.
+	 * https://github.com/newaetech/sonata-pcb/blob/649b11c2fb758f798966605a07a8b6b68dd434e9/sonata-schematics-r09.pdf
+	 */
+	enum class PinSink : uint16_t
+	{
+		// Breaking enum naming convention to match cononical names used in PCB
+		// schematic documentation.
+		// When available, it would be neater to use NOLINTBEGIN and NOLINTEND.
+		ser0_tx      = 0x000, // NOLINT(readability-identifier-naming)
+		ser1_tx      = 0x001, // NOLINT(readability-identifier-naming)
+		rs232_tx     = 0x002, // NOLINT(readability-identifier-naming)
+		rs485_tx     = 0x003, // NOLINT(readability-identifier-naming)
+		scl0         = 0x004, // NOLINT(readability-identifier-naming)
+		sda0         = 0x005, // NOLINT(readability-identifier-naming)
+		scl1         = 0x006, // NOLINT(readability-identifier-naming)
+		sda1         = 0x007, // NOLINT(readability-identifier-naming)
+		rph_g0       = 0x008, // NOLINT(readability-identifier-naming)
+		rph_g1       = 0x009, // NOLINT(readability-identifier-naming)
+		rph_g2_sda   = 0x00a, // NOLINT(readability-identifier-naming)
+		rph_g3_scl   = 0x00b, // NOLINT(readability-identifier-naming)
+		rph_g4       = 0x00c, // NOLINT(readability-identifier-naming)
+		rph_g5       = 0x00d, // NOLINT(readability-identifier-naming)
+		rph_g6       = 0x00e, // NOLINT(readability-identifier-naming)
+		rph_g7       = 0x00f, // NOLINT(readability-identifier-naming)
+		rph_g8       = 0x010, // NOLINT(readability-identifier-naming)
+		rph_g9       = 0x011, // NOLINT(readability-identifier-naming)
+		rph_g10      = 0x012, // NOLINT(readability-identifier-naming)
+		rph_g11      = 0x013, // NOLINT(readability-identifier-naming)
+		rph_g12      = 0x014, // NOLINT(readability-identifier-naming)
+		rph_g13      = 0x015, // NOLINT(readability-identifier-naming)
+		rph_txd0     = 0x016, // NOLINT(readability-identifier-naming)
+		rph_rxd0     = 0x017, // NOLINT(readability-identifier-naming)
+		rph_g16      = 0x018, // NOLINT(readability-identifier-naming)
+		rph_g17      = 0x019, // NOLINT(readability-identifier-naming)
+		rph_g18      = 0x01a, // NOLINT(readability-identifier-naming)
+		rph_g19      = 0x01b, // NOLINT(readability-identifier-naming)
+		rph_g20      = 0x01c, // NOLINT(readability-identifier-naming)
+		rph_g21      = 0x01d, // NOLINT(readability-identifier-naming)
+		rph_g22      = 0x01e, // NOLINT(readability-identifier-naming)
+		rph_g23      = 0x01f, // NOLINT(readability-identifier-naming)
+		rph_g24      = 0x020, // NOLINT(readability-identifier-naming)
+		rph_g25      = 0x021, // NOLINT(readability-identifier-naming)
+		rph_g26      = 0x022, // NOLINT(readability-identifier-naming)
+		rph_g27      = 0x023, // NOLINT(readability-identifier-naming)
+		ah_tmpio0    = 0x024, // NOLINT(readability-identifier-naming)
+		ah_tmpio1    = 0x025, // NOLINT(readability-identifier-naming)
+		ah_tmpio2    = 0x026, // NOLINT(readability-identifier-naming)
+		ah_tmpio3    = 0x027, // NOLINT(readability-identifier-naming)
+		ah_tmpio4    = 0x028, // NOLINT(readability-identifier-naming)
+		ah_tmpio5    = 0x029, // NOLINT(readability-identifier-naming)
+		ah_tmpio6    = 0x02a, // NOLINT(readability-identifier-naming)
+		ah_tmpio7    = 0x02b, // NOLINT(readability-identifier-naming)
+		ah_tmpio8    = 0x02c, // NOLINT(readability-identifier-naming)
+		ah_tmpio9    = 0x02d, // NOLINT(readability-identifier-naming)
+		ah_tmpio10   = 0x02e, // NOLINT(readability-identifier-naming)
+		ah_tmpio11   = 0x02f, // NOLINT(readability-identifier-naming)
+		ah_tmpio12   = 0x030, // NOLINT(readability-identifier-naming)
+		ah_tmpio13   = 0x031, // NOLINT(readability-identifier-naming)
+		mb1          = 0x032, // NOLINT(readability-identifier-naming)
+		mb2          = 0x033, // NOLINT(readability-identifier-naming)
+		mb4          = 0x034, // NOLINT(readability-identifier-naming)
+		mb5          = 0x035, // NOLINT(readability-identifier-naming)
+		mb6          = 0x036, // NOLINT(readability-identifier-naming)
+		mb7          = 0x037, // NOLINT(readability-identifier-naming)
+		mb10         = 0x038, // NOLINT(readability-identifier-naming)
+		pmod0_1      = 0x039, // NOLINT(readability-identifier-naming)
+		pmod0_2      = 0x03a, // NOLINT(readability-identifier-naming)
+		pmod0_3      = 0x03b, // NOLINT(readability-identifier-naming)
+		pmod0_4      = 0x03c, // NOLINT(readability-identifier-naming)
+		pmod0_7      = 0x03d, // NOLINT(readability-identifier-naming)
+		pmod0_8      = 0x03e, // NOLINT(readability-identifier-naming)
+		pmod0_9      = 0x03f, // NOLINT(readability-identifier-naming)
+		pmod0_10     = 0x040, // NOLINT(readability-identifier-naming)
+		pmod1_1      = 0x041, // NOLINT(readability-identifier-naming)
+		pmod1_2      = 0x042, // NOLINT(readability-identifier-naming)
+		pmod1_3      = 0x043, // NOLINT(readability-identifier-naming)
+		pmod1_4      = 0x044, // NOLINT(readability-identifier-naming)
+		pmod1_7      = 0x045, // NOLINT(readability-identifier-naming)
+		pmod1_8      = 0x046, // NOLINT(readability-identifier-naming)
+		pmod1_9      = 0x047, // NOLINT(readability-identifier-naming)
+		pmod1_10     = 0x048, // NOLINT(readability-identifier-naming)
+		pmodc_1      = 0x049, // NOLINT(readability-identifier-naming)
+		pmodc_2      = 0x04a, // NOLINT(readability-identifier-naming)
+		pmodc_3      = 0x04b, // NOLINT(readability-identifier-naming)
+		pmodc_4      = 0x04c, // NOLINT(readability-identifier-naming)
+		pmodc_5      = 0x04d, // NOLINT(readability-identifier-naming)
+		pmodc_6      = 0x04e, // NOLINT(readability-identifier-naming)
+		appspi_d0    = 0x04f, // NOLINT(readability-identifier-naming)
+		appspi_clk   = 0x050, // NOLINT(readability-identifier-naming)
+		appspi_cs    = 0x051, // NOLINT(readability-identifier-naming)
+		microsd_cmd  = 0x052, // NOLINT(readability-identifier-naming)
+		microsd_clk  = 0x053, // NOLINT(readability-identifier-naming)
+		microsd_dat3 = 0x054, // NOLINT(readability-identifier-naming)
+	};
+
+	/**
+	 * Each block sink is configured by an 8-bit register. This enum maps block
+	 * sink names to the offset of their configuration registers. The offsets
+	 * are relative to the first block sink register.
+	 *
+	 * For GPIO block reference:
+	 *   gpio_0 = Raspberry Pi Header Pins
+	 *   gpio_1 = Arduino Shield Header Pins
+	 *   gpio_2 = Pmod0 Pins
+	 *   gpio_3 = Pmod1 Pins
+	 *   gpio_4 = PmodC Pins
+	 *
+	 * Documentation source:
+	 * https://lowrisc.github.io/sonata-system/doc/ip/pinmux/
+	 */
+	enum class BlockSink : uint16_t
+	{
+		// Breaking enum naming convention to match cononical names used in
+		// documentation.
+		// When available, it would be neater to use NOLINTBEGIN and NOLINTEND.
+		gpio_0_ios_0  = 0x000, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_1  = 0x001, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_2  = 0x002, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_3  = 0x003, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_4  = 0x004, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_5  = 0x005, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_6  = 0x006, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_7  = 0x007, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_8  = 0x008, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_9  = 0x009, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_10 = 0x00a, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_11 = 0x00b, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_12 = 0x00c, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_13 = 0x00d, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_14 = 0x00e, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_15 = 0x00f, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_16 = 0x010, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_17 = 0x011, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_18 = 0x012, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_19 = 0x013, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_20 = 0x014, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_21 = 0x015, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_22 = 0x016, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_23 = 0x017, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_24 = 0x018, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_25 = 0x019, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_26 = 0x01a, // NOLINT(readability-identifier-naming)
+		gpio_0_ios_27 = 0x01b, // NOLINT(readability-identifier-naming)
+		gpio_1_ios_0  = 0x01c, // NOLINT(readability-identifier-naming)
+		gpio_1_ios_1  = 0x01d, // NOLINT(readability-identifier-naming)
+		gpio_1_ios_2  = 0x01e, // NOLINT(readability-identifier-naming)
+		gpio_1_ios_3  = 0x01f, // NOLINT(readability-identifier-naming)
+		gpio_1_ios_4  = 0x020, // NOLINT(readability-identifier-naming)
+		gpio_1_ios_5  = 0x021, // NOLINT(readability-identifier-naming)
+		gpio_1_ios_6  = 0x022, // NOLINT(readability-identifier-naming)
+		gpio_1_ios_7  = 0x023, // NOLINT(readability-identifier-naming)
+		gpio_1_ios_8  = 0x024, // NOLINT(readability-identifier-naming)
+		gpio_1_ios_9  = 0x025, // NOLINT(readability-identifier-naming)
+		gpio_1_ios_10 = 0x026, // NOLINT(readability-identifier-naming)
+		gpio_1_ios_11 = 0x027, // NOLINT(readability-identifier-naming)
+		gpio_1_ios_12 = 0x028, // NOLINT(readability-identifier-naming)
+		gpio_1_ios_13 = 0x029, // NOLINT(readability-identifier-naming)
+		gpio_2_ios_0  = 0x02a, // NOLINT(readability-identifier-naming)
+		gpio_2_ios_1  = 0x02b, // NOLINT(readability-identifier-naming)
+		gpio_2_ios_2  = 0x02c, // NOLINT(readability-identifier-naming)
+		gpio_2_ios_3  = 0x02d, // NOLINT(readability-identifier-naming)
+		gpio_2_ios_4  = 0x02e, // NOLINT(readability-identifier-naming)
+		gpio_2_ios_5  = 0x02f, // NOLINT(readability-identifier-naming)
+		gpio_2_ios_6  = 0x030, // NOLINT(readability-identifier-naming)
+		gpio_2_ios_7  = 0x031, // NOLINT(readability-identifier-naming)
+		gpio_3_ios_0  = 0x032, // NOLINT(readability-identifier-naming)
+		gpio_3_ios_1  = 0x033, // NOLINT(readability-identifier-naming)
+		gpio_3_ios_2  = 0x034, // NOLINT(readability-identifier-naming)
+		gpio_3_ios_3  = 0x035, // NOLINT(readability-identifier-naming)
+		gpio_3_ios_4  = 0x036, // NOLINT(readability-identifier-naming)
+		gpio_3_ios_5  = 0x037, // NOLINT(readability-identifier-naming)
+		gpio_3_ios_6  = 0x038, // NOLINT(readability-identifier-naming)
+		gpio_3_ios_7  = 0x039, // NOLINT(readability-identifier-naming)
+		gpio_4_ios_0  = 0x03a, // NOLINT(readability-identifier-naming)
+		gpio_4_ios_1  = 0x03b, // NOLINT(readability-identifier-naming)
+		gpio_4_ios_2  = 0x03c, // NOLINT(readability-identifier-naming)
+		gpio_4_ios_3  = 0x03d, // NOLINT(readability-identifier-naming)
+		gpio_4_ios_4  = 0x03e, // NOLINT(readability-identifier-naming)
+		gpio_4_ios_5  = 0x03f, // NOLINT(readability-identifier-naming)
+		uart_0_rx     = 0x040, // NOLINT(readability-identifier-naming)
+		uart_1_rx     = 0x041, // NOLINT(readability-identifier-naming)
+		uart_2_rx     = 0x042, // NOLINT(readability-identifier-naming)
+		spi_0_cipo    = 0x043, // NOLINT(readability-identifier-naming)
+		spi_1_cipo    = 0x044, // NOLINT(readability-identifier-naming)
+		spi_2_cipo    = 0x045, // NOLINT(readability-identifier-naming)
+	};
+
+	/**
+	 * Returns the number of sources available for a pin sink (output pin).
+	 *
+	 * @param pin_sink The pin sink to query.
+	 * @returns The number of sources available for the given sink.
+	 */
+	static constexpr uint8_t sources_number(PinSink pinSink)
+	{
+		switch (pinSink)
+		{
+			case PinSink::pmod0_2:
+			case PinSink::pmod1_2:
+				return 5;
+			case PinSink::rph_g18:
+			case PinSink::rph_g20:
+			case PinSink::rph_g21:
+			case PinSink::ah_tmpio10:
+			case PinSink::ah_tmpio11:
+			case PinSink::pmod0_4:
+			case PinSink::pmod1_4:
+				return 4;
+			case PinSink::ser1_tx:
+			case PinSink::rph_g0:
+			case PinSink::rph_g1:
+			case PinSink::rph_g2_sda:
+			case PinSink::rph_g3_scl:
+			case PinSink::rph_g7:
+			case PinSink::rph_g8:
+			case PinSink::rph_g10:
+			case PinSink::rph_g11:
+			case PinSink::rph_g12:
+			case PinSink::rph_g13:
+			case PinSink::rph_txd0:
+			case PinSink::rph_g16:
+			case PinSink::rph_g17:
+			case PinSink::rph_g19:
+			case PinSink::ah_tmpio1:
+			case PinSink::ah_tmpio3:
+			case PinSink::ah_tmpio5:
+			case PinSink::ah_tmpio6:
+			case PinSink::ah_tmpio9:
+			case PinSink::ah_tmpio13:
+			case PinSink::pmod0_1:
+			case PinSink::pmod0_3:
+			case PinSink::pmod0_8:
+			case PinSink::pmod0_9:
+			case PinSink::pmod0_10:
+			case PinSink::pmod1_1:
+			case PinSink::pmod1_3:
+			case PinSink::pmod1_8:
+			case PinSink::pmod1_9:
+			case PinSink::pmod1_10:
+				return 3;
+			default:
+				return 2;
+		}
+	}
+
+	/**
+	 * Returns the number of sources available for a block sink (block input).
+	 *
+	 * @param block_sink The block sink to query.
+	 * @returns The number of sources available for the given sink.
+	 */
+	static constexpr uint8_t sources_number(BlockSink blockSink)
+	{
+		switch (blockSink)
+		{
+			case BlockSink::uart_1_rx:
+				return 6;
+			case BlockSink::uart_2_rx:
+				return 5;
+			case BlockSink::spi_1_cipo:
+			case BlockSink::spi_2_cipo:
+				return 4;
+			case BlockSink::spi_0_cipo:
+				return 3;
+			default:
+				return 2;
+		}
+	}
+
+	/**
+	 * A handle to a sink configuration register. This can be used to select
+	 * the source of the handle's associated sink.
+	 */
+	template<typename SinkEnum>
+	struct Sink
+	{
+		CHERI::Capability<volatile uint8_t> reg;
+		const SinkEnum                      SinkId;
+
+		/**
+		 * Select a source to connect to the sink.
+		 *
+		 * To see the sources available for a given sink see the Sonata system
+		 * documentation:
+		 * https://lowrisc.github.io/sonata-system/doc/ip/pinmux/
+		 *
+		 * Note, source 0 disconnects the sink from any source disabling it,
+		 * and source 1 is the default source for any given sink.
+		 */
+		bool select(uint8_t source)
+		{
+			if (source >= sources_number(SinkId))
+			{
+				Debug::log("{} is outside the range of valid sources, [0-{}), "
+				           "of pin {}.",
+				           source,
+				           sources_number(SinkId),
+				           SinkId);
+				return false;
+			}
+			*reg = 1 << source;
+			return true;
+		}
+
+		/// Disconnect the sink from all available sources.
+		void disable()
+		{
+			*reg = 1 << SourceDisabled;
+		}
+
+		/// Reset the sink to it's default source.
+		void default_selection()
+		{
+			*reg = 1 << SourceDefault;
+		}
+	};
+
+	namespace
+	{
+		template<typename SinkEnum>
+		// This is used by `BlockSinks` and `PinSinks`
+		// to return a capability to a single sink's configuration register.
+		inline Sink<SinkEnum> get_sink(volatile uint8_t *baseRegister,
+		                               const SinkEnum    SinkId)
+		{
+			CHERI::Capability reg = {baseRegister +
+			                         static_cast<ptrdiff_t>(SinkId)};
+			reg.bounds()          = sizeof(uint8_t);
+			return Sink<SinkEnum>{reg, SinkId};
+		};
+	} // namespace
+
+	/**
+	 * A driver for the Sonata system's pin multiplexed output pins.
+	 *
+	 * The Sonata system's Pin Multiplexer (pinmux) has two sets of registers:
+	 * the pin sink registers and the block sink registers. This structure
+	 * provides access to the pin sinks registers. Pin sinks are output onto the
+	 * Sonata system's pins, which can be connected to a number of block outputs
+	 * (their sources). The sources each sink can connect to are limited. See
+	 * the documentation for the possible sources for a given pin:
+	 *
+	 * https://lowrisc.github.io/sonata-system/doc/ip/pinmux/
+	 */
+	struct PinSinks : private utils::NoCopyNoMove
+	{
+		volatile uint8_t registers[NumPinSinks];
+
+		/// Returns a handle to a pin sink (an output pin).
+		Sink<PinSink> get(PinSink sink) volatile
+		{
+			return get_sink<PinSink>(registers, sink);
+		};
+	};
+
+	/**
+	 * A driver for the Sonata system's pin multiplexed block inputs.
+	 *
+	 * The Sonata system's Pin Multiplexer (pinmux) has two sets of registers:
+	 * the pin sink registers and the block sink registers. This structure
+	 * provides access to the block sinks registers. Block sinks are inputs into
+	 * the Sonata system's devices that can be connected to a number of system
+	 * input pins (their sources). The sources each sink can connect to are
+	 * limited. See the documentation for the possible sources for a given pin:
+	 *
+	 * https://lowrisc.github.io/sonata-system/doc/ip/pinmux
+	 */
+	struct BlockSinks : private utils::NoCopyNoMove
+	{
+		volatile uint8_t registers[NumBlockSinks];
+
+		/// Returns a handle to a block sink (a block input).
+		Sink<BlockSink> get(BlockSink sink) volatile
+		{
+			return get_sink<BlockSink>(registers, sink);
+		};
+	};
+} // namespace SonataPinmux