text: // Copyright lowRISC contributors.
  // Licensed under the Apache License, Version 2.0, see LICENSE for details.
  // SPDX-License-Identifier: Apache-2.0
  
  #include "sw/device/lib/pinmux.h"
  
  #include "sw/device/lib/base/mmio.h"
  
  #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
  #include "pinmux_regs.h"  // Generated.
  
  #define PINMUX0_BASE_ADDR TOP_EARLGREY_PINMUX_AON_BASE_ADDR
  
  #define NUM_GPIO 32
  
  static void init_gpio_regs(uint32_t reg, uint32_t mask, uint32_t start_v) {
    mmio_region_t reg32 = mmio_region_from_addr(reg);
    uint32_t reg_value = start_v;
    uint32_t reg_offset = kTopEarlgreyPinmuxPeripheralInGpioGpio0 << 2;
  
    // We've got 32 GPIOs
    for (uint32_t i = 0; i < NUM_GPIO; ++i) {
      mmio_region_write32(reg32, reg_offset, reg_value & mask);
      reg_value++;
      reg_offset += 4;
    }
  }
  
  void pinmux_init(void) {
    // TODO: This hardcoded configuration is temporary and needs to be
    // replaced by proper initialization code once 1) the pinmux DIF is
    // available, 2) the pinmux and padring design is finalized.
  
    // input: assign MIO0..MIO31 to GPIO0..GPIO31
    init_gpio_regs(PINMUX0_BASE_ADDR + PINMUX_MIO_PERIPH_INSEL_0_REG_OFFSET,
                   PINMUX_MIO_PERIPH_INSEL_0_IN_0_MASK,
                   PINMUX_MIO_PERIPH_INSEL_IDX_OFFSET);
  
    // output: assign GPIO0..GPIO31 to MIO0..MIO31
    init_gpio_regs(PINMUX0_BASE_ADDR + PINMUX_MIO_OUTSEL_0_REG_OFFSET,
                   PINMUX_MIO_OUTSEL_0_OUT_0_MASK,
                   PINMUX_PERIPH_OUTSEL_IDX_OFFSET);
  
    // Configure UART0 RX input to connect to MIO pad IOC3
    mmio_region_t reg32 = mmio_region_from_addr(
        PINMUX0_BASE_ADDR + PINMUX_MIO_PERIPH_INSEL_0_REG_OFFSET);
    uint32_t reg_value = kTopEarlgreyPinmuxInselIoc3;
    // We've got one insel configuration field per register. Hence, we have to
    // convert the enumeration index into a byte address using << 2.
    uint32_t reg_offset = kTopEarlgreyPinmuxPeripheralInUart0Rx << 2;
    uint32_t mask = PINMUX_MIO_PERIPH_INSEL_0_IN_0_MASK;
    mmio_region_write32(reg32, reg_offset, reg_value & mask);
  
    // Configure UART0 TX output to connect to MIO pad IOC4
    reg32 =
        mmio_region_from_addr(PINMUX0_BASE_ADDR + PINMUX_MIO_OUTSEL_0_REG_OFFSET);
    reg_value = kTopEarlgreyPinmuxOutselUart0Tx;
    // We've got one insel configuration field per register. Hence, we have to
    // convert the enumeration index into a byte address using << 2.
    reg_offset = kTopEarlgreyPinmuxMioOutIoc4 << 2;
    mask = PINMUX_MIO_OUTSEL_0_OUT_0_MASK;
    mmio_region_write32(reg32, reg_offset, reg_value & mask);
  
    // Configure UART1 RX input to connect to MIO pad IOC8
    reg32 = mmio_region_from_addr(PINMUX0_BASE_ADDR +
                                  PINMUX_MIO_PERIPH_INSEL_0_REG_OFFSET);
    reg_value = kTopEarlgreyPinmuxInselIoc8;
    // We've got one insel configuration field per register. Hence, we have to
    // convert the enumeration index into a byte address using << 2.
    reg_offset = kTopEarlgreyPinmuxPeripheralInUart1Rx << 2;
    mask = PINMUX_MIO_PERIPH_INSEL_0_IN_0_MASK;
    mmio_region_write32(reg32, reg_offset, reg_value & mask);
  
    // Configure UART1 TX output to connect to MIO pad IOC9
    reg32 =
        mmio_region_from_addr(PINMUX0_BASE_ADDR + PINMUX_MIO_OUTSEL_0_REG_OFFSET);
    reg_value = kTopEarlgreyPinmuxOutselUart1Tx;
    // We've got one insel configuration field per register. Hence, we have to
    // convert the enumeration index into a byte address using << 2.
    reg_offset = kTopEarlgreyPinmuxMioOutIoc9 << 2;
    mask = PINMUX_MIO_OUTSEL_0_OUT_0_MASK;
    mmio_region_write32(reg32, reg_offset, reg_value & mask);
  
    // Configure USBDEV SENSE outputs to be high-Z (IOR0, IOR1)
    reg32 =
        mmio_region_from_addr(PINMUX0_BASE_ADDR + PINMUX_MIO_OUTSEL_0_REG_OFFSET);
    // TODO(lowRISC/opentitan#10408): replace with named constant
    reg_value = 2;  // high-Z value
    mask = PINMUX_MIO_OUTSEL_0_OUT_0_MASK;
    // We've got one insel configuration field per register. Hence, we have to
    // convert the enumeration index into a byte address using << 2.
    reg_offset = kTopEarlgreyPinmuxMioOutIor0 << 2;
    mmio_region_write32(reg32, reg_offset, reg_value & mask);
    // We've got one insel configuration field per register. Hence, we have to
    // convert the enumeration index into a byte address using << 2.
    reg_offset = kTopEarlgreyPinmuxMioOutIor1 << 2;
    mmio_region_write32(reg32, reg_offset, reg_value & mask);
  }
  