How do I set a 25 kHz PWM signal on an ESP-WROOM-32?
It is very simple to set up a PWM signal at any frequency you desire, with any resolution you desire, provided you don't exceed the maximum 'bandwidth': the frequency multplied by the resolution must be less than half the clock speed of the device.

The full explanation with relation to the ESP-IDF is available here. The article explains the intricacies of all the channels and their configurations. I must confess I have not read it all, because my application was very basic.

In setup(), the code required to instantiate a PWM signal on channel chan at frequency freq, with a resolution of bit_num bits is:

double ledcSetup(uint8_t chan, double freq, uint8_t bit_num)


The code to attach the channel chan to an output pin pin is:

void ledcAttachPin(uint8_t pin, uint8_t chan)


Within loop(), or otherwise, inflict a duty cycle duty to a given channel chan using:

void ledcWrite(uint8_t chan, uint32_t duty)


I recommend perusing esp32-hal-ledc.c in the core files you installed that enabled you to program the ESP32 in Arduino Studio. You don't need to include any files to get the above functionality, but it's always good to know a bit about what goes on behind the scenes.

A few things to note, if reading through the core code is too much:


chan can only be between 0 and 15, and the function will return 0 if you try an number outside these bounds;
you can't attach the PWM output to all of the GPIO pins, as some are input only and others might have secondary functions that you need;
duty is a 32-bit type but the maximum value is determined by the resolution you used for bit_num. For example, if bit_num is 8 then the range of duty is from 0 to 255. I don't know what happens if you put higher number: the duty may stay at 100%,  or the duty may be bitmasked such that writing 256 is the same as  0, 257 is 1, etc.


Once you have mastered this, the ESP32 includes 'fading' functionality, whereby the duty cycle changes from x% to y% in z milliseconds. There are a number of tutorials on the internet for such a thing.

FINAL NOTE:

If you haven't already, take a look at Intel's PWM fan specs. It states that you need an open-collector or open-drain source provided, in your case, by the ESP32. There's a chance that the PWM pin is pulled up to 5.25V within the fan; this will hurt the ESP32 if you just wire the two together. Likewise, the Tachometer output is pulled all the way up to 12V. This will kill the ESP32 if you wire it directly to the fan.