| // 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/testing/pinmux_testutils.h" | |
| #include "sw/device/lib/arch/device.h" | |
| #include "sw/device/lib/base/macros.h" | |
| #include "sw/device/lib/base/status.h" | |
| #include "sw/device/lib/dif/dif_base.h" | |
| #include "sw/device/lib/dif/dif_gpio.h" | |
| #include "sw/device/lib/dif/dif_pinmux.h" | |
| #include "sw/device/lib/runtime/hart.h" | |
| #include "sw/device/lib/testing/test_framework/check.h" | |
| #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" | |
| void pinmux_testutils_init(dif_pinmux_t *pinmux) { | |
| // Set up SW straps on IOC0-IOC2, for GPIOs 22-24 | |
| CHECK_DIF_OK(dif_pinmux_input_select(pinmux, | |
| kTopEarlgreyPinmuxPeripheralInGpioGpio22, | |
| kTopEarlgreyPinmuxInselIoc0)); | |
| CHECK_DIF_OK(dif_pinmux_input_select(pinmux, | |
| kTopEarlgreyPinmuxPeripheralInGpioGpio23, | |
| kTopEarlgreyPinmuxInselIoc1)); | |
| CHECK_DIF_OK(dif_pinmux_input_select(pinmux, | |
| kTopEarlgreyPinmuxPeripheralInGpioGpio24, | |
| kTopEarlgreyPinmuxInselIoc2)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopEarlgreyPinmuxMioOutIoc0, | |
| kTopEarlgreyPinmuxOutselGpioGpio22)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopEarlgreyPinmuxMioOutIoc1, | |
| kTopEarlgreyPinmuxOutselGpioGpio23)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopEarlgreyPinmuxMioOutIoc2, | |
| kTopEarlgreyPinmuxOutselGpioGpio24)); | |
| // Configure UART0 RX input to connect to MIO pad IOC3 | |
| CHECK_DIF_OK(dif_pinmux_input_select(pinmux, | |
| kTopEarlgreyPinmuxPeripheralInUart0Rx, | |
| kTopEarlgreyPinmuxInselIoc3)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopEarlgreyPinmuxMioOutIoc3, | |
| kTopEarlgreyPinmuxOutselConstantHighZ)); | |
| // Configure UART0 TX output to connect to MIO pad IOC4 | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopEarlgreyPinmuxMioOutIoc4, | |
| kTopEarlgreyPinmuxOutselUart0Tx)); | |
| #if !OT_IS_ENGLISH_BREAKFAST | |
| // Enable pull-ups on UART0 RX | |
| // Pull-ups are available only on certain platforms. | |
| if (kDeviceType == kDeviceSimDV) { | |
| dif_pinmux_pad_attr_t out_attr; | |
| dif_pinmux_pad_attr_t in_attr = { | |
| .slew_rate = 0, | |
| .drive_strength = 0, | |
| .flags = kDifPinmuxPadAttrPullResistorEnable | | |
| kDifPinmuxPadAttrPullResistorUp}; | |
| CHECK_DIF_OK(dif_pinmux_pad_write_attrs(pinmux, kTopEarlgreyMuxedPadsIoc3, | |
| kDifPinmuxPadKindMio, in_attr, | |
| &out_attr)); | |
| }; | |
| // Configure UART1 RX input to connect to MIO pad IOB4 | |
| CHECK_DIF_OK(dif_pinmux_input_select(pinmux, | |
| kTopEarlgreyPinmuxPeripheralInUart1Rx, | |
| kTopEarlgreyPinmuxInselIob4)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopEarlgreyPinmuxMioOutIob4, | |
| kTopEarlgreyPinmuxOutselConstantHighZ)); | |
| // Configure UART1 TX output to connect to MIO pad IOB5 | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopEarlgreyPinmuxMioOutIob5, | |
| kTopEarlgreyPinmuxOutselUart1Tx)); | |
| #endif | |
| // Configure USBDEV SENSE outputs to be high-Z (IOC7) | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopEarlgreyPinmuxMioOutIoc7, | |
| kTopEarlgreyPinmuxOutselConstantHighZ)); | |
| } | |
| // Mapping of Chip IOs to the GPIO peripheral. | |
| // | |
| // Depending on the simulation platform, there may be a limitation to how chip | |
| // IOs are allocated to the GPIO peripheral, even for testing. The DV testbench | |
| // does not have this limitation, and is able to allocate as many chip IOs as | |
| // the number of GPIOs supported by the peripheral. At this time, these pin | |
| // assignments matches DV (see `hw/top_earlgrey/dv/env/chip_if.sv`). | |
| // | |
| // The pinout spreadsheet allocates fewer pins to GPIOs than what the GPIO IP | |
| // supports. This oversubscription is intentional to maximize testing. | |
| const dif_pinmux_index_t kPinmuxTestutilsGpioInselPins[kDifGpioNumPins] = { | |
| kTopEarlgreyPinmuxInselIoa0, kTopEarlgreyPinmuxInselIoa1, | |
| kTopEarlgreyPinmuxInselIoa2, kTopEarlgreyPinmuxInselIoa3, | |
| kTopEarlgreyPinmuxInselIoa4, kTopEarlgreyPinmuxInselIoa5, | |
| kTopEarlgreyPinmuxInselIoa6, kTopEarlgreyPinmuxInselIoa7, | |
| kTopEarlgreyPinmuxInselIoa8, kTopEarlgreyPinmuxInselIob6, | |
| kTopEarlgreyPinmuxInselIob7, kTopEarlgreyPinmuxInselIob8, | |
| kTopEarlgreyPinmuxInselIob9, kTopEarlgreyPinmuxInselIob10, | |
| kTopEarlgreyPinmuxInselIob11, kTopEarlgreyPinmuxInselIob12, | |
| kTopEarlgreyPinmuxInselIoc9, kTopEarlgreyPinmuxInselIoc10, | |
| kTopEarlgreyPinmuxInselIoc11, kTopEarlgreyPinmuxInselIoc12, | |
| kTopEarlgreyPinmuxInselIor0, kTopEarlgreyPinmuxInselIor1, | |
| kTopEarlgreyPinmuxInselIor2, kTopEarlgreyPinmuxInselIor3, | |
| kTopEarlgreyPinmuxInselIor4, kTopEarlgreyPinmuxInselIor5, | |
| kTopEarlgreyPinmuxInselIor6, kTopEarlgreyPinmuxInselIor7, | |
| kTopEarlgreyPinmuxInselIor10, kTopEarlgreyPinmuxInselIor11, | |
| kTopEarlgreyPinmuxInselIor12, kTopEarlgreyPinmuxInselIor13}; | |
| const dif_pinmux_index_t kPinmuxTestutilsGpioMioOutPins[kDifGpioNumPins] = { | |
| kTopEarlgreyPinmuxMioOutIoa0, kTopEarlgreyPinmuxMioOutIoa1, | |
| kTopEarlgreyPinmuxMioOutIoa2, kTopEarlgreyPinmuxMioOutIoa3, | |
| kTopEarlgreyPinmuxMioOutIoa4, kTopEarlgreyPinmuxMioOutIoa5, | |
| kTopEarlgreyPinmuxMioOutIoa6, kTopEarlgreyPinmuxMioOutIoa7, | |
| kTopEarlgreyPinmuxMioOutIoa8, kTopEarlgreyPinmuxMioOutIob6, | |
| kTopEarlgreyPinmuxMioOutIob7, kTopEarlgreyPinmuxMioOutIob8, | |
| kTopEarlgreyPinmuxMioOutIob9, kTopEarlgreyPinmuxMioOutIob10, | |
| kTopEarlgreyPinmuxMioOutIob11, kTopEarlgreyPinmuxMioOutIob12, | |
| kTopEarlgreyPinmuxMioOutIoc9, kTopEarlgreyPinmuxMioOutIoc10, | |
| kTopEarlgreyPinmuxMioOutIoc11, kTopEarlgreyPinmuxMioOutIoc12, | |
| kTopEarlgreyPinmuxMioOutIor0, kTopEarlgreyPinmuxMioOutIor1, | |
| kTopEarlgreyPinmuxMioOutIor2, kTopEarlgreyPinmuxMioOutIor3, | |
| kTopEarlgreyPinmuxMioOutIor4, kTopEarlgreyPinmuxMioOutIor5, | |
| kTopEarlgreyPinmuxMioOutIor6, kTopEarlgreyPinmuxMioOutIor7, | |
| kTopEarlgreyPinmuxMioOutIor10, kTopEarlgreyPinmuxMioOutIor11, | |
| kTopEarlgreyPinmuxMioOutIor12, kTopEarlgreyPinmuxMioOutIor13}; | |
| uint32_t pinmux_testutils_get_testable_gpios_mask(void) { | |
| if (kDeviceType == kDeviceFpgaCw310) { | |
| // Only IOA2 to IOA8 are available for use as GPIOs. | |
| return 0x1fc; | |
| } else { | |
| return 0xffffffff; | |
| } | |
| } | |
| uint32_t pinmux_testutils_read_strap_pin(dif_pinmux_t *pinmux, dif_gpio_t *gpio, | |
| dif_gpio_pin_t io, | |
| top_earlgrey_muxed_pads_t pad) { | |
| // Turn off the pull enable on the pad and read the IO. | |
| dif_pinmux_pad_attr_t attr = {.flags = 0}; | |
| dif_pinmux_pad_attr_t attr_out; | |
| CHECK_DIF_OK(dif_pinmux_pad_write_attrs(pinmux, pad, kDifPinmuxPadKindMio, | |
| attr, &attr_out)); | |
| bool state; | |
| // The value read is unmodified by the internal pull resistors and represents | |
| // the the upper bit of the 4 possible states [Strong0, Weak0, Weak1, | |
| // Strong1]. | |
| CHECK_DIF_OK(dif_gpio_read(gpio, io, &state)); | |
| uint32_t result = state ? 2 : 0; | |
| // Based on the previous read, enable the opposite pull resistor. If the | |
| // external signal is weak, the internal pull resistor will win; if the | |
| // external signal is strong, the external value will win. | |
| attr.flags = kDifPinmuxPadAttrPullResistorEnable | | |
| (state ? 0 : kDifPinmuxPadAttrPullResistorUp); | |
| CHECK_DIF_OK(dif_pinmux_pad_write_attrs(pinmux, pad, kDifPinmuxPadKindMio, | |
| attr, &attr_out)); | |
| // Combine the result of the contest between the external signal in internal | |
| // pull resistors. This represents the lower bit of the 4 possible states. | |
| CHECK_DIF_OK(dif_gpio_read(gpio, io, &state)); | |
| result += state ? 1 : 0; | |
| return result; | |
| } | |
| uint32_t pinmux_testutils_read_straps(dif_pinmux_t *pinmux, dif_gpio_t *gpio) { | |
| uint32_t strap = 0; | |
| strap |= pinmux_testutils_read_strap_pin(pinmux, gpio, 22, | |
| kTopEarlgreyMuxedPadsIoc0); | |
| strap |= pinmux_testutils_read_strap_pin(pinmux, gpio, 23, | |
| kTopEarlgreyMuxedPadsIoc1) | |
| << 2; | |
| strap |= pinmux_testutils_read_strap_pin(pinmux, gpio, 24, | |
| kTopEarlgreyMuxedPadsIoc2) | |
| << 4; | |
| return strap; | |
| } | |
| void pinmux_testutils_configure_pads(const dif_pinmux_t *pinmux, | |
| const pinmux_pad_attributes_t *attrs, | |
| size_t num_attrs) { | |
| for (size_t i = 0; i < num_attrs; ++i) { | |
| dif_pinmux_pad_attr_t desired_attr, actual_attr; | |
| CHECK_DIF_OK(dif_pinmux_pad_get_attrs(pinmux, attrs[i].pad, attrs[i].kind, | |
| &desired_attr)); | |
| desired_attr.flags = attrs[i].flags; | |
| CHECK_DIF_OK(dif_pinmux_pad_write_attrs(pinmux, attrs[i].pad, attrs[i].kind, | |
| desired_attr, &actual_attr)); | |
| } | |
| } |