| /* | |
| * Copyright 2023 Google LLC | |
| * Copyright lowRISC contributors | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include "sw/device/lib/testing/pinmux_testutils.h" | |
| #include "hw/top_matcha/sw/autogen/top_matcha.h" | |
| #include "sw/device/lib/base/macros.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" | |
| // NB: Keep these definitions aligned with | |
| // hw/top_matcha/rtl/chip_matcha_verilator.sv and | |
| // hw/top_matcha/dv/env/chip_if.sv | |
| const dif_pinmux_index_t kPinmuxTestutilsGpioInselPins[kDifGpioNumPins] = { | |
| kTopMatchaPinmuxInselIoa0, kTopMatchaPinmuxInselIoa1, | |
| kTopMatchaPinmuxInselIoa2, kTopMatchaPinmuxInselIoa3, | |
| kTopMatchaPinmuxInselIoa4, kTopMatchaPinmuxInselIoa5, | |
| kTopMatchaPinmuxInselIoa6, kTopMatchaPinmuxInselIoa7, | |
| kTopMatchaPinmuxInselIoa8, kTopMatchaPinmuxInselIob0, | |
| kTopMatchaPinmuxInselIob1, kTopMatchaPinmuxInselIob2, | |
| kTopMatchaPinmuxInselIob3, kTopMatchaPinmuxInselIob4, | |
| kTopMatchaPinmuxInselIob5, kTopMatchaPinmuxInselIob6, | |
| kTopMatchaPinmuxInselIob7, kTopMatchaPinmuxInselIob8, | |
| kTopMatchaPinmuxInselIob10, kTopMatchaPinmuxInselIob11, | |
| kTopMatchaPinmuxInselIob12, kTopMatchaPinmuxInselIoc6, | |
| kTopMatchaPinmuxInselIoc0, kTopMatchaPinmuxInselIoc1, | |
| kTopMatchaPinmuxInselIoc2, kTopMatchaPinmuxInselIoc7, | |
| kTopMatchaPinmuxInselIoc9, kTopMatchaPinmuxInselIod0, | |
| kTopMatchaPinmuxInselIor6, kTopMatchaPinmuxInselIor7, | |
| kTopMatchaPinmuxInselIod1, kTopMatchaPinmuxInselIor10, | |
| }; | |
| const dif_pinmux_index_t kPinmuxTestutilsGpioMioOutPins[kDifGpioNumPins] = { | |
| kTopMatchaPinmuxMioOutIoa0, kTopMatchaPinmuxMioOutIoa1, | |
| kTopMatchaPinmuxMioOutIoa2, kTopMatchaPinmuxMioOutIoa3, | |
| kTopMatchaPinmuxMioOutIoa4, kTopMatchaPinmuxMioOutIoa5, | |
| kTopMatchaPinmuxMioOutIoa6, kTopMatchaPinmuxMioOutIoa7, | |
| kTopMatchaPinmuxMioOutIoa8, kTopMatchaPinmuxMioOutIob0, | |
| kTopMatchaPinmuxMioOutIob1, kTopMatchaPinmuxMioOutIob2, | |
| kTopMatchaPinmuxMioOutIob3, kTopMatchaPinmuxMioOutIob4, | |
| kTopMatchaPinmuxMioOutIob5, kTopMatchaPinmuxMioOutIob6, | |
| kTopMatchaPinmuxMioOutIob7, kTopMatchaPinmuxMioOutIob8, | |
| kTopMatchaPinmuxMioOutIob10, kTopMatchaPinmuxMioOutIob11, | |
| kTopMatchaPinmuxMioOutIob12, kTopMatchaPinmuxMioOutIoc6, | |
| kTopMatchaPinmuxMioOutIoc0, kTopMatchaPinmuxMioOutIoc1, | |
| kTopMatchaPinmuxMioOutIoc2, kTopMatchaPinmuxMioOutIoc7, | |
| kTopMatchaPinmuxMioOutIoc9, kTopMatchaPinmuxMioOutIod0, | |
| kTopMatchaPinmuxMioOutIor6, kTopMatchaPinmuxMioOutIor7, | |
| kTopMatchaPinmuxMioOutIod1, kTopMatchaPinmuxMioOutIor10, | |
| }; | |
| void pinmux_testutils_init(dif_pinmux_t *pinmux) { | |
| for (int i = 0; i < kDifGpioNumPins; ++i) { | |
| dif_pinmux_index_t mio = kPinmuxTestutilsGpioInselPins[i]; | |
| dif_pinmux_index_t gpio = kTopMatchaPinmuxPeripheralInGpioGpio0 + i; | |
| CHECK_DIF_OK(dif_pinmux_input_select(pinmux, gpio, mio)); | |
| } | |
| for (int i = 0; i < kDifGpioNumPins; ++i) { | |
| dif_pinmux_index_t mio = kPinmuxTestutilsGpioMioOutPins[i]; | |
| dif_pinmux_index_t gpio = kTopMatchaPinmuxOutselGpioGpio0 + i; | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, mio, gpio)); | |
| } | |
| // Configure UART0 RX input to connect to MIO pad IOC3 | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInUart0Rx, kTopMatchaPinmuxInselIoc3)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIoc3, | |
| kTopMatchaPinmuxOutselConstantHighZ)); | |
| // Configure UART0 TX output to connect to MIO pad IOC4 | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIoc4, | |
| kTopMatchaPinmuxOutselUart0Tx)); | |
| // 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, kTopMatchaMuxedPadsIoc3, | |
| kDifPinmuxPadKindMio, in_attr, | |
| &out_attr)); | |
| CHECK_DIF_OK(dif_pinmux_pad_write_attrs(pinmux, kTopMatchaMuxedPadsIoc10, | |
| kDifPinmuxPadKindMio, in_attr, | |
| &out_attr)); | |
| }; | |
| // Configure SMC_UART RX input to connect to MIO pad IOC10 | |
| CHECK_DIF_OK(dif_pinmux_input_select(pinmux, | |
| kTopMatchaPinmuxPeripheralInSmcUartRx, | |
| kTopMatchaPinmuxInselIoc10)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIoc10, | |
| kTopMatchaPinmuxOutselConstantHighZ)); | |
| // Configure SMC_UART TX output to connect to MIO pad IOC11 | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIoc11, | |
| kTopMatchaPinmuxOutselSmcUartTx)); | |
| } | |
| uint32_t pinmux_testutils_get_testable_gpios_mask(void) { return 0xffffffff; } | |
| 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)); | |
| } | |
| } | |
| dif_result_t pinmux_testutils_configure_i2s_tx(const dif_pinmux_t *pinmux) { | |
| if (pinmux == NULL) { | |
| return kDifBadArg; | |
| } | |
| // Mux I2S Tx | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIod3, | |
| kTopMatchaPinmuxOutselI2s0TxSclk)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIod4, | |
| kTopMatchaPinmuxOutselI2s0TxWs)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIod5, | |
| kTopMatchaPinmuxOutselI2s0TxSd)); | |
| return kDifOk; | |
| } | |
| dif_result_t pinmux_testutils_configure_i2s_rx(const dif_pinmux_t *pinmux) { | |
| if (pinmux == NULL) { | |
| return kDifBadArg; | |
| } | |
| // Mux I2S Rx | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIod0, | |
| kTopMatchaPinmuxOutselI2s0RxSclk)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIod1, | |
| kTopMatchaPinmuxOutselI2s0RxWs)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInI2s0RxSd, kTopMatchaPinmuxInselIod2)); | |
| return kDifOk; | |
| } | |
| dif_result_t pinmux_testutils_configure_cam_i2c(const dif_pinmux_t *pinmux) { | |
| if (pinmux == NULL) { | |
| return kDifBadArg; | |
| } | |
| // Mux Cam I2C | |
| CHECK_DIF_OK(dif_pinmux_input_select(pinmux, | |
| kTopMatchaPinmuxPeripheralInCamI2cSda, | |
| kTopMatchaPinmuxInselIoa5)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIoa5, | |
| kTopMatchaPinmuxOutselCamI2cSda)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIoa4, | |
| kTopMatchaPinmuxOutselCamI2cScl)); | |
| CHECK_DIF_OK(dif_pinmux_input_select(pinmux, | |
| kTopMatchaPinmuxPeripheralInCamI2cScl, | |
| kTopMatchaPinmuxInselIoa4)); | |
| return kDifOk; | |
| } | |
| dif_result_t pinmux_testutils_configure_isp_wrapper( | |
| const dif_pinmux_t *pinmux) { | |
| if (pinmux == NULL) { | |
| return kDifBadArg; | |
| } | |
| #if defined(MATCHA_SPARROW) | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInVideoAudioWrapperSData0, | |
| kTopMatchaPinmuxInselIob0)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInVideoAudioWrapperSData1, | |
| kTopMatchaPinmuxInselIob1)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInVideoAudioWrapperSData2, | |
| kTopMatchaPinmuxInselIob2)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInVideoAudioWrapperSData3, | |
| kTopMatchaPinmuxInselIob3)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInVideoAudioWrapperSData4, | |
| kTopMatchaPinmuxInselIob4)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInVideoAudioWrapperSData5, | |
| kTopMatchaPinmuxInselIob5)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInVideoAudioWrapperSData6, | |
| kTopMatchaPinmuxInselIob6)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInVideoAudioWrapperSData7, | |
| kTopMatchaPinmuxInselIob7)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInVideoAudioWrapperSVsync, | |
| kTopMatchaPinmuxInselIob9)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInVideoAudioWrapperSHsync, | |
| kTopMatchaPinmuxInselIob8)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInVsiCtlWrapperIspSclk, | |
| kTopMatchaPinmuxInselIob10)); | |
| #else | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInIspWrapperSData0, | |
| kTopMatchaPinmuxInselIob0)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInIspWrapperSData1, | |
| kTopMatchaPinmuxInselIob1)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInIspWrapperSData2, | |
| kTopMatchaPinmuxInselIob2)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInIspWrapperSData3, | |
| kTopMatchaPinmuxInselIob3)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInIspWrapperSData4, | |
| kTopMatchaPinmuxInselIob4)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInIspWrapperSData5, | |
| kTopMatchaPinmuxInselIob5)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInIspWrapperSData6, | |
| kTopMatchaPinmuxInselIob6)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInIspWrapperSData7, | |
| kTopMatchaPinmuxInselIob7)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInIspWrapperSVsync, | |
| kTopMatchaPinmuxInselIoa2)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInIspWrapperSHsync, | |
| kTopMatchaPinmuxInselIoa3)); | |
| CHECK_DIF_OK(dif_pinmux_input_select( | |
| pinmux, kTopMatchaPinmuxPeripheralInIspWrapperSPclk, | |
| kTopMatchaPinmuxInselIob8)); | |
| #endif | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIoa2, | |
| kTopMatchaPinmuxOutselConstantHighZ)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIoa3, | |
| kTopMatchaPinmuxOutselConstantHighZ)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIob0, | |
| kTopMatchaPinmuxOutselConstantHighZ)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIob1, | |
| kTopMatchaPinmuxOutselConstantHighZ)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIob2, | |
| kTopMatchaPinmuxOutselConstantHighZ)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIob3, | |
| kTopMatchaPinmuxOutselConstantHighZ)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIob4, | |
| kTopMatchaPinmuxOutselConstantHighZ)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIob5, | |
| kTopMatchaPinmuxOutselConstantHighZ)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIob6, | |
| kTopMatchaPinmuxOutselConstantHighZ)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIob7, | |
| kTopMatchaPinmuxOutselConstantHighZ)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIob8, | |
| kTopMatchaPinmuxOutselConstantHighZ)); | |
| return kDifOk; | |
| } | |
| dif_result_t pinmux_testutils_configure_cam_ctrl(const dif_pinmux_t *pinmux) { | |
| if (pinmux == NULL) { | |
| return kDifBadArg; | |
| } | |
| // Mux cam CTRL / TRIG | |
| CHECK_DIF_OK( | |
| dif_pinmux_input_select(pinmux, kTopMatchaPinmuxPeripheralInCamCtrlCamInt, | |
| kTopMatchaPinmuxInselIoa6)); | |
| CHECK_DIF_OK(dif_pinmux_output_select(pinmux, kTopMatchaPinmuxMioOutIoa7, | |
| kTopMatchaPinmuxOutselCamCtrlCamTrig)); | |
| return kDifOk; | |
| } |