bcm27xx: update patches from RPi foundation
[oweals/openwrt.git] / target / linux / bcm27xx / patches-5.4 / 950-0236-drm-vc4-Add-support-for-multiple-displays-to-fkms.patch
1 From b7a52df8162e1eb55a8403e9e9af79c581206335 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] drm: vc4: Add support for multiple displays to fkms
5
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.
9
10 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
11 ---
12  drivers/gpu/drm/vc4/vc4_firmware_kms.c | 162 +++++++++++++++++--------
13  1 file changed, 113 insertions(+), 49 deletions(-)
14
15 --- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
16 +++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
17 @@ -31,6 +31,8 @@
18  #include "vc_image_types.h"
19  #include <soc/bcm2835/raspberrypi-firmware.h>
20  
21 +#define PLANES_PER_CRTC                3
22 +
23  struct set_plane {
24         u8 display;
25         u8 plane_id;
26 @@ -177,6 +179,7 @@ struct vc4_crtc {
27         struct drm_pending_vblank_event *event;
28         u32 overscan[4];
29         bool vblank_enabled;
30 +       u32 display_number;
31  };
32  
33  static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc)
34 @@ -481,6 +484,7 @@ static const struct drm_plane_helper_fun
35  
36  static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
37                                              enum drm_plane_type type,
38 +                                            u8 display_num,
39                                              u8 plane_id)
40  {
41         struct drm_plane *plane = NULL;
42 @@ -544,7 +548,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;
50  
51 @@ -631,16 +635,20 @@ static void vc4_crtc_handle_page_flip(st
52  
53  static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
54  {
55 -       struct vc4_crtc *vc4_crtc = data;
56 -       u32 stat = readl(vc4_crtc->regs + SMICS);
57 +       struct vc4_crtc **crtc_list = data;
58 +       int i;
59 +       u32 stat = readl(crtc_list[0]->regs + SMICS);
60         irqreturn_t ret = IRQ_NONE;
61  
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);
67 -               ret = IRQ_HANDLED;
68 +               writel(0, crtc_list[0]->regs + SMICS);
69 +
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]);
74 +                       ret = IRQ_HANDLED;
75 +               }
76         }
77  
78         return ret;
79 @@ -837,66 +845,55 @@ static const struct drm_encoder_helper_f
80         .disable = vc4_fkms_encoder_disable,
81  };
82  
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)
87  {
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;
97         u32 blank = 1;
98         int ret;
99  
100 -       vc4->firmware_kms = true;
101 -
102 -       /* firmware kms doesn't have precise a scanoutpos implementation, so
103 -        * we can't do the precise vblank timestamp mode.
104 -        */
105 -       drm->driver->get_scanout_position = NULL;
106 -       drm->driver->get_vblank_timestamp = NULL;
107 -
108         vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
109         if (!vc4_crtc)
110                 return -ENOMEM;
111         crtc = &vc4_crtc->base;
112  
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;
118 -       }
119 -       of_node_put(firmware_node);
120 -
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;
126  
127         /* Blank the firmware provided framebuffer */
128         rpi_firmware_property(vc4->firmware,
129                               RPI_FIRMWARE_FRAMEBUFFER_BLANK,
130                               &blank, sizeof(blank));
131  
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,
134 +                                           display_ref,
135 +                                           0 + (display_idx * PLANES_PER_CRTC)
136 +                                          );
137         if (IS_ERR(primary_plane)) {
138                 dev_err(dev, "failed to construct primary plane\n");
139                 ret = PTR_ERR(primary_plane);
140                 goto err;
141         }
142  
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,
145 +                                           display_ref,
146 +                                           1 + (display_idx * PLANES_PER_CRTC)
147 +                                          );
148         if (IS_ERR(overlay_plane)) {
149                 dev_err(dev, "failed to construct overlay plane\n");
150                 ret = PTR_ERR(overlay_plane);
151                 goto err;
152         }
153  
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,
156 +                                          display_ref,
157 +                                          2 + (display_idx * PLANES_PER_CRTC)
158 +                                         );
159         if (IS_ERR(cursor_plane)) {
160                 dev_err(dev, "failed to construct cursor plane\n");
161                 ret = PTR_ERR(cursor_plane);
162 @@ -923,13 +920,6 @@ static int vc4_fkms_bind(struct device *
163                 goto err_destroy_encoder;
164         }
165  
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",
169 -                              vc4_crtc);
170 -       if (ret)
171 -               goto err_destroy_connector;
172 -
173         ret = rpi_firmware_property(vc4->firmware,
174                                     RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN,
175                                     &vc4_crtc->overscan,
176 @@ -939,7 +929,7 @@ static int vc4_fkms_bind(struct device *
177                 memset(&vc4_crtc->overscan, 0, sizeof(vc4_crtc->overscan));
178         }
179  
180 -       platform_set_drvdata(pdev, vc4_crtc);
181 +       *ret_crtc = vc4_crtc;
182  
183         return 0;
184  
185 @@ -956,17 +946,91 @@ err:
186         return ret;
187  }
188  
189 +static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
190 +{
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;
197 +       int ret;
198 +       const u32 display_num_lookup[] = {2, 7, 1};
199 +
200 +       vc4->firmware_kms = true;
201 +
202 +       /* firmware kms doesn't have precise a scanoutpos implementation, so
203 +        * we can't do the precise vblank timestamp mode.
204 +        */
205 +       drm->driver->get_scanout_position = NULL;
206 +       drm->driver->get_vblank_timestamp = NULL;
207 +
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;
213 +       }
214 +       of_node_put(firmware_node);
215 +
216 +       ret = rpi_firmware_property(vc4->firmware,
217 +                                   RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
218 +                                   &num_displays, sizeof(u32));
219 +
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
222 +        * set one display
223 +        */
224 +       if (ret || num_displays == 0) {
225 +               num_displays = 1;
226 +               DRM_WARN("Unable to determine number of displays's. Assuming 1\n");
227 +               ret = 0;
228 +       }
229 +
230 +       /* Allocate a list, with space for a NULL on the end */
231 +       crtc_list = devm_kzalloc(dev, sizeof(crtc_list) * (num_displays + 1),
232 +                                GFP_KERNEL);
233 +       if (!crtc_list)
234 +               return -ENOMEM;
235 +
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]);
240 +               if (ret)
241 +                       DRM_ERROR("Oh dear, failed to create display %u\n",
242 +                                 display_num);
243 +       }
244 +
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");
249 +
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",
253 +                              crtc_list);
254 +       if (ret)
255 +               DRM_ERROR("Oh dear, failed to register IRQ\n");
256 +
257 +       platform_set_drvdata(pdev, crtc_list);
258 +
259 +       return 0;
260 +}
261 +
262  static void vc4_fkms_unbind(struct device *dev, struct device *master,
263                             void *data)
264  {
265 -       struct drm_device *drm = dev_get_drvdata(master);
266         struct platform_device *pdev = to_platform_device(dev);
267 -       struct vc4_crtc *vc4_crtc = dev_get_drvdata(dev);
268 +       struct vc4_crtc **crtc_list = dev_get_drvdata(dev);
269 +       int i;
270  
271 -       vc4_fkms_connector_destroy(vc4_crtc->connector);
272 -       vc4_fkms_encoder_destroy(vc4_crtc->encoder);
273 -       drm_atomic_helper_shutdown(drm);
274 -       drm_crtc_cleanup(&vc4_crtc->base);
275 +       for (i = 0; crtc_list[i]; i++) {
276 +               vc4_fkms_connector_destroy(crtc_list[i]->connector);
277 +               vc4_fkms_encoder_destroy(crtc_list[i]->encoder);
278 +               drm_crtc_cleanup(&crtc_list[i]->base);
279 +       }
280  
281         platform_set_drvdata(pdev, NULL);
282  }