2382635_en-US

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

2382635_en-US

2382635_en-US

Understanding the PCIe M.2 Key E of iMX95EVK

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 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 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-3Figure-3

b. Independent reference clock - Link partners using different 100MHz clock source


Figure-4Figure-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-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:

  • Gen1: 2.5 GT/s (Giga-transfers/second)
  • Gen2: 5.0 GT/s
  • Gen3: 8.0 GT/s
  • Gen4: 16.0 GT/s

 

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-6Figure-6Figure-7Figure-7Figure-7Figure-8Figure-8Figure-8Figure-9Figure-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-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:

  • 3.3V rail is valid
  • REFCLK is stable
  • host side PCIe controller is ready


Then the host de-asserts
PERST# and the endpoint begins PCIe initialization.

The firmware/software driver sequencing is wrong if:
 

  • reset may be released too early
  • endpoint may boot before clock/power are stable
  • endpoint may remain held in reset
  • host may start LTSSM while endpoint is still not alive


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:

  1. pull the line low (drive a logic 0), or
  2. release the line and become high-impedance (Hi-Z).
     

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:

  • can observe/read the line state, and
  • can also assert the line by pulling it low.

So it is a shared wire where both sides participate.

The circuit looks something like this: -
 
Figure-11Figure-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: -
 

  • the SoC side can observe the state of the shared line and can also assert it by pulling LOW,
  • the Wi‑Fi endpoint side can also observe the same shared line and can also assert it by pulling LOW.


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: -
 

  • link may come up initially but fail in suspend/resume
  • L1/L1SS transitions may break
  • the module may disappear after idle periods
  • Wi‑Fi may fail after runtime PM kicks in




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:

  • PWREN is about supplying / enabling slot power
  • PD_B is about telling the module whether it should remain powered-down or active

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:

  • no 3.3 V at the socket
  • no current draw from the module
  • no PCIe enumeration

If M2_KE_PD_B is incorrect, you may see:

  • slot rail present, but module still appears dead or partially inactive
  • no PCIe link-up even though REFCLK and PERST# seem okay
  • confusing behavior where power looks present, but the module is effectively held off


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: -

  • Is VCC_KE_3V3 present and stable?
  • Are the PCIe pairs routed correctly and with the intended controlled impedance?
  • Is REFCLK present at the module?
  • Is PERST# timing sane?
  • Is CLKREQ# behaving or stuck?
  • Is the module actually powered/enabled versus held in M2_KE_PD_B/power control state?


 Software perspective: -

  • Is the PCIe RC node enabled in firmware/device tree?
  • Is the controller coming out of reset?
  • Is LTSSM starting?
  • Does the kernel ever detect link up?
  • Does configuration space read succeed?
  • Is ASPM/clock PM breaking early bring-up?


So, one of the intuitive debugging steps can be: -

         1. Observe link training in the software by checking: -

  • kernel logs
  • PCIe controller status
  • LTSSM state if available
  • whether device appears in config space

    2. Check if the module gets
    3.3V at the slot or not?

    3. 
    Check whether PERST# is initially asserted low and later released high.
    4. Check whether the 100 MHz PCIe reference clock is present at the slot.
    5. Observe CLKREQ# behavior before/after reset release.
    6. Only after you have verified that the PCIe link is stable, move on to debug ASPM, suspend/resume or wake handling logic.


    There's a reason we start with checking the software first as it doesn't involve physical efforts of connecting probes to the test-points and setting up a scope for it. Debugging the software by putting logs or observing PCIe initialization in 'dmesg' is the quickest way to check what's wrong. If you do not get a clue, then you should definitely consider the hardware perspective.


    That's all for today. This was a rather lengthy blog but rightly so. This will help to build up an understanding of how PCIe cards work from a perspective of embedded software engineer so that we move on to understand how it is brought up via firmware/software. Feel free to DM in case of any doubts/comments.

    Until next time!



 

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?

IMX95EVK
Tags (1)
No ratings
Version history
Last update:
18m ago
Updated by: