| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| #include "sw/device/silicon_creator/lib/drivers/pinmux.h" |
| |
| #include "sw/device/lib/base/abs_mmio.h" |
| #include "sw/device/lib/base/hardened.h" |
| #include "sw/device/lib/base/macros.h" |
| #include "sw/device/silicon_creator/lib/base/chip.h" |
| #include "sw/device/silicon_creator/lib/drivers/otp.h" |
| |
| #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" |
| #include "otp_ctrl_regs.h" |
| #include "pinmux_regs.h" |
| |
| /** |
| * A peripheral input and MIO pad to link it to. |
| */ |
| typedef struct pinmux_input { |
| top_earlgrey_pinmux_peripheral_in_t periph; |
| top_earlgrey_pinmux_insel_t insel; |
| top_earlgrey_muxed_pads_t pad; |
| } pinmux_input_t; |
| |
| /** |
| * An MIO pad and a peripheral output to link it to. |
| */ |
| typedef struct pinmux_output { |
| top_earlgrey_pinmux_mio_out_t mio; |
| top_earlgrey_pinmux_outsel_t outsel; |
| top_earlgrey_muxed_pads_t pad; |
| } pinmux_output_t; |
| |
| /** |
| * UART RX pin. |
| */ |
| static const pinmux_input_t kInputUart0 = { |
| .periph = kTopEarlgreyPinmuxPeripheralInUart0Rx, |
| .insel = kTopEarlgreyPinmuxInselIoc3, |
| .pad = kTopEarlgreyMuxedPadsIoc3, |
| }; |
| |
| /** |
| * UART TX pin. |
| */ |
| static const pinmux_output_t kOutputUart0 = { |
| .mio = kTopEarlgreyPinmuxMioOutIoc4, |
| .outsel = kTopEarlgreyPinmuxOutselUart0Tx, |
| .pad = kTopEarlgreyMuxedPadsIoc4, |
| }; |
| |
| /** |
| * SW strap pins. |
| */ |
| #define PINMUX_ASSERT_EQ_(a, b) \ |
| static_assert((a) == (b), "Unexpected software strap configuration.") |
| |
| PINMUX_ASSERT_EQ_(SW_STRAP_0_PERIPH, kTopEarlgreyPinmuxPeripheralInGpioGpio22); |
| PINMUX_ASSERT_EQ_(SW_STRAP_0_INSEL, kTopEarlgreyPinmuxInselIoc0); |
| PINMUX_ASSERT_EQ_(SW_STRAP_0_PAD, kTopEarlgreyMuxedPadsIoc0); |
| static const pinmux_input_t kInputSwStrap0 = { |
| .periph = SW_STRAP_0_PERIPH, |
| .insel = SW_STRAP_0_INSEL, |
| .pad = SW_STRAP_0_PAD, |
| }; |
| |
| PINMUX_ASSERT_EQ_(SW_STRAP_1_PERIPH, kTopEarlgreyPinmuxPeripheralInGpioGpio23); |
| PINMUX_ASSERT_EQ_(SW_STRAP_1_INSEL, kTopEarlgreyPinmuxInselIoc1); |
| PINMUX_ASSERT_EQ_(SW_STRAP_1_PAD, kTopEarlgreyMuxedPadsIoc1); |
| static const pinmux_input_t kInputSwStrap1 = { |
| .periph = SW_STRAP_1_PERIPH, |
| .insel = SW_STRAP_1_INSEL, |
| .pad = SW_STRAP_1_PAD, |
| }; |
| |
| PINMUX_ASSERT_EQ_(SW_STRAP_2_PERIPH, kTopEarlgreyPinmuxPeripheralInGpioGpio24); |
| PINMUX_ASSERT_EQ_(SW_STRAP_2_INSEL, kTopEarlgreyPinmuxInselIoc2); |
| PINMUX_ASSERT_EQ_(SW_STRAP_2_PAD, kTopEarlgreyMuxedPadsIoc2); |
| static const pinmux_input_t kInputSwStrap2 = { |
| .periph = SW_STRAP_2_PERIPH, |
| .insel = SW_STRAP_2_INSEL, |
| .pad = SW_STRAP_2_PAD, |
| }; |
| |
| /** |
| * Sets the input pad for the specified peripheral input. |
| * |
| * @param input A peripheral input and MIO pad to link it to. |
| */ |
| static void configure_input(uintptr_t base_addr, pinmux_input_t input) { |
| abs_mmio_write32(base_addr + PINMUX_MIO_PERIPH_INSEL_0_REG_OFFSET + |
| input.periph * sizeof(uint32_t), |
| input.insel); |
| } |
| |
| /** |
| * Enables pull-down for the specified pad. |
| * |
| * @param pad A MIO pad. |
| */ |
| static void enable_pull_down(uintptr_t base_addr, top_earlgrey_muxed_pads_t pad) { |
| uint32_t reg = |
| bitfield_bit32_write(0, PINMUX_MIO_PAD_ATTR_0_PULL_EN_0_BIT, true); |
| abs_mmio_write32(base_addr + |
| PINMUX_MIO_PAD_ATTR_0_REG_OFFSET + pad * sizeof(uint32_t), reg); |
| } |
| |
| /** |
| * Sets the peripheral output for each specified output pad. |
| * |
| * @param output An MIO pad and a peripheral output to link it to. |
| */ |
| static void configure_output(uintptr_t base_addr, pinmux_output_t output) { |
| abs_mmio_write32(base_addr + |
| PINMUX_MIO_OUTSEL_0_REG_OFFSET + output.mio * sizeof(uint32_t), |
| output.outsel); |
| } |
| |
| void pinmux_init(uintptr_t base_addr, uintptr_t otp_addr) { |
| uint32_t bootstrap_en = |
| otp_read32(otp_addr, OTP_CTRL_PARAM_OWNER_SW_CFG_ROM_BOOTSTRAP_EN_OFFSET); |
| if (launder32(bootstrap_en) == kHardenedBoolTrue) { |
| HARDENED_CHECK_EQ(bootstrap_en, kHardenedBoolTrue); |
| // Note: attributes should be configured before the pinmux matrix to avoid |
| // "undesired electrical behavior and/or contention at the pads". |
| enable_pull_down(base_addr, kInputSwStrap0.pad); |
| enable_pull_down(base_addr, kInputSwStrap1.pad); |
| enable_pull_down(base_addr, kInputSwStrap2.pad); |
| configure_input(base_addr, kInputSwStrap0); |
| configure_input(base_addr, kInputSwStrap1); |
| configure_input(base_addr, kInputSwStrap2); |
| } |
| |
| configure_input(base_addr, kInputUart0); |
| configure_output(base_addr, kOutputUart0); |
| } |