The i.MX95 EVK features an M.2 Key E slot, typically used for WiFi/BT combo cards. While plugging in a module is straightforward, understanding how the PCIe link actually comes up require diving into hardware signals, firmware initialization, and software enumeration.
In this blog, we will: -
1. Examine the M.2 Key E physical connector and identify PCIe signals on it.
2. Understand what those PCIe signals do and why are they needed?
3. What could be the possible routes while debugging PCIe in a system?
Introduction
It is worth mentioning that M.2 Key E is not always used for PCIe. Rather it also supports other interfaces like USB 2.0, UART, SDIO. Our focus will specifically be on PCIe.
This blog assumes that you have a basic understanding of PCIe.
What is PCIe?
Why is it used?
What is a link and lane?
among other details. For the uninitiated, feel free to pause here and explore the web to get a basic understanding before eventually coming back to this blog. One of the links that prove to be resourceful yet crisp:-
Microsoft PowerPoint - 03-05_-_Winkles_-_PCI_Express_Basics
At this point, if you have physical access to the board, feel free to inspect and look at the M.2 Key E PCIe slot. M.2 keys are essential notches on connectors. It looks something like this: -
M.2 Key E slotM.2 Key E slot
Figure-1
There are several M.2 key types that support PCIe, each designed for different use cases. Some of them are: -
Slot type Common-uses Form Factor
Key M :- NVMe SSDs (supports x4) 2280, 22110,2260,2242,2230
Key B :- SATA, cellular modems (supports x2) 2242,2260, 2280
Key E :- Wifi/BT modules (supports x1) 2230, 1630, 3030
Key A :- Wifi/BT (supports x2) 2230, 1630, 3030
These slots come in different form factors as you can see from the above list. The form factor refers to the width and length of the module. Each M.2 size uses a code that shows these dimensions. For example, “2280” means the module is 22 mm wide and 80 mm long. Similarly, "22110" means 22mm wide and 110mm long.
On i.MX 95 evaluation kits and carrier boards, the M.2 Key E slot typically uses the 2230 form factor.
For educational purpose we only refer to an illustration of M.2 connector from iMX95EVK schematic. Readers may obtain the schematic/design files from the NXP's official website.
The below image shows the M.2 Key E connector and the PCIe signals coming in and out of the iMX95EVK board's M.2 key E header.
M.2 Key E schematicM.2 Key E schematic
Figure-2
The M.2 Key‑E slot is the Wi‑Fi/BT connector, and the PCIe-related nets exposed there include the PCIe differential data pair(s), reference clock, reset, clock request, and wake signals.
M.2 Key E signals
For PCIe bring‑up, the most important signals on this slot are:
1. PCIE1_TX0_P, PCIE1_TX0_N → slot PET_P0, PET_N0
Direction - Output from i.MX95 RC to Endpoint module
PCIe transmit pair from host/root complex. With these signals, the root complex (i.MX95 side) transmits toward the Wi‑Fi module
In the Image above that shows M.2 Key E connector, please observe that there's a capacitance of 0.22uF on each of the lines of a TX differential pair.
As per the PCIe specification, there are 3 main reasons to place coupling capacitors on the Tx lines:
a. DC Isolation: -
Since the differential signal is recovered by measuring the potential difference between the pairs, the AC caps remove any DC offset induced on the signal when a driver and receiver run at different voltages. This factors out any ground offset between a motherboard and a PCIe card.
b. Detecting plug/unplug events: -
Some PCIe endpoints are hot-swappable. The capacitors on a Tx pair allow the driver to use an RC time constant to detect the presence of a receiver at the end of a lane.
c. Detecting Lane count: -
In components that have multiple PCIe lanes, the plug/unplug events will occur across each lane, and the number of triggered lanes can be sensed by the PCIe-capable device.
Note - The capacitors also need to pass as much signal as possible up to high frequencies, meaning they should have high enough self-resonant frequency.
2. PCIE1_RX0_P, PCIE1_RX0_N → slot PER_P0, PER_N0
Direction - Input to i.MX95 RC from module
PCIe receive pair to host/root complex. With these signals, the root complex (i.MX95 side) receives from the Wi‑Fi module.
TX0_P/N and RX0_P/N are the high-speed differential PCIe lane signals. These are the lines that carry:
a. LTSSM training traffic
b. configuration transactions
c. memory reads/writes
d. Interrupts as PCIe messages (MSI/MSIX)
In a hardware bring-up, if these pairs are swapped or there's a missing AC coupling, the link will not train properly.
As seen in Figure-2, The Key‑E connector exposes a second PCIe lane group (PET_P1/N1, PER_P1/N1, REFCLK_P1/N1, PERST1, CLKREQ1, PEWAKE1), but for a normal M.2 Wi‑Fi module usually x1 PCIe is used.
3. PCIE_WIFI_CLK_P, PCIE_WIFI_CLK_N / PCIE1_CLKIN_P, PCIE1_CLKIN_N → slot REFCLK_P0, REFCLK_N0
Direction - Clock output toward module
PCIe needs a stable, low-jitter reference clock. The slot exposes REFCLK sourced from the board PCIe clock path.
In PCIe, mainly there are 2 types of clocking:-
a. Common reference clock - Both link partners share exact same 100MHz clock source
Figure-3Figure-3
b. Independent reference clock - Link partners using different 100MHz clock source
Figure-4Figure-4
iMX95EVK by default uses Common reference clock, meaning that the host[iMX95EVK] and the PCIe endpoint connected to it would be sharing the 100MHz clock source.
In the schematic image, PCIE_WIFI_CLK_P and PCIE_WIFI_CLK_N [100MHz] going towards the M.2 Key E slot are coming from the Si5332 clock generator on the board.
In other words, it can be said that - the PCIe M.2 Key.E Wi-Fi module expects the iMX95EVK board to provide it the 100MHz reference clock.
PCIe uses CDR (Clock Data Recovery), in which the clock is embedded in the data stream itself, not sent as a separate signal. So PCIe TX/RX pairs carry: -
a. Data (encoded using 8b/10b or 128b/130b)
b. Clock (embedded in signal transitions)
Note: - CDR needs a reference frequency to lock onto. Both link partners must operate at the same base frequency, otherwise bit errors and even link failures can occur.
Standard Ref clock used - 100MHz Differential clock (+-300ppm)
Question - why not just send a separate clock signal instead of CDR?
- That's because like in the older parallel buses, there would be clock skew issues at high speeds. More pins would be required. With CDR, fewer signals are used (just RX/TX pairs) and the clock travels with the data itself.
Figure-5Figure-5
The image above indicates that the PCIe link partners have PLL that uses REFCLK to generate the internal clocks. Each device uses their respective PLLs to generate higher-frequency clocks:
what does it mean? - PLL uses REFCLK to generate internal clocks
- A PLL is a frequency multiplier circuit that takes a low-frequency input (reference clock) and generates a higher-frequency output that's phase-locked (synchronized) to the input.
Figure-6Figure-6
Figure-7Figure-7
Figure-8Figure-8
Figure-9Figure-9
Question - Why use PLL internally instead of sending High-Frequency clock directly ?
- Following are the reasons: -
a. Routing a high frequency clock directly from host's main oscillator to PCIe slot would cause signal degradation, EMI and power loss.
b. Difficult to route on the PCB.
c. Using PLLs internally is much cheaper.
d. At multi-GHz speeds, tiny deviation in clock timing can lead to data transmission errors. The PLL's loop filter continuously aligns the phase of the high-speed output signal with the reference clock.
Question - If CDR embeds clock in data transmission, then why is Reference clock provided as a separate signal?
Figure-10Figure-10
As can be seen from the above image, CDR doesn't work in isolation. It extracts clock from data, but it needs to know what frequency to look for. Without a reference clock, CDR sees transitions in data stream, but it doesn't know if it's 2.5, 5.0, 8.0GHz or some other frequency for that matter.
Imagine trying to catch a ball: Without REFCLK (no reference): - You don't know if the ball is coming at 10 mph or 100 mph
Question - What would happen if the link partners have even minimal difference in reference clock?
- As per the specification, small differences are tolerable (±300 ppm), but larger differences cause link failure.
±300 ppm means:
100 MHz ± 300 ppm = 100 MHz ± 0.03 MHz = 99.97 MHz to 100.03 MHz
For 2.5 GHz (after ×25 multiplication): 2.5 GHz ± 300 ppm = 2.5 GHz ± 0.75 MHz = 2,499.25 MHz to 2,500.75 MHz
During link training, devices exchange training sequences:
Transmitter sends: 10101010... at 2.5000 GHz
Receiver expects: 10101010... at 2.5025 GHz
The receiver's CDR tries to lock but phase keeps drifting.
-Bit errors accumulate
-Link training timeout
-Link stays in "Detect" state
This ultimately results in PCIe link failures.
4. PCIE1_RST_B -> slot PERST0 (active low reset) - PCIe reset
Direction - Output from host to module
It is PCIe reset to the endpoint. It is like host indicating to EP - "now you may start PCIe"
The endpoint card should stay in reset until:
Then the host de-asserts PERST# and the endpoint begins PCIe initialization.
The firmware/software driver sequencing is wrong if:
And then if you go on debugging such a board, you notice reference clock and power rails are fine at the moment of probing but somehow PCIe never enumerates. So, timing of PERST# signal is of utmost importance.
|
Event |
Symptom |
|
PERST# never deasserts |
Card stays invisible |
|
PERST# deasserts too early |
Intermittent or no enumeration |
5. WiFi_CLKREQ_B / PCIE1_IMX_CLKREQ_B / slot CLKREQ0 - PCIe clock request
Direction - Open-drain Bi-directional
In PCIe, CLKREQ# is an active-low bidirectional, open drain sideband signal which can be used by root complex and endpoint. It allows multiple devices to share a single wire. Devices can pull the CLKREQ# low to signal state changes and release it to floating state, allowing an external resistance to pull it high.
Let's try to understand what open-drain bidirectional signal means:
An open-drain output can do only two things:
It cannot actively drive the line high by itself.
So, if you want the line to be high when nobody is pulling it low, you must provide a pull-up resistor to a supply rail (for example 3.3 V)
Hence electrically the line becomes: -
No one pulls low --> pull-up resistor makes line HIGH
Any device pulls low --> line becomes LOW
Bi-directional open-drain means: -
Both connected devices:
So it is a shared wire where both sides participate.
The circuit looks something like this: -
Figure-11Figure-11
One can observe from the above circuit diagram that the host-side PCIE1_IMX_CLKREQ_B and the module-side WiFi_CLKREQ_B are tied together through 0 Ohm links onto a single shared net.
A 10K Ohms resistance to pull the line high to VDD_3V3 when nobody is driving it low.
Here bi-directional means: -
For PCIe CLKREQ#, that means the two ends of the link (upstream port / downstream port) are connected to the same physical signal, and either side can request “clock” by pulling it low.
Why is CLKREQ# used in PCIe?
It is used by link partners to request reference clock for power state coordination. What this means is - with the help of this signal, power consumption can be managed by allowing either link partners to request, start or stop the 100MHz reference clock.
Root complex monitors the CLKREQ# pin to detect when an endpoint is requesting a clock to wake up the link. In some SoC designs, the host can also drive this pin to control clock gating or to indicate an exit from low-power state.
Endpoint pulls CLKREQ# low to request that the host resume providing the reference clock so the device can transition from a sleep state back to active data transmission.
This signal is essential for the software to enable the ASPM/low-power states. If it is not routed on the board correctly: -
Question - What happens if the CLKREQ# signal was implemented as normal push-pull instead of open-drain Bi-directional signal?
- one side could accidentally drive HIGH while the other drove LOW, creating contention and a direct short circuit between the power supply and ground. Open drain avoids that because nobody ever actively drives HIGH. If either side wants LOW, it simply sinks the line. Otherwise, both sides release the line, and the pull-up makes it HIGH.
Question - Why active-low and why not active-high?
- In a shared open-drain system, LOW is the easy state to actively assert.
Open-drain hardware naturally pulls downward to ground using an NMOS / sink path, while HIGH is simply the released state created by the pull-up resistor. So active-low is the most natural form for such a signal
What exactly happens on the wire in different cases ?
Considering an open-drain bi-directional CLKREQ# has pull-up resistance to 3.3V
Case-A: No link partner needs the clock
RC releases the line
EP releases the line
pull-up resistance pulls the wire HIGH
results in CLKREQ#=1 de-asserted
Case-B: Endpoint needs the clock
endpoint pulls wire LOW
host may still be released
result: wire goes LOW anyway
both sides read CLKREQ# = 0 (asserted)
Case-C Host needs the clock
host pulls wire LOW
endpoint may be released
result: wire goes LOW
both sides see request asserted
Case-D Both sides need the clock
both may pull LOW simultaneously
no conflict, because both are only sinking the line
line stays LOW safely
6. WL_PCIE1_WAKEOUT_B / slot PEWAKE0 - PCIe wake
Direction - Input to host from module
It is an active-low sideband signal to wake up the host from sleep or low-power state. The hosts go to deep sleep states to conserve power. During this time, the main PCIe clock and data lanes are often completely powered down or disabled.
This Wake# signal in M.2 Key E provides a direct out-of-band communication line to alert the host. The M.2 card detects an event that requires the host attention and then pulls the WAKE# low. Upon detecting this transition, the host powers up the necessary rails and re-enable the PCIe clock to fully resume the system.
Some use-cases:-
a. Wake on Wireless LAN - allows the host to wake up if a Wi-Fi card detects specific network traffic
b. Bluetooth Device connection - allows the host to wake up when a paired Bluetooth device attempts to connect
7. M2_KE_PWREN and M2_KE_PD_B
Direction - Output from PCAL IO Expander to load switch
M2_KE_PWREN - M.2 Key E Power Enable
It is a board control signal used to enable power to the Key‑E slot / module power path.
VCC_KE_3V3 is disabled by default to reduce transient power consumption so this control signal is used to turn that power on when the platform is ready.
If M2_KE_PWREN is not asserted, the Wi‑Fi module may look completely dead even if PCIe routing is perfect, because the slot power rail may still be off
M2_KE_PD_B - M.2 Key‑E Power-Down, active low
if M2_KE_PD_B is driven LOW, the board is intentionally telling the module to stay in a disabled / power-down type condition, and if M2_KE_PD_B is HIGH, the module is allowed to operate normally.
PD_B is different from PWREN:
The PCAL IO Expander is controlled via I2C and used as one of the board's GPIO control.
If M2_KE_PWREN is not implemented correctly, you may see:
If M2_KE_PD_B is incorrect, you may see:
Note: - As seen in the Image, The Key‑E connector exposes a second PCIe lane group (PET_P1/N1, PER_P1/N1, REFCLK_P1/N1, PERST1, CLKREQ1, PEWAKE1), but for a normal M.2 Wi‑Fi module usually x1 PCIe is used.
Debugging lens
Assuming, you have connected the PCIe M.2 Key E Wi-Fi card such as this one - AW693 on iMX95EVK. And booted it up with the latest Linux BSP. You notice that on 'lspci', there is no respective device entry for this M.2 module. There are 2 routes of debugging from this point onwards, assuming that the PCIe card is not faulty:-
Hardware perspective: -
Software perspective: -
So, one of the intuitive debugging steps can be: -
1. Observe link training in the software by checking: -
The i.MX95 EVK features an M.2 Key E slot, typically used for WiFi/BT combo cards. While plugging in a module is straightforward, understanding how the PCIe link actually comes up require diving into hardware signals, firmware initialization, and software enumeration.
In this blog, we will: -
1. Examine the M.2 Key E physical connector and identify PCIe signals on it.
2. Understand what those PCIe signals do and why are they needed?
3. What could be the possible routes while debugging PCIe in a system?