1 From 4817db177a74ac58671e1fe84d98d584375d9697 Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.org>
3 Date: Wed, 3 Apr 2019 17:15:45 +0100
4 Subject: [PATCH 594/806] drm: vc4: Add support for multiple displays to fkms
6 There is a slightly nasty hack in that all crtcs share the
7 same SMI interrupt from the firmware. This seems to currently
8 work well enough, but ought to be fixed at a later date.
10 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
12 drivers/gpu/drm/vc4/vc4_firmware_kms.c | 160 +++++++++++++++++--------
13 1 file changed, 113 insertions(+), 47 deletions(-)
15 --- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
16 +++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
18 #include "vc_image_types.h"
19 #include <soc/bcm2835/raspberrypi-firmware.h>
21 +#define PLANES_PER_CRTC 3
26 @@ -175,6 +177,7 @@ struct vc4_crtc {
27 struct drm_pending_vblank_event *event;
33 static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc)
34 @@ -480,6 +483,7 @@ static const struct drm_plane_helper_fun
36 static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
37 enum drm_plane_type type,
41 struct drm_plane *plane = NULL;
42 @@ -543,7 +547,7 @@ static struct drm_plane *vc4_fkms_plane_
43 vc4_plane->mb.tag.tag = RPI_FIRMWARE_SET_PLANE;
44 vc4_plane->mb.tag.buf_size = sizeof(struct set_plane);
45 vc4_plane->mb.tag.req_resp_size = 0;
46 - vc4_plane->mb.plane.display = 0;
47 + vc4_plane->mb.plane.display = display_num;
48 vc4_plane->mb.plane.plane_id = plane_id;
49 vc4_plane->mb.plane.layer = default_zpos ? default_zpos : -127;
51 @@ -630,16 +634,20 @@ static void vc4_crtc_handle_page_flip(st
53 static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
55 - struct vc4_crtc *vc4_crtc = data;
56 - u32 stat = readl(vc4_crtc->regs + SMICS);
57 + struct vc4_crtc **crtc_list = data;
59 + u32 stat = readl(crtc_list[0]->regs + SMICS);
60 irqreturn_t ret = IRQ_NONE;
62 if (stat & SMICS_INTERRUPTS) {
63 - writel(0, vc4_crtc->regs + SMICS);
64 - if (vc4_crtc->vblank_enabled)
65 - drm_crtc_handle_vblank(&vc4_crtc->base);
66 - vc4_crtc_handle_page_flip(vc4_crtc);
68 + writel(0, crtc_list[0]->regs + SMICS);
70 + for (i = 0; crtc_list[i]; i++) {
71 + if (crtc_list[i]->vblank_enabled)
72 + drm_crtc_handle_vblank(&crtc_list[i]->base);
73 + vc4_crtc_handle_page_flip(crtc_list[i]);
79 @@ -836,66 +844,55 @@ static const struct drm_encoder_helper_f
80 .disable = vc4_fkms_encoder_disable,
83 -static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
84 +static int vc4_fkms_create_screen(struct device *dev, struct drm_device *drm,
85 + int display_idx, int display_ref,
86 + struct vc4_crtc **ret_crtc)
88 - struct platform_device *pdev = to_platform_device(dev);
89 - struct drm_device *drm = dev_get_drvdata(master);
90 struct vc4_dev *vc4 = to_vc4_dev(drm);
91 struct vc4_crtc *vc4_crtc;
92 struct vc4_fkms_encoder *vc4_encoder;
93 struct drm_crtc *crtc;
94 struct drm_plane *primary_plane, *overlay_plane, *cursor_plane;
95 struct drm_plane *destroy_plane, *temp;
96 - struct device_node *firmware_node;
100 - vc4->firmware_kms = true;
102 - /* firmware kms doesn't have precise a scanoutpos implementation, so
103 - * we can't do the precise vblank timestamp mode.
105 - drm->driver->get_scanout_position = NULL;
106 - drm->driver->get_vblank_timestamp = NULL;
108 vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
111 crtc = &vc4_crtc->base;
113 - firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
114 - vc4->firmware = rpi_firmware_get(firmware_node);
115 - if (!vc4->firmware) {
116 - DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n");
117 - return -EPROBE_DEFER;
119 - of_node_put(firmware_node);
121 - /* Map the SMI interrupt reg */
122 - vc4_crtc->regs = vc4_ioremap_regs(pdev, 0);
123 - if (IS_ERR(vc4_crtc->regs))
124 - return PTR_ERR(vc4_crtc->regs);
125 + vc4_crtc->display_number = display_ref;
127 /* Blank the firmware provided framebuffer */
128 rpi_firmware_property(vc4->firmware,
129 RPI_FIRMWARE_FRAMEBUFFER_BLANK,
130 &blank, sizeof(blank));
132 - primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, 0);
133 + primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY,
135 + 0 + (display_idx * PLANES_PER_CRTC)
137 if (IS_ERR(primary_plane)) {
138 dev_err(dev, "failed to construct primary plane\n");
139 ret = PTR_ERR(primary_plane);
143 - overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, 1);
144 + overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY,
146 + 1 + (display_idx * PLANES_PER_CRTC)
148 if (IS_ERR(overlay_plane)) {
149 dev_err(dev, "failed to construct overlay plane\n");
150 ret = PTR_ERR(overlay_plane);
154 - cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR, 2);
155 + cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR,
157 + 2 + (display_idx * PLANES_PER_CRTC)
159 if (IS_ERR(cursor_plane)) {
160 dev_err(dev, "failed to construct cursor plane\n");
161 ret = PTR_ERR(cursor_plane);
162 @@ -922,13 +919,6 @@ static int vc4_fkms_bind(struct device *
163 goto err_destroy_encoder;
166 - writel(0, vc4_crtc->regs + SMICS);
167 - ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
168 - vc4_crtc_irq_handler, 0, "vc4 firmware kms",
171 - goto err_destroy_connector;
173 ret = rpi_firmware_property(vc4->firmware,
174 RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN,
176 @@ -938,7 +928,7 @@ static int vc4_fkms_bind(struct device *
177 memset(&vc4_crtc->overscan, 0, sizeof(vc4_crtc->overscan));
180 - platform_set_drvdata(pdev, vc4_crtc);
181 + *ret_crtc = vc4_crtc;
185 @@ -955,15 +945,91 @@ err:
189 +static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
191 + struct platform_device *pdev = to_platform_device(dev);
192 + struct drm_device *drm = dev_get_drvdata(master);
193 + struct vc4_dev *vc4 = to_vc4_dev(drm);
194 + struct device_node *firmware_node;
195 + struct vc4_crtc **crtc_list;
196 + u32 num_displays, display_num;
198 + const u32 display_num_lookup[] = {2, 7, 1};
200 + vc4->firmware_kms = true;
202 + /* firmware kms doesn't have precise a scanoutpos implementation, so
203 + * we can't do the precise vblank timestamp mode.
205 + drm->driver->get_scanout_position = NULL;
206 + drm->driver->get_vblank_timestamp = NULL;
208 + firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
209 + vc4->firmware = rpi_firmware_get(firmware_node);
210 + if (!vc4->firmware) {
211 + DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n");
212 + return -EPROBE_DEFER;
214 + of_node_put(firmware_node);
216 + ret = rpi_firmware_property(vc4->firmware,
217 + RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
218 + &num_displays, sizeof(u32));
220 + /* If we fail to get the number of displays, or it returns 0, then
221 + * assume old firmware that doesn't have the mailbox call, so just
224 + if (ret || num_displays == 0) {
226 + DRM_WARN("Unable to determine number of displays's. Assuming 1\n");
230 + /* Allocate a list, with space for a NULL on the end */
231 + crtc_list = devm_kzalloc(dev, sizeof(crtc_list) * (num_displays + 1),
236 + for (display_num = 0; display_num < num_displays; display_num++) {
237 + ret = vc4_fkms_create_screen(dev, drm, display_num,
238 + display_num_lookup[display_num],
239 + &crtc_list[display_num]);
241 + DRM_ERROR("Oh dear, failed to create display %u\n",
245 + /* Map the SMI interrupt reg */
246 + crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0);
247 + if (IS_ERR(crtc_list[0]->regs))
248 + DRM_ERROR("Oh dear, failed to map registers\n");
250 + writel(0, crtc_list[0]->regs + SMICS);
251 + ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
252 + vc4_crtc_irq_handler, 0, "vc4 firmware kms",
255 + DRM_ERROR("Oh dear, failed to register IRQ\n");
257 + platform_set_drvdata(pdev, crtc_list);
262 static void vc4_fkms_unbind(struct device *dev, struct device *master,
265 struct platform_device *pdev = to_platform_device(dev);
266 - struct vc4_crtc *vc4_crtc = dev_get_drvdata(dev);
267 + struct vc4_crtc **crtc_list = dev_get_drvdata(dev);
270 - vc4_fkms_connector_destroy(vc4_crtc->connector);
271 - vc4_fkms_encoder_destroy(vc4_crtc->encoder);
272 - drm_crtc_cleanup(&vc4_crtc->base);
273 + for (i = 0; crtc_list[i]; i++) {
274 + vc4_fkms_connector_destroy(crtc_list[i]->connector);
275 + vc4_fkms_encoder_destroy(crtc_list[i]->encoder);
276 + drm_crtc_cleanup(&crtc_list[i]->base);
279 platform_set_drvdata(pdev, NULL);