brintos

brintos / linux-shallow public Read only

0
0
Text · 5.7 KiB · 073e64d Raw
206 lines · c
1// SPDX-License-Identifier: GPL-2.0+2 3/*4 * Copyright (C) 2022 Pengutronix, Lucas Stach <kernel@pengutronix.de>5 */6 7#include <drm/drm_atomic_helper.h>8#include <drm/drm_bridge.h>9#include <drm/drm_crtc.h>10#include <linux/bitfield.h>11#include <linux/io.h>12#include <linux/module.h>13#include <linux/of.h>14#include <linux/of_graph.h>15#include <linux/platform_device.h>16#include <linux/pm_runtime.h>17 18#define HTX_PVI_CTRL			0x019#define  PVI_CTRL_OP_VSYNC_POL		BIT(18)20#define  PVI_CTRL_OP_HSYNC_POL		BIT(17)21#define  PVI_CTRL_OP_DE_POL		BIT(16)22#define  PVI_CTRL_INP_VSYNC_POL		BIT(14)23#define  PVI_CTRL_INP_HSYNC_POL		BIT(13)24#define  PVI_CTRL_INP_DE_POL		BIT(12)25#define  PVI_CTRL_MODE_MASK		GENMASK(2, 1)26#define  PVI_CTRL_MODE_LCDIF		227#define  PVI_CTRL_EN			BIT(0)28 29struct imx8mp_hdmi_pvi {30	struct drm_bridge	bridge;31	struct device		*dev;32	struct drm_bridge	*next_bridge;33	void __iomem		*regs;34};35 36static inline struct imx8mp_hdmi_pvi *37to_imx8mp_hdmi_pvi(struct drm_bridge *bridge)38{39	return container_of(bridge, struct imx8mp_hdmi_pvi, bridge);40}41 42static int imx8mp_hdmi_pvi_bridge_attach(struct drm_bridge *bridge,43					 enum drm_bridge_attach_flags flags)44{45	struct imx8mp_hdmi_pvi *pvi = to_imx8mp_hdmi_pvi(bridge);46 47	return drm_bridge_attach(bridge->encoder, pvi->next_bridge,48				 bridge, flags);49}50 51static void imx8mp_hdmi_pvi_bridge_enable(struct drm_bridge *bridge,52					  struct drm_bridge_state *bridge_state)53{54	struct drm_atomic_state *state = bridge_state->base.state;55	struct imx8mp_hdmi_pvi *pvi = to_imx8mp_hdmi_pvi(bridge);56	struct drm_connector_state *conn_state;57	const struct drm_display_mode *mode;58	struct drm_crtc_state *crtc_state;59	struct drm_connector *connector;60	u32 bus_flags = 0, val;61 62	connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);63	conn_state = drm_atomic_get_new_connector_state(state, connector);64	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);65 66	if (WARN_ON(pm_runtime_resume_and_get(pvi->dev)))67		return;68 69	mode = &crtc_state->adjusted_mode;70 71	val = FIELD_PREP(PVI_CTRL_MODE_MASK, PVI_CTRL_MODE_LCDIF) | PVI_CTRL_EN;72 73	if (mode->flags & DRM_MODE_FLAG_PVSYNC)74		val |= PVI_CTRL_OP_VSYNC_POL | PVI_CTRL_INP_VSYNC_POL;75 76	if (mode->flags & DRM_MODE_FLAG_PHSYNC)77		val |= PVI_CTRL_OP_HSYNC_POL | PVI_CTRL_INP_HSYNC_POL;78 79	if (pvi->next_bridge->timings)80		bus_flags = pvi->next_bridge->timings->input_bus_flags;81	else if (bridge_state)82		bus_flags = bridge_state->input_bus_cfg.flags;83 84	if (bus_flags & DRM_BUS_FLAG_DE_HIGH)85		val |= PVI_CTRL_OP_DE_POL | PVI_CTRL_INP_DE_POL;86 87	writel(val, pvi->regs + HTX_PVI_CTRL);88}89 90static void imx8mp_hdmi_pvi_bridge_disable(struct drm_bridge *bridge,91					   struct drm_bridge_state *bridge_state)92{93	struct imx8mp_hdmi_pvi *pvi = to_imx8mp_hdmi_pvi(bridge);94 95	writel(0x0, pvi->regs + HTX_PVI_CTRL);96 97	pm_runtime_put(pvi->dev);98}99 100static u32 *101imx8mp_hdmi_pvi_bridge_get_input_bus_fmts(struct drm_bridge *bridge,102					  struct drm_bridge_state *bridge_state,103					  struct drm_crtc_state *crtc_state,104					  struct drm_connector_state *conn_state,105					  u32 output_fmt,106					  unsigned int *num_input_fmts)107{108	struct imx8mp_hdmi_pvi *pvi = to_imx8mp_hdmi_pvi(bridge);109	struct drm_bridge *next_bridge = pvi->next_bridge;110	struct drm_bridge_state *next_state;111 112	if (!next_bridge->funcs->atomic_get_input_bus_fmts)113		return NULL;114 115	next_state = drm_atomic_get_new_bridge_state(crtc_state->state,116						     next_bridge);117 118	return next_bridge->funcs->atomic_get_input_bus_fmts(next_bridge,119							     next_state,120							     crtc_state,121							     conn_state,122							     output_fmt,123							     num_input_fmts);124}125 126static const struct drm_bridge_funcs imx_hdmi_pvi_bridge_funcs = {127	.attach		= imx8mp_hdmi_pvi_bridge_attach,128	.atomic_enable	= imx8mp_hdmi_pvi_bridge_enable,129	.atomic_disable	= imx8mp_hdmi_pvi_bridge_disable,130	.atomic_get_input_bus_fmts = imx8mp_hdmi_pvi_bridge_get_input_bus_fmts,131	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,132	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,133	.atomic_reset = drm_atomic_helper_bridge_reset,134};135 136static int imx8mp_hdmi_pvi_probe(struct platform_device *pdev)137{138	struct device_node *remote;139	struct imx8mp_hdmi_pvi *pvi;140 141	pvi = devm_kzalloc(&pdev->dev, sizeof(*pvi), GFP_KERNEL);142	if (!pvi)143		return -ENOMEM;144 145	platform_set_drvdata(pdev, pvi);146	pvi->dev = &pdev->dev;147 148	pvi->regs = devm_platform_ioremap_resource(pdev, 0);149	if (IS_ERR(pvi->regs))150		return PTR_ERR(pvi->regs);151 152	/* Get the next bridge in the pipeline. */153	remote = of_graph_get_remote_node(pdev->dev.of_node, 1, -1);154	if (!remote)155		return -EINVAL;156 157	pvi->next_bridge = of_drm_find_bridge(remote);158	of_node_put(remote);159 160	if (!pvi->next_bridge)161		return dev_err_probe(&pdev->dev, -EPROBE_DEFER,162				     "could not find next bridge\n");163 164	pm_runtime_enable(&pdev->dev);165 166	/* Register the bridge. */167	pvi->bridge.funcs = &imx_hdmi_pvi_bridge_funcs;168	pvi->bridge.of_node = pdev->dev.of_node;169	pvi->bridge.timings = pvi->next_bridge->timings;170 171	drm_bridge_add(&pvi->bridge);172 173	return 0;174}175 176static void imx8mp_hdmi_pvi_remove(struct platform_device *pdev)177{178	struct imx8mp_hdmi_pvi *pvi = platform_get_drvdata(pdev);179 180	drm_bridge_remove(&pvi->bridge);181 182	pm_runtime_disable(&pdev->dev);183}184 185static const struct of_device_id imx8mp_hdmi_pvi_match[] = {186	{187		.compatible = "fsl,imx8mp-hdmi-pvi",188	}, {189		/* sentinel */190	}191};192MODULE_DEVICE_TABLE(of, imx8mp_hdmi_pvi_match);193 194static struct platform_driver imx8mp_hdmi_pvi_driver = {195	.probe	= imx8mp_hdmi_pvi_probe,196	.remove_new = imx8mp_hdmi_pvi_remove,197	.driver		= {198		.name = "imx-hdmi-pvi",199		.of_match_table	= imx8mp_hdmi_pvi_match,200	},201};202module_platform_driver(imx8mp_hdmi_pvi_driver);203 204MODULE_DESCRIPTION("i.MX8MP HDMI TX Parallel Video Interface bridge driver");205MODULE_LICENSE("GPL");206