Hello @christopherlajoie ,
Thank you for the heads-up regarding your vacation. That gives me sufficient time to prepare a detailed response for you.
Thank you for your update and detailed observations.
Regarding the level shifters for MDIO and MDC signals, please refer to the attached image for the location of U14 (MDIO) and U22 (MDC) on the board (the yellow ones). You can probe their behavior using an oscilloscope to verify signal integrity. I agree that if the board is new, the likelihood of damage is low, unless there is a manufacturing defect.

As for your question about the setup time: on the SMI interface, MDIO is sampled on the next rising edge of MDC. This means that the setup time requirement applies to the data being valid before that edge, not necessarily before the current edge shown in your capture. So the setup time requirement shall be met easily.
To validate the behavior, I ran the lwip_s32k148 example on the S32K148EVB-Q176 board using the following setup:
Software:
- S32 Design Studio v3.5
- SDK: s32sdk_s32k1xx_rtm_401
Hardware:
- TJA1103-SDBR daughter board in rev-RMII mode
- PHY address: 0x02
- No pull-up resistor on MDIO line
I added a PHY driver and defined the PHY entry.

A FreeRTOS task was created to blink an LED and periodically read two PHY registers using PHY_Read(). I kept the MSCR settings at default, resulting in:
- MDC frequency: ~2.39 MHz
- Hold time: 20 ns (MSCR.HOLDTIME = 0x0)
- Hold time: 170 ns (MSCR.HOLDTIME = 0x7 - set by debugger)

I tried resetting the PHY, but it turned out to be unnecessary — so I commented out the related code.
Signals were observed on resistors R46 (MDIO) and R38 (MDC). Below is a waveform capture of a complete Clause 22 read transaction:
- Target PHY: 0x02
- Read register: 0x03
- Data returned by TJA1103: 0xB013 (between cursors)

Please try to capture a full Clause 22 transaction on your oscilloscope for comparison. The waveform should resemble the timing diagram described on Management Data Input/Output - Wikipedia
I'm not able to review your entire code (but thank you for sharing it anyway). However, please note that the first parameter of PHY_Read (as well as other PHY functions) is not the PHY address, but the index of the PHY entry — so it should be 0 or PHY_INSTANCE_0. The PHY address must be set within the PHY entry itself.
Best regards,
Pavel