PWM Frequency Configuration#

Applies to Jetson Orin Nano, Jetson Orin NX, Jetson AGX Orin (Tegra234), and Jetson AGX Thor (Tegra264).

This topic describes how to choose a pulse width modulation (PWM) output frequency on NVIDIA® Jetson™ platforms with the on-SoC PWM controllers exposed by the pwm-tegra driver (drivers/pwm/pwm-tegra.c), and how to express that choice in the kernel device tree (DTS).

For Tegra234, the set of PWM controllers exposed at the Kernel level depends on the Jetson module. Some on-SoC PWMs are reserved as voltage-regulator inputs (PWM_VID) and are not available to Linux:

  • On the Jetson AGX Orin series, PWM2 (GPU_PWM_VID), PWM4 (SOC_PWM_VID), PWM6 (CPU_PWM_VID), and PWM7 (CV_PWM_VID) are reserved. Four PWM controllers remain available at the Kernel level: pwm@3280000 (PWM1), pwm@32a0000 (PWM3), pwm@32c0000 (PWM5), and pwm@32f0000 (PWM8).

  • On the Jetson Orin NX and Jetson Orin Nano series, PWM4 (SOC_PWM_VID) and PWM6 (CPU_PWM_VID) are reserved. Six PWM controllers remain available at the Kernel level: pwm@3280000 (PWM1), pwm@3290000 (PWM2), pwm@32a0000 (PWM3), pwm@32c0000 (PWM5), pwm@32e0000 (PWM7), and pwm@32f0000 (PWM8).

For Tegra264, the set of PWM controllers exposed at the Kernel level depends on the Jetson module. Some on-SoC PWMs are reserved as voltage-regulator inputs (PWM_VID) and are not available to Linux:

  • On the Jetson AGX Thor series, PWM1 (CPU_PWM_VID), PWM6 (MSS_PWM_VID), PWM7 (GPU_PWM_VID), and PWM8 (SOC_PWM_VID) are reserved. Six PWM controllers remain available at the Kernel level: pwm@810c5e0000 (PWM2), pwm@810c5f0000 (PWM3), pwm@c6a0000 (PWM4), pwm@810c600000 (PWM5), pwm@810c610000 (PWM9), and pwm@810c620000 (PWM10).

The pwm-tegra driver binds to Tegra234 through the "nvidia,tegra194-pwm" fallback (tegra194_pwm_soc data) and binds to Tegra264 directly through "nvidia,tegra264-pwm" (tegra264_pwm_soc data).

How PWM Output Frequency Is Generated#

The Tegra PWM controller produces its output frequency by dividing the source clock rate by two cascaded dividers:

f_out = clk_rate / ((1 + PWM_DEPTH) * (1 + PFM))
  • clk_rate is the rate of the source clock feeding the controller (a per-controller clock such as TEGRA234_CLK_PWM5 or TEGRA264_CLK_PWM3).

  • PWM_DEPTH is a per-controller divider. Its bit width and whether it can be programmed from the device tree depend on the SoC. The driver default is 255.

  • PFM is a per-controller divider programmed at runtime by the driver each time a new period is applied.

The PWM_DEPTH and PFM field widths differ between Tegra234 and Tegra264:

SoC

PWM_DEPTH Bits

PFM Bits

Tegra234

8

13

Tegra264

16

16

Knobs Available to the Developer#

To target a specific PWM output frequency, three knobs cooperate.

Source Clock Parent#

The parent of each PWM clock is requested by the kernel via the assigned-clock-parents property on the PWM node. The list of permitted parents and their maximum rates can be inspected at runtime via the following commands:

$ cat /sys/kernel/debug/clk/<clk>/clk_possible_parents
$ cat /sys/kernel/debug/bpmp/debug/clk/<parent>/max_rate

For Tegra234 PWM1, PWM2, PWM3, PWM5, PWM7, PWM8, the permitted parents are TEGRA234_CLK_PLLP_OUT0 (~408 MHz), TEGRA234_CLK_CLK_M (~19.2 MHz), and TEGRA234_CLK_CLK_32K (32768 Hz). The exact subset exposed at the Kernel level depends on the module, as noted earlier.

For Tegra264 PWM2, PWM3, PWM5, PWM9, PWM10, the permitted parents are TEGRA264_CLK_PLLP_OUT0 (~202.5 MHz) and TEGRA264_CLK_OSC (~27 MHz). For Tegra264 PWM4 (AON), the permitted parents are TEGRA264_CLK_PLL_AON (~600 MHz) and TEGRA264_CLK_OSC (~27 MHz).

The driver forces the source clock to its maximum supported rate at probe time (drivers/pwm/pwm-tegra.c, tegra_pwm_probe).

nvidia,pwm-depth Property#

Increasing nvidia,pwm-depth improves duty-cycle resolution but raises the minimum reachable period. Decreasing it lowers the minimum reachable period but reduces duty-cycle resolution.

  • On Tegra234, nvidia,pwm-depth is not programmable. The silicon hard-codes it at 255; setting nvidia,pwm-depth to a non-default value only causes the driver to compute incorrect periods and duty cycles.

  • On Tegra264, nvidia,pwm-depth is configurable from the device tree via nvidia,pwm-depth in the range 0..65535. The driver default remains 255.

PWM Period#

The user-facing period (in nanoseconds) is written to /sys/class/pwm/pwmchipN/pwmM/period and is bounded by the following:

  • A minimum period set at probe time by the driver from the resolved clk_rate and pwm_depth, calculated as min_period_ns = NSEC_PER_SEC / (clk_rate / (1 + pwm_depth)) + 1.

  • A maximum period determined by the SCALE field width (13 bits on Tegra234, 16 bits on Tegra264). If the computed PFM exceeds the field’s maximum value (8191 on Tegra234 or 65535 on Tegra264), the driver returns -EINVAL.

Reference Table: Reachable Period Range (Tegra234)#

With nvidia,pwm-depth left at the default 255 and SCALE width set to 13, the reachable period range is then computed as follows:

  • period_min_ns = (1 + PWM_DEPTH) * 1e9 / clk_rate.

  • period_max_ns = (1 + PWM_DEPTH) * (1 + PFM_MAX) * 1e9 / clk_rate, with PFM_MAX = 8191.

Parent Clock

PWM Controllers

Source Rate

Min Period (Max Output Freq)

Max Period (Min Output Freq)

pllp_out0

PWM1, PWM2, PWM3, PWM5, PWM7, PWM8

408 MHz

~628 ns (~1.59 MHz)

~5.14 ms (~194.5 Hz)

clk_m

PWM1, PWM2, PWM3, PWM5, PWM7, PWM8

19.2 MHz

~13.33 μs (75 kHz)

~109.23 ms (~9.16 Hz)

clk_32k

PWM1, PWM2, PWM3, PWM5, PWM7, PWM8

32.768 kHz

7.8125 ms (128 Hz)

64 s (0.015625 Hz)

Reference Table: Reachable Period Range (Tegra264)#

With SCALE width set to 16, the reachable period range is computed as follows:

  • period_min_ns = (1 + PWM_DEPTH) * 1e9 / clk_rate.

  • period_max_ns = (1 + PWM_DEPTH) * (1 + PFM_MAX) * 1e9 / clk_rate, with PFM_MAX = 65535.

Because nvidia,pwm-depth is configurable on Tegra264, we provide two reference tables: one for the driver default of 255, and one for the maximum value of 65535.

With nvidia,pwm-depth = 255 (driver default):

Parent Clock

PWM Controllers

Source Rate

Min Period (Max Output Freq)

Max Period (Min Output Freq)

pll_aon

PWM4 only

~600 MHz

~427 ns (~2.34 MHz)

~27.96 ms (~35.77 Hz)

pllp_out0

PWM2, PWM3, PWM5, PWM9, PWM10

202.5 MHz

~1.26 μs (~791 kHz)

~82.85 ms (~12.07 Hz)

osc

PWM2, PWM3, PWM4, PWM5, PWM9, PWM10

27 MHz

~9.48 μs (~105.5 kHz)

~621.4 ms (~1.61 Hz)

With nvidia,pwm-depth = 65535 (maximum):

Parent Clock

PWM Controllers

Source Rate

Min Period (Max Output Freq)

Max Period (Min Output Freq)

pll_aon

PWM4 only

~600 MHz

~109.2 μs (~9.16 kHz)

~7.158 s (~0.140 Hz)

pllp_out0

PWM2, PWM3, PWM5, PWM9, PWM10

202.5 MHz

~323.6 μs (~3.09 kHz)

~21.21 s (~0.0472 Hz)

osc

PWM2, PWM3, PWM4, PWM5, PWM9, PWM10

27 MHz

~2.43 ms (~412 Hz)

~159.1 s (~0.00629 Hz)

Example: Configure Tegra234 PWM5 With CLK_32K As Parent For 1 Hz Output#

To produce a 1 Hz output on Tegra234 PWM5, use TEGRA234_CLK_CLK_32K (32,768 Hz) as the parent. PWM_DEPTH is fixed at 255 on Tegra234, so no nvidia,pwm-depth property is needed. Add the following to your board DTS:

pwm@32c0000 {
    assigned-clocks = <&bpmp TEGRA234_CLK_PWM5>;
    assigned-clock-parents = <&bpmp TEGRA234_CLK_CLK_32K>;
    status = "okay";
};

Why these values? With clk_rate = 32768 Hz and PWM_DEPTH = 255, requesting a 1,000,000,000 ns period (1 Hz) resolves to PFM = DIV_ROUND_CLOSEST(32768 / (1e9 * 256 / 1e9)) - 1 = 128 - 1 = 127. The actual output is 32768 / (256 * 128) = 1 Hz exactly—no rounding error.

Then rebuild and reflash the kernel DTB. After reboot, verify the configured parent and rate:

$ cat /sys/kernel/debug/clk/pwm5/clk_parent
$ cat /sys/kernel/debug/clk/pwm5/clk_rate

To request the 1 Hz period (50% duty cycle):

# echo 0          > /sys/class/pwm/pwmchip<N>/export
# echo 1000000000 > /sys/class/pwm/pwmchip<N>/pwm0/period
# echo 500000000  > /sys/class/pwm/pwmchip<N>/pwm0/duty_cycle
# echo 1          > /sys/class/pwm/pwmchip<N>/pwm0/enable

Replace <N> with the chip number that corresponds to PWM5 in /sys/class/pwm/.

Example: Configure Tegra264 PWM5 With OSC As Parent For ~30 fps Output#

To produce an output period of roughly 33 ms (close to 30 fps) on Tegra264 PWM5, use TEGRA264_CLK_OSC (~27 MHz) as the parent and set PWM_DEPTH to its maximum so that a period this long stays within the SCALE field. Add the following to your board DTS:

pwm@810c600000 {
    assigned-clocks = <&bpmp TEGRA264_CLK_PWM5>;
    assigned-clock-parents = <&bpmp TEGRA264_CLK_OSC>;
    nvidia,pwm-depth = <65535>;
    status = "okay";
};

Why these values? With clk_rate = 27 MHz and PWM_DEPTH = 65535, requesting a 33,333,333 ns period (30 fps) resolves to PFM = DIV_ROUND_CLOSEST(27000000 / (1e9 * 65536 / 33333333)) - 1 = 13. The actual output is 27000000 / (65536 * 14) 29.43 Hz (period ~33.98 ms), which is the closest the divider can produce to 30 fps.

Then rebuild and reflash the kernel DTB. After reboot, verify the configured parent and rate:

$ cat /sys/kernel/debug/clk/pwm5/clk_parent
$ cat /sys/kernel/debug/clk/pwm5/clk_rate

To request the 30 fps period (50% duty cycle):

# echo 0        > /sys/class/pwm/pwmchip<N>/export
# echo 33333333 > /sys/class/pwm/pwmchip<N>/pwm0/period
# echo 16666666 > /sys/class/pwm/pwmchip<N>/pwm0/duty_cycle
# echo 1        > /sys/class/pwm/pwmchip<N>/pwm0/enable

Replace <N> with the chip number that corresponds to PWM5 in /sys/class/pwm/.