| /* |
| * 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; |
| } |
| // Mux ISP wrapper |
| 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)); |
| |
| 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; |
| } |