diff options
author | Dave Airlie <airlied@redhat.com> | 2016-07-21 21:40:24 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2016-07-21 21:40:24 -0400 |
commit | c11dea5b0290984fa48111957ba3fdc5b3bdae5a (patch) | |
tree | 0bbdd88c17e5624f5ef8bbe395593f65300ffa5a | |
parent | c8c21231f0808d78347062704c54321d97303cf0 (diff) | |
parent | c4a304d3b1dc9d1732b5d78cc190b5c3e41870d4 (diff) |
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
-rw-r--r-- | Documentation/devicetree/bindings/display/fsl,dcu.txt | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_output.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 78 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_tcon.c | 1 |
5 files changed, 68 insertions, 25 deletions
diff --git a/Documentation/devicetree/bindings/display/fsl,dcu.txt b/Documentation/devicetree/bindings/display/fsl,dcu.txt index ae55cde1b69e..63ec2a624aa9 100644 --- a/Documentation/devicetree/bindings/display/fsl,dcu.txt +++ b/Documentation/devicetree/bindings/display/fsl,dcu.txt | |||
@@ -12,7 +12,7 @@ Required properties: | |||
12 | - clock-names: Should be "dcu" and "pix" | 12 | - clock-names: Should be "dcu" and "pix" |
13 | See ../clocks/clock-bindings.txt for details. | 13 | See ../clocks/clock-bindings.txt for details. |
14 | - big-endian Boolean property, LS1021A DCU registers are big-endian. | 14 | - big-endian Boolean property, LS1021A DCU registers are big-endian. |
15 | - fsl,panel: The phandle to panel node. | 15 | - port Video port for the panel output |
16 | 16 | ||
17 | Optional properties: | 17 | Optional properties: |
18 | - fsl,tcon: The phandle to the timing controller node. | 18 | - fsl,tcon: The phandle to the timing controller node. |
@@ -24,6 +24,11 @@ dcu: dcu@2ce0000 { | |||
24 | clocks = <&platform_clk 0>, <&platform_clk 0>; | 24 | clocks = <&platform_clk 0>, <&platform_clk 0>; |
25 | clock-names = "dcu", "pix"; | 25 | clock-names = "dcu", "pix"; |
26 | big-endian; | 26 | big-endian; |
27 | fsl,panel = <&panel>; | ||
28 | fsl,tcon = <&tcon>; | 27 | fsl,tcon = <&tcon>; |
28 | |||
29 | port { | ||
30 | dcu_out: endpoint { | ||
31 | remote-endpoint = <&panel_out>; | ||
32 | }; | ||
33 | }; | ||
29 | }; | 34 | }; |
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c index a6e4cd591960..d9d6cc1c8e39 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c | |||
@@ -43,7 +43,7 @@ int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev) | |||
43 | if (ret) | 43 | if (ret) |
44 | goto err; | 44 | goto err; |
45 | 45 | ||
46 | ret = fsl_dcu_drm_connector_create(fsl_dev, &fsl_dev->encoder); | 46 | ret = fsl_dcu_create_outputs(fsl_dev); |
47 | if (ret) | 47 | if (ret) |
48 | goto err; | 48 | goto err; |
49 | 49 | ||
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_output.h b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_output.h index 7093109fbc21..5a7b88e19e44 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_output.h +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_output.h | |||
@@ -25,9 +25,8 @@ to_fsl_dcu_connector(struct drm_connector *con) | |||
25 | : NULL; | 25 | : NULL; |
26 | } | 26 | } |
27 | 27 | ||
28 | int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev, | ||
29 | struct drm_encoder *encoder); | ||
30 | int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev, | 28 | int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev, |
31 | struct drm_crtc *crtc); | 29 | struct drm_crtc *crtc); |
30 | int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev); | ||
32 | 31 | ||
33 | #endif /* __FSL_DCU_DRM_CONNECTOR_H__ */ | 32 | #endif /* __FSL_DCU_DRM_CONNECTOR_H__ */ |
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c index 0b0989e503ea..26edcc899712 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | |||
@@ -10,6 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/backlight.h> | 12 | #include <linux/backlight.h> |
13 | #include <linux/of_graph.h> | ||
13 | 14 | ||
14 | #include <drm/drmP.h> | 15 | #include <drm/drmP.h> |
15 | #include <drm/drm_atomic_helper.h> | 16 | #include <drm/drm_atomic_helper.h> |
@@ -132,12 +133,12 @@ static const struct drm_connector_helper_funcs connector_helper_funcs = { | |||
132 | .mode_valid = fsl_dcu_drm_connector_mode_valid, | 133 | .mode_valid = fsl_dcu_drm_connector_mode_valid, |
133 | }; | 134 | }; |
134 | 135 | ||
135 | int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev, | 136 | static int fsl_dcu_attach_panel(struct fsl_dcu_drm_device *fsl_dev, |
136 | struct drm_encoder *encoder) | 137 | struct drm_panel *panel) |
137 | { | 138 | { |
139 | struct drm_encoder *encoder = &fsl_dev->encoder; | ||
138 | struct drm_connector *connector = &fsl_dev->connector.base; | 140 | struct drm_connector *connector = &fsl_dev->connector.base; |
139 | struct drm_mode_config *mode_config = &fsl_dev->drm->mode_config; | 141 | struct drm_mode_config *mode_config = &fsl_dev->drm->mode_config; |
140 | struct device_node *panel_node; | ||
141 | int ret; | 142 | int ret; |
142 | 143 | ||
143 | fsl_dev->connector.encoder = encoder; | 144 | fsl_dev->connector.encoder = encoder; |
@@ -161,21 +162,7 @@ int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev, | |||
161 | mode_config->dpms_property, | 162 | mode_config->dpms_property, |
162 | DRM_MODE_DPMS_OFF); | 163 | DRM_MODE_DPMS_OFF); |
163 | 164 | ||
164 | panel_node = of_parse_phandle(fsl_dev->np, "fsl,panel", 0); | 165 | ret = drm_panel_attach(panel, connector); |
165 | if (!panel_node) { | ||
166 | dev_err(fsl_dev->dev, "fsl,panel property not found\n"); | ||
167 | ret = -ENODEV; | ||
168 | goto err_sysfs; | ||
169 | } | ||
170 | |||
171 | fsl_dev->connector.panel = of_drm_find_panel(panel_node); | ||
172 | if (!fsl_dev->connector.panel) { | ||
173 | ret = -EPROBE_DEFER; | ||
174 | goto err_panel; | ||
175 | } | ||
176 | of_node_put(panel_node); | ||
177 | |||
178 | ret = drm_panel_attach(fsl_dev->connector.panel, connector); | ||
179 | if (ret) { | 166 | if (ret) { |
180 | dev_err(fsl_dev->dev, "failed to attach panel\n"); | 167 | dev_err(fsl_dev->dev, "failed to attach panel\n"); |
181 | goto err_sysfs; | 168 | goto err_sysfs; |
@@ -183,11 +170,62 @@ int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev, | |||
183 | 170 | ||
184 | return 0; | 171 | return 0; |
185 | 172 | ||
186 | err_panel: | ||
187 | of_node_put(panel_node); | ||
188 | err_sysfs: | 173 | err_sysfs: |
189 | drm_connector_unregister(connector); | 174 | drm_connector_unregister(connector); |
190 | err_cleanup: | 175 | err_cleanup: |
191 | drm_connector_cleanup(connector); | 176 | drm_connector_cleanup(connector); |
192 | return ret; | 177 | return ret; |
193 | } | 178 | } |
179 | |||
180 | static int fsl_dcu_attach_endpoint(struct fsl_dcu_drm_device *fsl_dev, | ||
181 | const struct of_endpoint *ep) | ||
182 | { | ||
183 | struct drm_bridge *bridge; | ||
184 | struct device_node *np; | ||
185 | |||
186 | np = of_graph_get_remote_port_parent(ep->local_node); | ||
187 | |||
188 | fsl_dev->connector.panel = of_drm_find_panel(np); | ||
189 | if (fsl_dev->connector.panel) { | ||
190 | of_node_put(np); | ||
191 | return fsl_dcu_attach_panel(fsl_dev, fsl_dev->connector.panel); | ||
192 | } | ||
193 | |||
194 | bridge = of_drm_find_bridge(np); | ||
195 | of_node_put(np); | ||
196 | if (!bridge) | ||
197 | return -ENODEV; | ||
198 | |||
199 | fsl_dev->encoder.bridge = bridge; | ||
200 | bridge->encoder = &fsl_dev->encoder; | ||
201 | |||
202 | return drm_bridge_attach(fsl_dev->drm, bridge); | ||
203 | } | ||
204 | |||
205 | int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev) | ||
206 | { | ||
207 | struct of_endpoint ep; | ||
208 | struct device_node *ep_node, *panel_node; | ||
209 | int ret; | ||
210 | |||
211 | /* This is for backward compatibility */ | ||
212 | panel_node = of_parse_phandle(fsl_dev->np, "fsl,panel", 0); | ||
213 | if (panel_node) { | ||
214 | fsl_dev->connector.panel = of_drm_find_panel(panel_node); | ||
215 | of_node_put(panel_node); | ||
216 | if (!fsl_dev->connector.panel) | ||
217 | return -EPROBE_DEFER; | ||
218 | return fsl_dcu_attach_panel(fsl_dev, fsl_dev->connector.panel); | ||
219 | } | ||
220 | |||
221 | ep_node = of_graph_get_next_endpoint(fsl_dev->np, NULL); | ||
222 | if (!ep_node) | ||
223 | return -ENODEV; | ||
224 | |||
225 | ret = of_graph_parse_endpoint(ep_node, &ep); | ||
226 | of_node_put(ep_node); | ||
227 | if (ret) | ||
228 | return -ENODEV; | ||
229 | |||
230 | return fsl_dcu_attach_endpoint(fsl_dev, &ep); | ||
231 | } | ||
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_tcon.c b/drivers/gpu/drm/fsl-dcu/fsl_tcon.c index bbe34f1c0505..bca09ea24632 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_tcon.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_tcon.c | |||
@@ -92,6 +92,7 @@ struct fsl_tcon *fsl_tcon_init(struct device *dev) | |||
92 | goto err_node_put; | 92 | goto err_node_put; |
93 | } | 93 | } |
94 | 94 | ||
95 | of_node_put(np); | ||
95 | clk_prepare_enable(tcon->ipg_clk); | 96 | clk_prepare_enable(tcon->ipg_clk); |
96 | 97 | ||
97 | dev_info(dev, "Using TCON in bypass mode\n"); | 98 | dev_info(dev, "Using TCON in bypass mode\n"); |