Merge branch 'for-next' of http://git.agner.ch/git/linux-drm-fsl-dcu into drm-next
This adds drm bridge support for the NXP/Freescale DCU. The patchset has been discussed on the mailing list since quite some time... Plus there is a small fix provided by Peter. * 'for-next' of http://git.agner.ch/git/linux-drm-fsl-dcu: drm/fsl-dcu: add support for drm bridge drm/fsl-dcu: rework codes to support of_graph dt binding for panel drm/fsl-dcu: add missing of_node_put after calling of_parse_phandle
This commit is contained in:
commit
c11dea5b02
|
@ -12,7 +12,7 @@ Required properties:
|
||||||
- clock-names: Should be "dcu" and "pix"
|
- clock-names: Should be "dcu" and "pix"
|
||||||
See ../clocks/clock-bindings.txt for details.
|
See ../clocks/clock-bindings.txt for details.
|
||||||
- big-endian Boolean property, LS1021A DCU registers are big-endian.
|
- big-endian Boolean property, LS1021A DCU registers are big-endian.
|
||||||
- fsl,panel: The phandle to panel node.
|
- port Video port for the panel output
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
- fsl,tcon: The phandle to the timing controller node.
|
- fsl,tcon: The phandle to the timing controller node.
|
||||||
|
@ -24,6 +24,11 @@ dcu: dcu@2ce0000 {
|
||||||
clocks = <&platform_clk 0>, <&platform_clk 0>;
|
clocks = <&platform_clk 0>, <&platform_clk 0>;
|
||||||
clock-names = "dcu", "pix";
|
clock-names = "dcu", "pix";
|
||||||
big-endian;
|
big-endian;
|
||||||
fsl,panel = <&panel>;
|
|
||||||
fsl,tcon = <&tcon>;
|
fsl,tcon = <&tcon>;
|
||||||
|
|
||||||
|
port {
|
||||||
|
dcu_out: endpoint {
|
||||||
|
remote-endpoint = <&panel_out>;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,7 +43,7 @@ int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
ret = fsl_dcu_drm_connector_create(fsl_dev, &fsl_dev->encoder);
|
ret = fsl_dcu_create_outputs(fsl_dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,8 @@ to_fsl_dcu_connector(struct drm_connector *con)
|
||||||
: NULL;
|
: NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev,
|
|
||||||
struct drm_encoder *encoder);
|
|
||||||
int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
|
int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
|
||||||
struct drm_crtc *crtc);
|
struct drm_crtc *crtc);
|
||||||
|
int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev);
|
||||||
|
|
||||||
#endif /* __FSL_DCU_DRM_CONNECTOR_H__ */
|
#endif /* __FSL_DCU_DRM_CONNECTOR_H__ */
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/backlight.h>
|
#include <linux/backlight.h>
|
||||||
|
#include <linux/of_graph.h>
|
||||||
|
|
||||||
#include <drm/drmP.h>
|
#include <drm/drmP.h>
|
||||||
#include <drm/drm_atomic_helper.h>
|
#include <drm/drm_atomic_helper.h>
|
||||||
|
@ -132,12 +133,12 @@ static const struct drm_connector_helper_funcs connector_helper_funcs = {
|
||||||
.mode_valid = fsl_dcu_drm_connector_mode_valid,
|
.mode_valid = fsl_dcu_drm_connector_mode_valid,
|
||||||
};
|
};
|
||||||
|
|
||||||
int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev,
|
static int fsl_dcu_attach_panel(struct fsl_dcu_drm_device *fsl_dev,
|
||||||
struct drm_encoder *encoder)
|
struct drm_panel *panel)
|
||||||
{
|
{
|
||||||
|
struct drm_encoder *encoder = &fsl_dev->encoder;
|
||||||
struct drm_connector *connector = &fsl_dev->connector.base;
|
struct drm_connector *connector = &fsl_dev->connector.base;
|
||||||
struct drm_mode_config *mode_config = &fsl_dev->drm->mode_config;
|
struct drm_mode_config *mode_config = &fsl_dev->drm->mode_config;
|
||||||
struct device_node *panel_node;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
fsl_dev->connector.encoder = encoder;
|
fsl_dev->connector.encoder = encoder;
|
||||||
|
@ -161,21 +162,7 @@ int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev,
|
||||||
mode_config->dpms_property,
|
mode_config->dpms_property,
|
||||||
DRM_MODE_DPMS_OFF);
|
DRM_MODE_DPMS_OFF);
|
||||||
|
|
||||||
panel_node = of_parse_phandle(fsl_dev->np, "fsl,panel", 0);
|
ret = drm_panel_attach(panel, connector);
|
||||||
if (!panel_node) {
|
|
||||||
dev_err(fsl_dev->dev, "fsl,panel property not found\n");
|
|
||||||
ret = -ENODEV;
|
|
||||||
goto err_sysfs;
|
|
||||||
}
|
|
||||||
|
|
||||||
fsl_dev->connector.panel = of_drm_find_panel(panel_node);
|
|
||||||
if (!fsl_dev->connector.panel) {
|
|
||||||
ret = -EPROBE_DEFER;
|
|
||||||
goto err_panel;
|
|
||||||
}
|
|
||||||
of_node_put(panel_node);
|
|
||||||
|
|
||||||
ret = drm_panel_attach(fsl_dev->connector.panel, connector);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(fsl_dev->dev, "failed to attach panel\n");
|
dev_err(fsl_dev->dev, "failed to attach panel\n");
|
||||||
goto err_sysfs;
|
goto err_sysfs;
|
||||||
|
@ -183,11 +170,62 @@ int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_panel:
|
|
||||||
of_node_put(panel_node);
|
|
||||||
err_sysfs:
|
err_sysfs:
|
||||||
drm_connector_unregister(connector);
|
drm_connector_unregister(connector);
|
||||||
err_cleanup:
|
err_cleanup:
|
||||||
drm_connector_cleanup(connector);
|
drm_connector_cleanup(connector);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int fsl_dcu_attach_endpoint(struct fsl_dcu_drm_device *fsl_dev,
|
||||||
|
const struct of_endpoint *ep)
|
||||||
|
{
|
||||||
|
struct drm_bridge *bridge;
|
||||||
|
struct device_node *np;
|
||||||
|
|
||||||
|
np = of_graph_get_remote_port_parent(ep->local_node);
|
||||||
|
|
||||||
|
fsl_dev->connector.panel = of_drm_find_panel(np);
|
||||||
|
if (fsl_dev->connector.panel) {
|
||||||
|
of_node_put(np);
|
||||||
|
return fsl_dcu_attach_panel(fsl_dev, fsl_dev->connector.panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
bridge = of_drm_find_bridge(np);
|
||||||
|
of_node_put(np);
|
||||||
|
if (!bridge)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
fsl_dev->encoder.bridge = bridge;
|
||||||
|
bridge->encoder = &fsl_dev->encoder;
|
||||||
|
|
||||||
|
return drm_bridge_attach(fsl_dev->drm, bridge);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev)
|
||||||
|
{
|
||||||
|
struct of_endpoint ep;
|
||||||
|
struct device_node *ep_node, *panel_node;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* This is for backward compatibility */
|
||||||
|
panel_node = of_parse_phandle(fsl_dev->np, "fsl,panel", 0);
|
||||||
|
if (panel_node) {
|
||||||
|
fsl_dev->connector.panel = of_drm_find_panel(panel_node);
|
||||||
|
of_node_put(panel_node);
|
||||||
|
if (!fsl_dev->connector.panel)
|
||||||
|
return -EPROBE_DEFER;
|
||||||
|
return fsl_dcu_attach_panel(fsl_dev, fsl_dev->connector.panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
ep_node = of_graph_get_next_endpoint(fsl_dev->np, NULL);
|
||||||
|
if (!ep_node)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
ret = of_graph_parse_endpoint(ep_node, &ep);
|
||||||
|
of_node_put(ep_node);
|
||||||
|
if (ret)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
return fsl_dcu_attach_endpoint(fsl_dev, &ep);
|
||||||
|
}
|
||||||
|
|
|
@ -92,6 +92,7 @@ struct fsl_tcon *fsl_tcon_init(struct device *dev)
|
||||||
goto err_node_put;
|
goto err_node_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
of_node_put(np);
|
||||||
clk_prepare_enable(tcon->ipg_clk);
|
clk_prepare_enable(tcon->ipg_clk);
|
||||||
|
|
||||||
dev_info(dev, "Using TCON in bypass mode\n");
|
dev_info(dev, "Using TCON in bypass mode\n");
|
||||||
|
|
Loading…
Reference in New Issue