diff options
author | Thierry Reding <treding@nvidia.com> | 2017-11-28 05:20:40 -0500 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2018-03-16 19:03:36 -0400 |
commit | 0281c4149021376123b4ccdb1548692a3f6e70bd (patch) | |
tree | e2d1031c16f495b117a96f2f6035736561455b8e | |
parent | 4ae4b5c0dbaa499f2fd9215caac6e474c8dd477f (diff) |
drm/tegra: hub: Use private object for global state
Rather than subclass the global atomic state to store the hub display
clock and rate, create a private object and store this data in its
state.
Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r-- | drivers/gpu/drm/tegra/dc.c | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.c | 36 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.h | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/hub.c | 110 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/hub.h | 17 |
5 files changed, 123 insertions, 80 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index dfa787e383cc..464495b46db2 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c | |||
@@ -1736,31 +1736,6 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc, | |||
1736 | drm_crtc_vblank_on(crtc); | 1736 | drm_crtc_vblank_on(crtc); |
1737 | } | 1737 | } |
1738 | 1738 | ||
1739 | static int tegra_crtc_atomic_check(struct drm_crtc *crtc, | ||
1740 | struct drm_crtc_state *state) | ||
1741 | { | ||
1742 | struct tegra_atomic_state *s = to_tegra_atomic_state(state->state); | ||
1743 | struct tegra_dc_state *tegra = to_dc_state(state); | ||
1744 | |||
1745 | /* | ||
1746 | * The display hub display clock needs to be fed by the display clock | ||
1747 | * with the highest frequency to ensure proper functioning of all the | ||
1748 | * displays. | ||
1749 | * | ||
1750 | * Note that this isn't used before Tegra186, but it doesn't hurt and | ||
1751 | * conditionalizing it would make the code less clean. | ||
1752 | */ | ||
1753 | if (state->active) { | ||
1754 | if (!s->clk_disp || tegra->pclk > s->rate) { | ||
1755 | s->dc = to_tegra_dc(crtc); | ||
1756 | s->clk_disp = s->dc->clk; | ||
1757 | s->rate = tegra->pclk; | ||
1758 | } | ||
1759 | } | ||
1760 | |||
1761 | return 0; | ||
1762 | } | ||
1763 | |||
1764 | static void tegra_crtc_atomic_begin(struct drm_crtc *crtc, | 1739 | static void tegra_crtc_atomic_begin(struct drm_crtc *crtc, |
1765 | struct drm_crtc_state *old_crtc_state) | 1740 | struct drm_crtc_state *old_crtc_state) |
1766 | { | 1741 | { |
@@ -1797,7 +1772,6 @@ static void tegra_crtc_atomic_flush(struct drm_crtc *crtc, | |||
1797 | } | 1772 | } |
1798 | 1773 | ||
1799 | static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { | 1774 | static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { |
1800 | .atomic_check = tegra_crtc_atomic_check, | ||
1801 | .atomic_begin = tegra_crtc_atomic_begin, | 1775 | .atomic_begin = tegra_crtc_atomic_begin, |
1802 | .atomic_flush = tegra_crtc_atomic_flush, | 1776 | .atomic_flush = tegra_crtc_atomic_flush, |
1803 | .atomic_enable = tegra_crtc_atomic_enable, | 1777 | .atomic_enable = tegra_crtc_atomic_enable, |
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index d50bddb2e447..e20e013151f0 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c | |||
@@ -42,6 +42,10 @@ static int tegra_atomic_check(struct drm_device *drm, | |||
42 | if (err < 0) | 42 | if (err < 0) |
43 | return err; | 43 | return err; |
44 | 44 | ||
45 | err = tegra_display_hub_atomic_check(drm, state); | ||
46 | if (err < 0) | ||
47 | return err; | ||
48 | |||
45 | err = drm_atomic_normalize_zpos(drm, state); | 49 | err = drm_atomic_normalize_zpos(drm, state); |
46 | if (err < 0) | 50 | if (err < 0) |
47 | return err; | 51 | return err; |
@@ -56,35 +60,6 @@ static int tegra_atomic_check(struct drm_device *drm, | |||
56 | return 0; | 60 | return 0; |
57 | } | 61 | } |
58 | 62 | ||
59 | static struct drm_atomic_state * | ||
60 | tegra_atomic_state_alloc(struct drm_device *drm) | ||
61 | { | ||
62 | struct tegra_atomic_state *state = kzalloc(sizeof(*state), GFP_KERNEL); | ||
63 | |||
64 | if (!state || drm_atomic_state_init(drm, &state->base) < 0) { | ||
65 | kfree(state); | ||
66 | return NULL; | ||
67 | } | ||
68 | |||
69 | return &state->base; | ||
70 | } | ||
71 | |||
72 | static void tegra_atomic_state_clear(struct drm_atomic_state *state) | ||
73 | { | ||
74 | struct tegra_atomic_state *tegra = to_tegra_atomic_state(state); | ||
75 | |||
76 | drm_atomic_state_default_clear(state); | ||
77 | tegra->clk_disp = NULL; | ||
78 | tegra->dc = NULL; | ||
79 | tegra->rate = 0; | ||
80 | } | ||
81 | |||
82 | static void tegra_atomic_state_free(struct drm_atomic_state *state) | ||
83 | { | ||
84 | drm_atomic_state_default_release(state); | ||
85 | kfree(state); | ||
86 | } | ||
87 | |||
88 | static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = { | 63 | static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = { |
89 | .fb_create = tegra_fb_create, | 64 | .fb_create = tegra_fb_create, |
90 | #ifdef CONFIG_DRM_FBDEV_EMULATION | 65 | #ifdef CONFIG_DRM_FBDEV_EMULATION |
@@ -92,9 +67,6 @@ static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = { | |||
92 | #endif | 67 | #endif |
93 | .atomic_check = tegra_atomic_check, | 68 | .atomic_check = tegra_atomic_check, |
94 | .atomic_commit = drm_atomic_helper_commit, | 69 | .atomic_commit = drm_atomic_helper_commit, |
95 | .atomic_state_alloc = tegra_atomic_state_alloc, | ||
96 | .atomic_state_clear = tegra_atomic_state_clear, | ||
97 | .atomic_state_free = tegra_atomic_state_free, | ||
98 | }; | 70 | }; |
99 | 71 | ||
100 | static void tegra_atomic_commit_tail(struct drm_atomic_state *old_state) | 72 | static void tegra_atomic_commit_tail(struct drm_atomic_state *old_state) |
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 73b661ce7086..4f41aaec8530 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h | |||
@@ -42,20 +42,6 @@ struct tegra_fbdev { | |||
42 | }; | 42 | }; |
43 | #endif | 43 | #endif |
44 | 44 | ||
45 | struct tegra_atomic_state { | ||
46 | struct drm_atomic_state base; | ||
47 | |||
48 | struct clk *clk_disp; | ||
49 | struct tegra_dc *dc; | ||
50 | unsigned long rate; | ||
51 | }; | ||
52 | |||
53 | static inline struct tegra_atomic_state * | ||
54 | to_tegra_atomic_state(struct drm_atomic_state *state) | ||
55 | { | ||
56 | return container_of(state, struct tegra_atomic_state, base); | ||
57 | } | ||
58 | |||
59 | struct tegra_drm { | 45 | struct tegra_drm { |
60 | struct drm_device *drm; | 46 | struct drm_device *drm; |
61 | 47 | ||
diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c index 094324daa917..9a3f23d4780f 100644 --- a/drivers/gpu/drm/tegra/hub.c +++ b/drivers/gpu/drm/tegra/hub.c | |||
@@ -573,6 +573,89 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, | |||
573 | return p; | 573 | return p; |
574 | } | 574 | } |
575 | 575 | ||
576 | static struct drm_private_state * | ||
577 | tegra_display_hub_duplicate_state(struct drm_private_obj *obj) | ||
578 | { | ||
579 | struct tegra_display_hub_state *state; | ||
580 | |||
581 | state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL); | ||
582 | if (!state) | ||
583 | return NULL; | ||
584 | |||
585 | __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); | ||
586 | |||
587 | return &state->base; | ||
588 | } | ||
589 | |||
590 | static void tegra_display_hub_destroy_state(struct drm_private_obj *obj, | ||
591 | struct drm_private_state *state) | ||
592 | { | ||
593 | struct tegra_display_hub_state *hub_state = | ||
594 | to_tegra_display_hub_state(state); | ||
595 | |||
596 | kfree(hub_state); | ||
597 | } | ||
598 | |||
599 | static const struct drm_private_state_funcs tegra_display_hub_state_funcs = { | ||
600 | .atomic_duplicate_state = tegra_display_hub_duplicate_state, | ||
601 | .atomic_destroy_state = tegra_display_hub_destroy_state, | ||
602 | }; | ||
603 | |||
604 | static struct tegra_display_hub_state * | ||
605 | tegra_display_hub_get_state(struct tegra_display_hub *hub, | ||
606 | struct drm_atomic_state *state) | ||
607 | { | ||
608 | struct drm_device *drm = dev_get_drvdata(hub->client.parent); | ||
609 | struct drm_private_state *priv; | ||
610 | |||
611 | WARN_ON(!drm_modeset_is_locked(&drm->mode_config.connection_mutex)); | ||
612 | |||
613 | priv = drm_atomic_get_private_obj_state(state, &hub->base); | ||
614 | if (IS_ERR(priv)) | ||
615 | return ERR_CAST(priv); | ||
616 | |||
617 | return to_tegra_display_hub_state(priv); | ||
618 | } | ||
619 | |||
620 | int tegra_display_hub_atomic_check(struct drm_device *drm, | ||
621 | struct drm_atomic_state *state) | ||
622 | { | ||
623 | struct tegra_drm *tegra = drm->dev_private; | ||
624 | struct tegra_display_hub_state *hub_state; | ||
625 | struct drm_crtc_state *old, *new; | ||
626 | struct drm_crtc *crtc; | ||
627 | unsigned int i; | ||
628 | |||
629 | if (!tegra->hub) | ||
630 | return 0; | ||
631 | |||
632 | hub_state = tegra_display_hub_get_state(tegra->hub, state); | ||
633 | if (IS_ERR(hub_state)) | ||
634 | return PTR_ERR(hub_state); | ||
635 | |||
636 | /* | ||
637 | * The display hub display clock needs to be fed by the display clock | ||
638 | * with the highest frequency to ensure proper functioning of all the | ||
639 | * displays. | ||
640 | * | ||
641 | * Note that this isn't used before Tegra186, but it doesn't hurt and | ||
642 | * conditionalizing it would make the code less clean. | ||
643 | */ | ||
644 | for_each_oldnew_crtc_in_state(state, crtc, old, new, i) { | ||
645 | struct tegra_dc_state *dc = to_dc_state(new); | ||
646 | |||
647 | if (new->active) { | ||
648 | if (!hub_state->clk || dc->pclk > hub_state->rate) { | ||
649 | hub_state->dc = to_tegra_dc(dc->base.crtc); | ||
650 | hub_state->clk = hub_state->dc->clk; | ||
651 | hub_state->rate = dc->pclk; | ||
652 | } | ||
653 | } | ||
654 | } | ||
655 | |||
656 | return 0; | ||
657 | } | ||
658 | |||
576 | static void tegra_display_hub_update(struct tegra_dc *dc) | 659 | static void tegra_display_hub_update(struct tegra_dc *dc) |
577 | { | 660 | { |
578 | u32 value; | 661 | u32 value; |
@@ -598,26 +681,28 @@ static void tegra_display_hub_update(struct tegra_dc *dc) | |||
598 | void tegra_display_hub_atomic_commit(struct drm_device *drm, | 681 | void tegra_display_hub_atomic_commit(struct drm_device *drm, |
599 | struct drm_atomic_state *state) | 682 | struct drm_atomic_state *state) |
600 | { | 683 | { |
601 | struct tegra_atomic_state *s = to_tegra_atomic_state(state); | ||
602 | struct tegra_drm *tegra = drm->dev_private; | 684 | struct tegra_drm *tegra = drm->dev_private; |
603 | struct tegra_display_hub *hub = tegra->hub; | 685 | struct tegra_display_hub *hub = tegra->hub; |
686 | struct tegra_display_hub_state *hub_state; | ||
604 | struct device *dev = hub->client.dev; | 687 | struct device *dev = hub->client.dev; |
605 | int err; | 688 | int err; |
606 | 689 | ||
607 | if (s->clk_disp) { | 690 | hub_state = tegra_display_hub_get_state(hub, state); |
608 | err = clk_set_rate(s->clk_disp, s->rate); | 691 | |
692 | if (hub_state->clk) { | ||
693 | err = clk_set_rate(hub_state->clk, hub_state->rate); | ||
609 | if (err < 0) | 694 | if (err < 0) |
610 | dev_err(dev, "failed to set rate of %pC to %lu Hz\n", | 695 | dev_err(dev, "failed to set rate of %pC to %lu Hz\n", |
611 | s->clk_disp, s->rate); | 696 | hub_state->clk, hub_state->rate); |
612 | 697 | ||
613 | err = clk_set_parent(hub->clk_disp, s->clk_disp); | 698 | err = clk_set_parent(hub->clk_disp, hub_state->clk); |
614 | if (err < 0) | 699 | if (err < 0) |
615 | dev_err(dev, "failed to set parent of %pC to %pC: %d\n", | 700 | dev_err(dev, "failed to set parent of %pC to %pC: %d\n", |
616 | hub->clk_disp, s->clk_disp, err); | 701 | hub->clk_disp, hub_state->clk, err); |
617 | } | 702 | } |
618 | 703 | ||
619 | if (s->dc) | 704 | if (hub_state->dc) |
620 | tegra_display_hub_update(s->dc); | 705 | tegra_display_hub_update(hub_state->dc); |
621 | } | 706 | } |
622 | 707 | ||
623 | static int tegra_display_hub_init(struct host1x_client *client) | 708 | static int tegra_display_hub_init(struct host1x_client *client) |
@@ -625,6 +710,14 @@ static int tegra_display_hub_init(struct host1x_client *client) | |||
625 | struct tegra_display_hub *hub = to_tegra_display_hub(client); | 710 | struct tegra_display_hub *hub = to_tegra_display_hub(client); |
626 | struct drm_device *drm = dev_get_drvdata(client->parent); | 711 | struct drm_device *drm = dev_get_drvdata(client->parent); |
627 | struct tegra_drm *tegra = drm->dev_private; | 712 | struct tegra_drm *tegra = drm->dev_private; |
713 | struct tegra_display_hub_state *state; | ||
714 | |||
715 | state = kzalloc(sizeof(*state), GFP_KERNEL); | ||
716 | if (!state) | ||
717 | return -ENOMEM; | ||
718 | |||
719 | drm_atomic_private_obj_init(&hub->base, &state->base, | ||
720 | &tegra_display_hub_state_funcs); | ||
628 | 721 | ||
629 | tegra->hub = hub; | 722 | tegra->hub = hub; |
630 | 723 | ||
@@ -636,6 +729,7 @@ static int tegra_display_hub_exit(struct host1x_client *client) | |||
636 | struct drm_device *drm = dev_get_drvdata(client->parent); | 729 | struct drm_device *drm = dev_get_drvdata(client->parent); |
637 | struct tegra_drm *tegra = drm->dev_private; | 730 | struct tegra_drm *tegra = drm->dev_private; |
638 | 731 | ||
732 | drm_atomic_private_obj_fini(&tegra->hub->base); | ||
639 | tegra->hub = NULL; | 733 | tegra->hub = NULL; |
640 | 734 | ||
641 | return 0; | 735 | return 0; |
diff --git a/drivers/gpu/drm/tegra/hub.h b/drivers/gpu/drm/tegra/hub.h index 890a47cd05c3..85b8bf41a395 100644 --- a/drivers/gpu/drm/tegra/hub.h +++ b/drivers/gpu/drm/tegra/hub.h | |||
@@ -41,6 +41,7 @@ struct tegra_display_hub_soc { | |||
41 | }; | 41 | }; |
42 | 42 | ||
43 | struct tegra_display_hub { | 43 | struct tegra_display_hub { |
44 | struct drm_private_obj base; | ||
44 | struct host1x_client client; | 45 | struct host1x_client client; |
45 | struct clk *clk_disp; | 46 | struct clk *clk_disp; |
46 | struct clk *clk_dsc; | 47 | struct clk *clk_dsc; |
@@ -57,6 +58,20 @@ to_tegra_display_hub(struct host1x_client *client) | |||
57 | return container_of(client, struct tegra_display_hub, client); | 58 | return container_of(client, struct tegra_display_hub, client); |
58 | } | 59 | } |
59 | 60 | ||
61 | struct tegra_display_hub_state { | ||
62 | struct drm_private_state base; | ||
63 | |||
64 | struct tegra_dc *dc; | ||
65 | unsigned long rate; | ||
66 | struct clk *clk; | ||
67 | }; | ||
68 | |||
69 | static inline struct tegra_display_hub_state * | ||
70 | to_tegra_display_hub_state(struct drm_private_state *priv) | ||
71 | { | ||
72 | return container_of(priv, struct tegra_display_hub_state, base); | ||
73 | } | ||
74 | |||
60 | struct tegra_dc; | 75 | struct tegra_dc; |
61 | struct tegra_plane; | 76 | struct tegra_plane; |
62 | 77 | ||
@@ -68,6 +83,8 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, | |||
68 | unsigned int wgrp, | 83 | unsigned int wgrp, |
69 | unsigned int index); | 84 | unsigned int index); |
70 | 85 | ||
86 | int tegra_display_hub_atomic_check(struct drm_device *drm, | ||
87 | struct drm_atomic_state *state); | ||
71 | void tegra_display_hub_atomic_commit(struct drm_device *drm, | 88 | void tegra_display_hub_atomic_commit(struct drm_device *drm, |
72 | struct drm_atomic_state *state); | 89 | struct drm_atomic_state *state); |
73 | 90 | ||