Re: [PATCH RESEND 12/17] drm/spacemit: add Innosilicon DP/eDP controller bridge driver
Philipp Zabel <[email protected]> Mon, 27 Jul 2026 09:49:58 +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 DP/eDP controller that sits downstream of the Saturn DPU. Two > identical instances share one compatible; the eDP-vs-DP role is board > wiring, so it is taken from the devicetree: an eDP panel always sits > under an aux-bus child node, an external DP connector never does. >=20 > The link is driven through the generic PHY framework, so the controller > never touches a PLL register. The controller's HPD interrupt is gated by > the DP pixel clock, which can be off exactly when a plug has to be > caught, so the connector is also polled and the interrupt path re-reads > the live level when it does fire. >=20 > Signed-off-by: Cody Kang <[email protected]> > --- > drivers/gpu/drm/spacemit/Kconfig | 19 + > drivers/gpu/drm/spacemit/Makefile | 3 + > drivers/gpu/drm/spacemit/spacemit_inno_dp.c | 2443 +++++++++++++++++++++= ++++++ > drivers/gpu/drm/spacemit/spacemit_inno_dp.h | 328 ++++ > 4 files changed, 2793 insertions(+) >=20 [...] > diff --git a/drivers/gpu/drm/spacemit/spacemit_inno_dp.c b/drivers/gpu/dr= m/spacemit/spacemit_inno_dp.c > new file mode 100644 > index 000000000000..e88731d9b18b > --- /dev/null > +++ b/drivers/gpu/drm/spacemit/spacemit_inno_dp.c > @@ -0,0 +1,2443 @@ [...] > +static int inno_dp_probe(struct platform_device *pdev) > +{ [...] > + dp->reset =3D devm_reset_control_get_optional_exclusive(&pdev->dev, NUL= L); Since this is only asserted in probe and deasserted in remove, you could use devm_reset_control_get_optional_exclusive_deasserted() [1]. [1] https://docs.kernel.org/driver-api/reset.html#c.devm_reset_control_get_= optional_exclusive_deasserted > + if (IS_ERR(dp->reset)) { > + ret =3D dev_err_probe(dev, PTR_ERR(dp->reset), > + "failed to get reset\n"); > + return ret; > + } > + > + dp->pxclk =3D devm_clk_get(dev, "pxclk"); > + if (IS_ERR(dp->pxclk)) { > + ret =3D dev_err_probe(dev, PTR_ERR(dp->pxclk), > + "failed to get pxclk\n"); > + return ret; > + } > + > + if (dp->edp_mode) { > + dp->bridge.type =3D DRM_MODE_CONNECTOR_eDP; > + /* > + * OP_DETECT is required: without it > + * drm_bridge_connector_detect() hard-codes CONNECTED for any > + * eDP connector and fbdev wedges at bind. > + */ > + dp->bridge.ops =3D DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | > + DRM_BRIDGE_OP_HPD; > + } else { > + dp->bridge.type =3D DRM_MODE_CONNECTOR_DisplayPort; > + /* > + * No OP_HPD: the HPD interrupt is gated by the DP pixel clock. > + * Leaving it out marks the connector POLL_CONNECT | > + * POLL_DISCONNECT instead. > + */ > + dp->bridge.ops =3D DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | > + DRM_BRIDGE_OP_MODES; > + } > + > + if (dp->reset) { This check is not necessary, reset_control_deassert() handles NULL pointers. > + ret =3D reset_control_deassert(dp->reset); If the _deasserted() variant is used above, this can be removed and the reset control doesn't need to be stored in dp. > + if (ret) { > + dev_err(dev, "failed to deassert reset: %d\n", ret); > + return ret; > + } > + } > + [...] > + return 0; > + > +err_clk: > + clk_disable_unprepare(dp->pxclk); > +err_reset: > + if (dp->reset) > + reset_control_assert(dp->reset); Same as above. Remove the unnecessary check or manual assertion entirely. > + > + return ret; > +} > + > +static void inno_dp_remove(struct platform_device *pdev) > +{ > + struct spacemit_dp_dev *dp =3D platform_get_drvdata(pdev); > + > + component_del(&pdev->dev, &spacemit_dp_ops); > + > + if (dp) { > + clk_disable_unprepare(dp->pxclk); > + if (dp->reset) > + reset_control_assert(dp->reset); Same as above. > + } > +} regards Philipp