Re: [PATCH RESEND 10/17] drm/spacemit: add Saturn DPU KMS pipeline
Philipp Zabel <[email protected]> Mon, 27 Jul 2026 09:35:38 +0200
| Newsgroups | dev.linux.lists.spacemit,org.infradead.lists.linux-phy,org.infradead.lists.linux-riscv,org.kernel.vger.linux-clk,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On Sa, 2026-07-25 at 00:51 -0400, Cody Kang via B4 Relay wrote: > From: Cody Kang <[email protected]> >=20 > Add the atomic KMS implementation on top of the hardware backend: one > CRTC and one primary plane per DPU instance. atomic_check validates > the plane rectangle 1:1 against the mode and sizes the per-channel FBC > line buffer; atomic commit builds the cmdlist batches, maps the > framebuffer through the DMMU and arms the cfg-ready handshake, with > vblank events driven from the DPU interrupt. >=20 > Signed-off-by: Cody Kang <[email protected]> > --- > drivers/gpu/drm/spacemit/spacemit_crtc.c | 815 +++++++++++++++++++++++= ++++++ > drivers/gpu/drm/spacemit/spacemit_planes.c | 376 +++++++++++++ > 2 files changed, 1191 insertions(+) >=20 > diff --git a/drivers/gpu/drm/spacemit/spacemit_crtc.c b/drivers/gpu/drm/s= pacemit/spacemit_crtc.c > new file mode 100644 > index 000000000000..b75ff6320501 > --- /dev/null > +++ b/drivers/gpu/drm/spacemit/spacemit_crtc.c > @@ -0,0 +1,815 @@ [...] > +/* > + * The assert and deassert orders are not mirror images: the hardware wa= nts > + * these. > + */ > +static void dpu_reset_assert(struct device *dev, const char *name, > + struct reset_control *rstc) > +{ > + int ret =3D reset_control_assert(rstc); > + > + if (ret) > + dev_warn(dev, "failed to assert %s reset: %d\n", name, ret); > +} > + > +static void dpu_reset_deassert(struct device *dev, const char *name, > + struct reset_control *rstc) > +{ > + int ret =3D reset_control_deassert(rstc); > + > + if (ret) > + dev_warn(dev, "failed to deassert %s reset: %d\n", name, ret); > +} > + > +static int dpu_pm_suspend(struct device *dev) > +{ > + struct spacemit_drm_private *priv =3D dev_get_drvdata(dev); > + struct spacemit_crtc *a_crtc =3D priv->a_crtc; > + > + /* > + * Assert before gating: a reset asserted into an already-gated block > + * has no clock edges to propagate on and leaves the register file > + * untouched. > + */ > + dpu_reset_assert(dev, "lcd", a_crtc->lcd_reset); > + dpu_reset_assert(dev, "esc", a_crtc->esc_reset); > + dpu_reset_assert(dev, "mclk", a_crtc->mclk_reset); It looks like these three are mirrored, and could be handled by reset_control_bulk_assert/deassert(). > + dpu_reset_assert(dev, "aclk", a_crtc->aclk_reset); > + dpu_reset_assert(dev, "dsc", a_crtc->dsc_reset); > + usleep_range(10000, 20000); > + > + if (a_crtc->core && a_crtc->core->disable_clk) > + a_crtc->core->disable_clk(a_crtc); > + > + return 0; > +} > + > +static int dpu_pm_resume(struct device *dev) > +{ > + struct spacemit_drm_private *priv =3D dev_get_drvdata(dev); > + struct spacemit_crtc *a_crtc =3D priv->a_crtc; > + > + dpu_reset_deassert(dev, "mclk", a_crtc->mclk_reset); > + dpu_reset_deassert(dev, "esc", a_crtc->esc_reset); > + dpu_reset_deassert(dev, "lcd", a_crtc->lcd_reset); > + dpu_reset_deassert(dev, "aclk", a_crtc->aclk_reset); > + dpu_reset_deassert(dev, "dsc", a_crtc->dsc_reset); > + > + if (a_crtc->core && a_crtc->core->enable_clk) > + a_crtc->core->enable_clk(a_crtc); > + > + return 0; > +} regards Philipp