]> Git Repo - linux.git/blob - drivers/gpu/drm/display/drm_bridge_connector.c
Merge tag 'linux-watchdog-6.14-rc1' of git://www.linux-watchdog.org/linux-watchdog
[linux.git] / drivers / gpu / drm / display / drm_bridge_connector.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2019 Laurent Pinchart <[email protected]>
4  */
5
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <linux/of.h>
9 #include <linux/property.h>
10 #include <linux/slab.h>
11
12 #include <drm/drm_atomic_state_helper.h>
13 #include <drm/drm_bridge.h>
14 #include <drm/drm_bridge_connector.h>
15 #include <drm/drm_connector.h>
16 #include <drm/drm_device.h>
17 #include <drm/drm_edid.h>
18 #include <drm/drm_managed.h>
19 #include <drm/drm_modeset_helper_vtables.h>
20 #include <drm/drm_print.h>
21 #include <drm/drm_probe_helper.h>
22 #include <drm/display/drm_hdmi_audio_helper.h>
23 #include <drm/display/drm_hdmi_helper.h>
24 #include <drm/display/drm_hdmi_state_helper.h>
25
26 /**
27  * DOC: overview
28  *
29  * The DRM bridge connector helper object provides a DRM connector
30  * implementation that wraps a chain of &struct drm_bridge. The connector
31  * operations are fully implemented based on the operations of the bridges in
32  * the chain, and don't require any intervention from the display controller
33  * driver at runtime.
34  *
35  * To use the helper, display controller drivers create a bridge connector with
36  * a call to drm_bridge_connector_init(). This associates the newly created
37  * connector with the chain of bridges passed to the function and registers it
38  * with the DRM device. At that point the connector becomes fully usable, no
39  * further operation is needed.
40  *
41  * The DRM bridge connector operations are implemented based on the operations
42  * provided by the bridges in the chain. Each connector operation is delegated
43  * to the bridge closest to the connector (at the end of the chain) that
44  * provides the relevant functionality.
45  *
46  * To make use of this helper, all bridges in the chain shall report bridge
47  * operation flags (&drm_bridge->ops) and bridge output type
48  * (&drm_bridge->type), as well as the DRM_BRIDGE_ATTACH_NO_CONNECTOR attach
49  * flag (none of the bridges shall create a DRM connector directly).
50  */
51
52 /**
53  * struct drm_bridge_connector - A connector backed by a chain of bridges
54  */
55 struct drm_bridge_connector {
56         /**
57          * @base: The base DRM connector
58          */
59         struct drm_connector base;
60         /**
61          * @encoder:
62          *
63          * The encoder at the start of the bridges chain.
64          */
65         struct drm_encoder *encoder;
66         /**
67          * @bridge_edid:
68          *
69          * The last bridge in the chain (closest to the connector) that provides
70          * EDID read support, if any (see &DRM_BRIDGE_OP_EDID).
71          */
72         struct drm_bridge *bridge_edid;
73         /**
74          * @bridge_hpd:
75          *
76          * The last bridge in the chain (closest to the connector) that provides
77          * hot-plug detection notification, if any (see &DRM_BRIDGE_OP_HPD).
78          */
79         struct drm_bridge *bridge_hpd;
80         /**
81          * @bridge_detect:
82          *
83          * The last bridge in the chain (closest to the connector) that provides
84          * connector detection, if any (see &DRM_BRIDGE_OP_DETECT).
85          */
86         struct drm_bridge *bridge_detect;
87         /**
88          * @bridge_modes:
89          *
90          * The last bridge in the chain (closest to the connector) that provides
91          * connector modes detection, if any (see &DRM_BRIDGE_OP_MODES).
92          */
93         struct drm_bridge *bridge_modes;
94         /**
95          * @bridge_hdmi:
96          *
97          * The bridge in the chain that implements necessary support for the
98          * HDMI connector infrastructure, if any (see &DRM_BRIDGE_OP_HDMI).
99          */
100         struct drm_bridge *bridge_hdmi;
101 };
102
103 #define to_drm_bridge_connector(x) \
104         container_of(x, struct drm_bridge_connector, base)
105
106 /* -----------------------------------------------------------------------------
107  * Bridge Connector Hot-Plug Handling
108  */
109
110 static void drm_bridge_connector_hpd_notify(struct drm_connector *connector,
111                                             enum drm_connector_status status)
112 {
113         struct drm_bridge_connector *bridge_connector =
114                 to_drm_bridge_connector(connector);
115         struct drm_bridge *bridge;
116
117         /* Notify all bridges in the pipeline of hotplug events. */
118         drm_for_each_bridge_in_chain(bridge_connector->encoder, bridge) {
119                 if (bridge->funcs->hpd_notify)
120                         bridge->funcs->hpd_notify(bridge, status);
121         }
122 }
123
124 static void drm_bridge_connector_handle_hpd(struct drm_bridge_connector *drm_bridge_connector,
125                                             enum drm_connector_status status)
126 {
127         struct drm_connector *connector = &drm_bridge_connector->base;
128         struct drm_device *dev = connector->dev;
129
130         mutex_lock(&dev->mode_config.mutex);
131         connector->status = status;
132         mutex_unlock(&dev->mode_config.mutex);
133
134         drm_bridge_connector_hpd_notify(connector, status);
135
136         drm_kms_helper_connector_hotplug_event(connector);
137 }
138
139 static void drm_bridge_connector_hpd_cb(void *cb_data,
140                                         enum drm_connector_status status)
141 {
142         drm_bridge_connector_handle_hpd(cb_data, status);
143 }
144
145 static void drm_bridge_connector_oob_hotplug_event(struct drm_connector *connector,
146                                                    enum drm_connector_status status)
147 {
148         struct drm_bridge_connector *bridge_connector =
149                 to_drm_bridge_connector(connector);
150
151         drm_bridge_connector_handle_hpd(bridge_connector, status);
152 }
153
154 static void drm_bridge_connector_enable_hpd(struct drm_connector *connector)
155 {
156         struct drm_bridge_connector *bridge_connector =
157                 to_drm_bridge_connector(connector);
158         struct drm_bridge *hpd = bridge_connector->bridge_hpd;
159
160         if (hpd)
161                 drm_bridge_hpd_enable(hpd, drm_bridge_connector_hpd_cb,
162                                       bridge_connector);
163 }
164
165 static void drm_bridge_connector_disable_hpd(struct drm_connector *connector)
166 {
167         struct drm_bridge_connector *bridge_connector =
168                 to_drm_bridge_connector(connector);
169         struct drm_bridge *hpd = bridge_connector->bridge_hpd;
170
171         if (hpd)
172                 drm_bridge_hpd_disable(hpd);
173 }
174
175 /* -----------------------------------------------------------------------------
176  * Bridge Connector Functions
177  */
178
179 static enum drm_connector_status
180 drm_bridge_connector_detect(struct drm_connector *connector, bool force)
181 {
182         struct drm_bridge_connector *bridge_connector =
183                 to_drm_bridge_connector(connector);
184         struct drm_bridge *detect = bridge_connector->bridge_detect;
185         struct drm_bridge *hdmi = bridge_connector->bridge_hdmi;
186         enum drm_connector_status status;
187
188         if (detect) {
189                 status = detect->funcs->detect(detect);
190
191                 if (hdmi)
192                         drm_atomic_helper_connector_hdmi_hotplug(connector, status);
193
194                 drm_bridge_connector_hpd_notify(connector, status);
195         } else {
196                 switch (connector->connector_type) {
197                 case DRM_MODE_CONNECTOR_DPI:
198                 case DRM_MODE_CONNECTOR_LVDS:
199                 case DRM_MODE_CONNECTOR_DSI:
200                 case DRM_MODE_CONNECTOR_eDP:
201                         status = connector_status_connected;
202                         break;
203                 default:
204                         status = connector_status_unknown;
205                         break;
206                 }
207         }
208
209         return status;
210 }
211
212 static void drm_bridge_connector_force(struct drm_connector *connector)
213 {
214         struct drm_bridge_connector *bridge_connector =
215                 to_drm_bridge_connector(connector);
216         struct drm_bridge *hdmi = bridge_connector->bridge_hdmi;
217
218         if (hdmi)
219                 drm_atomic_helper_connector_hdmi_force(connector);
220 }
221
222 static void drm_bridge_connector_debugfs_init(struct drm_connector *connector,
223                                               struct dentry *root)
224 {
225         struct drm_bridge_connector *bridge_connector =
226                 to_drm_bridge_connector(connector);
227         struct drm_encoder *encoder = bridge_connector->encoder;
228         struct drm_bridge *bridge;
229
230         list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) {
231                 if (bridge->funcs->debugfs_init)
232                         bridge->funcs->debugfs_init(bridge, root);
233         }
234 }
235
236 static void drm_bridge_connector_reset(struct drm_connector *connector)
237 {
238         struct drm_bridge_connector *bridge_connector =
239                 to_drm_bridge_connector(connector);
240
241         drm_atomic_helper_connector_reset(connector);
242         if (bridge_connector->bridge_hdmi)
243                 __drm_atomic_helper_connector_hdmi_reset(connector,
244                                                          connector->state);
245 }
246
247 static const struct drm_connector_funcs drm_bridge_connector_funcs = {
248         .reset = drm_bridge_connector_reset,
249         .detect = drm_bridge_connector_detect,
250         .force = drm_bridge_connector_force,
251         .fill_modes = drm_helper_probe_single_connector_modes,
252         .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
253         .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
254         .debugfs_init = drm_bridge_connector_debugfs_init,
255         .oob_hotplug_event = drm_bridge_connector_oob_hotplug_event,
256 };
257
258 /* -----------------------------------------------------------------------------
259  * Bridge Connector Helper Functions
260  */
261
262 static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector,
263                                                struct drm_bridge *bridge)
264 {
265         enum drm_connector_status status;
266         const struct drm_edid *drm_edid;
267         int n;
268
269         status = drm_bridge_connector_detect(connector, false);
270         if (status != connector_status_connected)
271                 goto no_edid;
272
273         drm_edid = drm_bridge_edid_read(bridge, connector);
274         if (!drm_edid_valid(drm_edid)) {
275                 drm_edid_free(drm_edid);
276                 goto no_edid;
277         }
278
279         drm_edid_connector_update(connector, drm_edid);
280         n = drm_edid_connector_add_modes(connector);
281
282         drm_edid_free(drm_edid);
283         return n;
284
285 no_edid:
286         drm_edid_connector_update(connector, NULL);
287         return 0;
288 }
289
290 static int drm_bridge_connector_get_modes(struct drm_connector *connector)
291 {
292         struct drm_bridge_connector *bridge_connector =
293                 to_drm_bridge_connector(connector);
294         struct drm_bridge *bridge;
295
296         /*
297          * If there is a HDMI bridge, EDID has been updated as a part of
298          * the .detect(). Just update the modes here.
299          */
300         bridge = bridge_connector->bridge_hdmi;
301         if (bridge)
302                 return drm_edid_connector_add_modes(connector);
303
304         /*
305          * If display exposes EDID, then we parse that in the normal way to
306          * build table of supported modes.
307          */
308         bridge = bridge_connector->bridge_edid;
309         if (bridge)
310                 return drm_bridge_connector_get_modes_edid(connector, bridge);
311
312         /*
313          * Otherwise if the display pipeline reports modes (e.g. with a fixed
314          * resolution panel or an analog TV output), query it.
315          */
316         bridge = bridge_connector->bridge_modes;
317         if (bridge)
318                 return bridge->funcs->get_modes(bridge, connector);
319
320         /*
321          * We can't retrieve modes, which can happen for instance for a DVI or
322          * VGA output with the DDC bus unconnected. The KMS core will add the
323          * default modes.
324          */
325         return 0;
326 }
327
328 static enum drm_mode_status
329 drm_bridge_connector_mode_valid(struct drm_connector *connector,
330                                 struct drm_display_mode *mode)
331 {
332         struct drm_bridge_connector *bridge_connector =
333                 to_drm_bridge_connector(connector);
334
335         if (bridge_connector->bridge_hdmi)
336                 return drm_hdmi_connector_mode_valid(connector, mode);
337
338         return MODE_OK;
339 }
340
341 static int drm_bridge_connector_atomic_check(struct drm_connector *connector,
342                                              struct drm_atomic_state *state)
343 {
344         struct drm_bridge_connector *bridge_connector =
345                 to_drm_bridge_connector(connector);
346
347         if (bridge_connector->bridge_hdmi)
348                 return drm_atomic_helper_connector_hdmi_check(connector, state);
349
350         return 0;
351 }
352
353 static const struct drm_connector_helper_funcs drm_bridge_connector_helper_funcs = {
354         .get_modes = drm_bridge_connector_get_modes,
355         .mode_valid = drm_bridge_connector_mode_valid,
356         .enable_hpd = drm_bridge_connector_enable_hpd,
357         .disable_hpd = drm_bridge_connector_disable_hpd,
358         .atomic_check = drm_bridge_connector_atomic_check,
359 };
360
361 static enum drm_mode_status
362 drm_bridge_connector_tmds_char_rate_valid(const struct drm_connector *connector,
363                                           const struct drm_display_mode *mode,
364                                           unsigned long long tmds_rate)
365 {
366         struct drm_bridge_connector *bridge_connector =
367                 to_drm_bridge_connector(connector);
368         struct drm_bridge *bridge;
369
370         bridge = bridge_connector->bridge_hdmi;
371         if (!bridge)
372                 return MODE_ERROR;
373
374         if (bridge->funcs->hdmi_tmds_char_rate_valid)
375                 return bridge->funcs->hdmi_tmds_char_rate_valid(bridge, mode, tmds_rate);
376         else
377                 return MODE_OK;
378 }
379
380 static int drm_bridge_connector_clear_infoframe(struct drm_connector *connector,
381                                                 enum hdmi_infoframe_type type)
382 {
383         struct drm_bridge_connector *bridge_connector =
384                 to_drm_bridge_connector(connector);
385         struct drm_bridge *bridge;
386
387         bridge = bridge_connector->bridge_hdmi;
388         if (!bridge)
389                 return -EINVAL;
390
391         return bridge->funcs->hdmi_clear_infoframe(bridge, type);
392 }
393
394 static int drm_bridge_connector_write_infoframe(struct drm_connector *connector,
395                                                 enum hdmi_infoframe_type type,
396                                                 const u8 *buffer, size_t len)
397 {
398         struct drm_bridge_connector *bridge_connector =
399                 to_drm_bridge_connector(connector);
400         struct drm_bridge *bridge;
401
402         bridge = bridge_connector->bridge_hdmi;
403         if (!bridge)
404                 return -EINVAL;
405
406         return bridge->funcs->hdmi_write_infoframe(bridge, type, buffer, len);
407 }
408
409 static const struct drm_edid *
410 drm_bridge_connector_read_edid(struct drm_connector *connector)
411 {
412         struct drm_bridge_connector *bridge_connector =
413                 to_drm_bridge_connector(connector);
414         struct drm_bridge *bridge;
415
416         bridge = bridge_connector->bridge_edid;
417         if (!bridge)
418                 return NULL;
419
420         return drm_bridge_edid_read(bridge, connector);
421 }
422
423 static const struct drm_connector_hdmi_funcs drm_bridge_connector_hdmi_funcs = {
424         .tmds_char_rate_valid = drm_bridge_connector_tmds_char_rate_valid,
425         .clear_infoframe = drm_bridge_connector_clear_infoframe,
426         .write_infoframe = drm_bridge_connector_write_infoframe,
427         .read_edid = drm_bridge_connector_read_edid,
428 };
429
430 static int drm_bridge_connector_audio_startup(struct drm_connector *connector)
431 {
432         struct drm_bridge_connector *bridge_connector =
433                 to_drm_bridge_connector(connector);
434         struct drm_bridge *bridge;
435
436         bridge = bridge_connector->bridge_hdmi;
437         if (!bridge)
438                 return -EINVAL;
439
440         if (!bridge->funcs->hdmi_audio_startup)
441                 return 0;
442
443         return bridge->funcs->hdmi_audio_startup(connector, bridge);
444 }
445
446 static int drm_bridge_connector_audio_prepare(struct drm_connector *connector,
447                                               struct hdmi_codec_daifmt *fmt,
448                                               struct hdmi_codec_params *hparms)
449 {
450         struct drm_bridge_connector *bridge_connector =
451                 to_drm_bridge_connector(connector);
452         struct drm_bridge *bridge;
453
454         bridge = bridge_connector->bridge_hdmi;
455         if (!bridge)
456                 return -EINVAL;
457
458         return bridge->funcs->hdmi_audio_prepare(connector, bridge, fmt, hparms);
459 }
460
461 static void drm_bridge_connector_audio_shutdown(struct drm_connector *connector)
462 {
463         struct drm_bridge_connector *bridge_connector =
464                 to_drm_bridge_connector(connector);
465         struct drm_bridge *bridge;
466
467         bridge = bridge_connector->bridge_hdmi;
468         if (!bridge)
469                 return;
470
471         bridge->funcs->hdmi_audio_shutdown(connector, bridge);
472 }
473
474 static int drm_bridge_connector_audio_mute_stream(struct drm_connector *connector,
475                                                   bool enable, int direction)
476 {
477         struct drm_bridge_connector *bridge_connector =
478                 to_drm_bridge_connector(connector);
479         struct drm_bridge *bridge;
480
481         bridge = bridge_connector->bridge_hdmi;
482         if (!bridge)
483                 return -EINVAL;
484
485         if (bridge->funcs->hdmi_audio_mute_stream)
486                 return bridge->funcs->hdmi_audio_mute_stream(connector, bridge,
487                                                              enable, direction);
488         else
489                 return -ENOTSUPP;
490 }
491
492 static const struct drm_connector_hdmi_audio_funcs drm_bridge_connector_hdmi_audio_funcs = {
493         .startup = drm_bridge_connector_audio_startup,
494         .prepare = drm_bridge_connector_audio_prepare,
495         .shutdown = drm_bridge_connector_audio_shutdown,
496         .mute_stream = drm_bridge_connector_audio_mute_stream,
497 };
498
499 /* -----------------------------------------------------------------------------
500  * Bridge Connector Initialisation
501  */
502
503 /**
504  * drm_bridge_connector_init - Initialise a connector for a chain of bridges
505  * @drm: the DRM device
506  * @encoder: the encoder where the bridge chain starts
507  *
508  * Allocate, initialise and register a &drm_bridge_connector with the @drm
509  * device. The connector is associated with a chain of bridges that starts at
510  * the @encoder. All bridges in the chain shall report bridge operation flags
511  * (&drm_bridge->ops) and bridge output type (&drm_bridge->type), and none of
512  * them may create a DRM connector directly.
513  *
514  * Returns a pointer to the new connector on success, or a negative error
515  * pointer otherwise.
516  */
517 struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
518                                                 struct drm_encoder *encoder)
519 {
520         struct drm_bridge_connector *bridge_connector;
521         struct drm_connector *connector;
522         struct i2c_adapter *ddc = NULL;
523         struct drm_bridge *bridge, *panel_bridge = NULL;
524         unsigned int supported_formats = BIT(HDMI_COLORSPACE_RGB);
525         unsigned int max_bpc = 8;
526         int connector_type;
527         int ret;
528
529         bridge_connector = drmm_kzalloc(drm, sizeof(*bridge_connector), GFP_KERNEL);
530         if (!bridge_connector)
531                 return ERR_PTR(-ENOMEM);
532
533         bridge_connector->encoder = encoder;
534
535         /*
536          * TODO: Handle doublescan_allowed and stereo_allowed.
537          */
538         connector = &bridge_connector->base;
539         connector->interlace_allowed = true;
540         connector->ycbcr_420_allowed = true;
541
542         /*
543          * Initialise connector status handling. First locate the furthest
544          * bridges in the pipeline that support HPD and output detection. Then
545          * initialise the connector polling mode, using HPD if available and
546          * falling back to polling if supported. If neither HPD nor output
547          * detection are available, we don't support hotplug detection at all.
548          */
549         connector_type = DRM_MODE_CONNECTOR_Unknown;
550         drm_for_each_bridge_in_chain(encoder, bridge) {
551                 if (!bridge->interlace_allowed)
552                         connector->interlace_allowed = false;
553                 if (!bridge->ycbcr_420_allowed)
554                         connector->ycbcr_420_allowed = false;
555
556                 if (bridge->ops & DRM_BRIDGE_OP_EDID)
557                         bridge_connector->bridge_edid = bridge;
558                 if (bridge->ops & DRM_BRIDGE_OP_HPD)
559                         bridge_connector->bridge_hpd = bridge;
560                 if (bridge->ops & DRM_BRIDGE_OP_DETECT)
561                         bridge_connector->bridge_detect = bridge;
562                 if (bridge->ops & DRM_BRIDGE_OP_MODES)
563                         bridge_connector->bridge_modes = bridge;
564                 if (bridge->ops & DRM_BRIDGE_OP_HDMI) {
565                         if (bridge_connector->bridge_hdmi)
566                                 return ERR_PTR(-EBUSY);
567                         if (!bridge->funcs->hdmi_write_infoframe ||
568                             !bridge->funcs->hdmi_clear_infoframe)
569                                 return ERR_PTR(-EINVAL);
570
571                         bridge_connector->bridge_hdmi = bridge;
572
573                         if (bridge->supported_formats)
574                                 supported_formats = bridge->supported_formats;
575                         if (bridge->max_bpc)
576                                 max_bpc = bridge->max_bpc;
577                 }
578
579                 if (!drm_bridge_get_next_bridge(bridge))
580                         connector_type = bridge->type;
581
582 #ifdef CONFIG_OF
583                 if (!drm_bridge_get_next_bridge(bridge) &&
584                     bridge->of_node)
585                         connector->fwnode = fwnode_handle_get(of_fwnode_handle(bridge->of_node));
586 #endif
587
588                 if (bridge->ddc)
589                         ddc = bridge->ddc;
590
591                 if (drm_bridge_is_panel(bridge))
592                         panel_bridge = bridge;
593         }
594
595         if (connector_type == DRM_MODE_CONNECTOR_Unknown)
596                 return ERR_PTR(-EINVAL);
597
598         if (bridge_connector->bridge_hdmi) {
599                 if (!connector->ycbcr_420_allowed)
600                         supported_formats &= ~BIT(HDMI_COLORSPACE_YUV420);
601
602                 bridge = bridge_connector->bridge_hdmi;
603
604                 ret = drmm_connector_hdmi_init(drm, connector,
605                                                bridge_connector->bridge_hdmi->vendor,
606                                                bridge_connector->bridge_hdmi->product,
607                                                &drm_bridge_connector_funcs,
608                                                &drm_bridge_connector_hdmi_funcs,
609                                                connector_type, ddc,
610                                                supported_formats,
611                                                max_bpc);
612                 if (ret)
613                         return ERR_PTR(ret);
614
615                 if (bridge->hdmi_audio_max_i2s_playback_channels ||
616                     bridge->hdmi_audio_spdif_playback) {
617                         if (!bridge->funcs->hdmi_audio_prepare ||
618                             !bridge->funcs->hdmi_audio_shutdown)
619                                 return ERR_PTR(-EINVAL);
620
621                         ret = drm_connector_hdmi_audio_init(connector,
622                                                             bridge->hdmi_audio_dev,
623                                                             &drm_bridge_connector_hdmi_audio_funcs,
624                                                             bridge->hdmi_audio_max_i2s_playback_channels,
625                                                             bridge->hdmi_audio_spdif_playback,
626                                                             bridge->hdmi_audio_dai_port);
627                         if (ret)
628                                 return ERR_PTR(ret);
629                 }
630         } else {
631                 ret = drmm_connector_init(drm, connector,
632                                           &drm_bridge_connector_funcs,
633                                           connector_type, ddc);
634                 if (ret)
635                         return ERR_PTR(ret);
636         }
637
638         drm_connector_helper_add(connector, &drm_bridge_connector_helper_funcs);
639
640         if (bridge_connector->bridge_hpd)
641                 connector->polled = DRM_CONNECTOR_POLL_HPD;
642         else if (bridge_connector->bridge_detect)
643                 connector->polled = DRM_CONNECTOR_POLL_CONNECT
644                                   | DRM_CONNECTOR_POLL_DISCONNECT;
645
646         if (panel_bridge)
647                 drm_panel_bridge_set_orientation(connector, panel_bridge);
648
649         return connector;
650 }
651 EXPORT_SYMBOL_GPL(drm_bridge_connector_init);
This page took 0.073541 seconds and 4 git commands to generate.