Few time ago I made the photodiode amplifier. Today, I decided to measure PWM on the Google Pixel 3, 4, 5.
…and I got very unexpected results. The PWM traces on the oscilloscope are modulated by something weird.
After that I checked how oscilloscope traces are modified on changing the Android states (Power up -> bootloader -> loading of the kernel -> restart).
On power up and on running the boorloader, normal PWM is displayed.
Then, on running the kernel, high frequency spikes appear on the base PWM traces
Zooming into these spikes shows that this is not the noise but periodical signal modulated on the base PWM
Reasonable question is what the hell is this?
What if this is dithering? !!!
Checking the Pixel 3 kernel source code reveals that the Pixel 3 can use dithering
version = SDE_COLOR_PROCESS_MAJOR(hw_cap->sblk->dither.version);
switch (version) {
case 1:
ops->setup_dither = sde_hw_pp_setup_dither_v1;
break;
default:
ops->setup_dither = NULL;
break;
}
then the sde_hw_pp_setup_dither_v1()
is invoked by:
static void _sde_encoder_setup_dither(struct sde_encoder_phys *phys)
{
void *dither_cfg;
int ret = 0, rc, i = 0;
size_t len = 0;
enum sde_rm_topology_name topology;
struct drm_encoder *drm_enc;
struct msm_mode_info mode_info;
struct msm_display_dsc_info *dsc = NULL;
struct sde_encoder_virt *sde_enc;
struct sde_hw_pingpong *hw_pp;
if (!phys || !phys->connector || !phys->hw_pp ||
!phys->hw_pp->ops.setup_dither || !phys->parent)
return;
topology = sde_connector_get_topology_name(phys->connector);
if ((topology == SDE_RM_TOPOLOGY_PPSPLIT) &&
(phys->split_role == ENC_ROLE_SLAVE))
return;
drm_enc = phys->parent;
sde_enc = to_sde_encoder_virt(drm_enc);
rc = _sde_encoder_get_mode_info(&sde_enc->base, &mode_info);
if (rc) {
SDE_ERROR_ENC(sde_enc, "failed to get mode info\n");
return;
}
dsc = &mode_info.comp_info.dsc_info;
/* disable dither for 10 bpp or 10bpc dsc config */
if (dsc->bpp == 10 || dsc->bpc == 10) {
phys->hw_pp->ops.setup_dither(phys->hw_pp, NULL, 0);
return;
}
ret = sde_connector_get_dither_cfg(phys->connector,
phys->connector->state, &dither_cfg, &len);
if (ret)
return;
if (TOPOLOGY_DUALPIPE_MERGE_MODE(topology)) {
for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
hw_pp = sde_enc->hw_pp[i];
if (hw_pp) {
phys->hw_pp->ops.setup_dither(hw_pp, dither_cfg,
len);
}
}
} else {
phys->hw_pp->ops.setup_dither(phys->hw_pp, dither_cfg, len);
}
}
To check this theory, I need to change implementation of _sde_encoder_setup_dither() by just immediately returning from the function. Then load new kernel and check the traces again.