summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorNaveen Kumar S <nkumars@nvidia.com>2018-07-17 09:55:34 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2018-07-19 13:55:06 -0400
commit0b4617dc859097866aa62be19cc59e69bc0d579b (patch)
treee01adfdf9e2183832069b7a6ba2c4f176a9cecaf /drivers
parent3cef83d3a1cb39177e04b97536fca3fef0b9a184 (diff)
video: tegra: default mode support for fbconsole
First mode from EDID is chosen for fbconsole without applying any sort of filtering. This lead to choosing modes which were not always guaranteed to be supported by our hardware. To overcome such cases, we are adding support for users to specify a default mode for fbconsole. Other userspace applications will have to choose the best mode based on their requirements. To avoid any impact on platforms that might prefer the earlier logic of using the first mode from monitor's modelist, default mode for fbconsole will be set only if a mode is specified through "nvidia,fbcon-default-mode" property in DT. Refactored code. Created a new function for fbcon default mode parsing logic and used tegra_dc_set_fbcon_boot_mode() to set early dc mode for fbconsole. Added edid parameter to tegra_dc_set_fbcon_boot_mode() and moved its declaration to dc_privs.h as edid.h is already available in this header file. bug 200308135 Change-Id: Id69a10b8b7b85176dacc4a9127ef0707aea3c4ca Signed-off-by: Naveen Kumar S <nkumars@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/1563131 (cherry picked from commit a5e01c17dbc55fd0153790ddbded5e017a6f7999) Reviewed-on: https://git-master.nvidia.com/r/1780977 Reviewed-by: Shu Zhong <shuz@nvidia.com> GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu <bbasu@nvidia.com> Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/tegra/dc/dc.c2
-rw-r--r--drivers/video/tegra/dc/dc.h3
-rw-r--r--drivers/video/tegra/dc/dc_priv.h2
-rw-r--r--drivers/video/tegra/dc/dp.c9
-rw-r--r--drivers/video/tegra/dc/hdmi2.0.c51
-rw-r--r--drivers/video/tegra/dc/mode.c57
-rw-r--r--drivers/video/tegra/dc/of_dc.c108
-rw-r--r--drivers/video/tegra/fb.c6
8 files changed, 156 insertions, 82 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index 9dfc890e9..0c0437e4a 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -6770,7 +6770,7 @@ static int tegra_dc_probe(struct platform_device *ndev)
6770 hotplug_init_status = dc->out_ops->hotplug_init(dc); 6770 hotplug_init_status = dc->out_ops->hotplug_init(dc);
6771 6771
6772 if (dc->out->type == TEGRA_DC_OUT_DP) { 6772 if (dc->out->type == TEGRA_DC_OUT_DP) {
6773 ret = tegra_dc_set_fbcon_boot_mode(dc); 6773 ret = tegra_dc_set_fbcon_boot_mode(dc, dc->edid);
6774 if (ret) 6774 if (ret)
6775 dev_err(&dc->ndev->dev, 6775 dev_err(&dc->ndev->dev,
6776 "Failed to set fbcon mode for DC %d\n", 6776 "Failed to set fbcon mode for DC %d\n",
diff --git a/drivers/video/tegra/dc/dc.h b/drivers/video/tegra/dc/dc.h
index f7859ea54..7a94afad1 100644
--- a/drivers/video/tegra/dc/dc.h
+++ b/drivers/video/tegra/dc/dc.h
@@ -677,6 +677,8 @@ struct tegra_dc_out {
677 struct completion user_vblank_comp; 677 struct completion user_vblank_comp;
678 678
679 bool is_ext_dp_panel; 679 bool is_ext_dp_panel;
680 /* Default mode for fbconsole */
681 struct fb_videomode *fbcon_default_mode;
680 682
681 int (*enable)(struct device *); 683 int (*enable)(struct device *);
682 int (*postpoweron)(struct device *); 684 int (*postpoweron)(struct device *);
@@ -981,7 +983,6 @@ int tegra_dc_to_fb_videomode(struct fb_videomode *fbmode,
981 const struct tegra_dc_mode *mode); 983 const struct tegra_dc_mode *mode);
982int tegra_dc_set_fb_mode(struct tegra_dc *dc, const struct fb_videomode *fbmode, 984int tegra_dc_set_fb_mode(struct tegra_dc *dc, const struct fb_videomode *fbmode,
983 bool stereo_mode); 985 bool stereo_mode);
984int tegra_dc_set_fbcon_boot_mode(struct tegra_dc *dc);
985 986
986unsigned tegra_dc_get_out_height(const struct tegra_dc *dc); 987unsigned tegra_dc_get_out_height(const struct tegra_dc *dc);
987unsigned tegra_dc_get_out_width(const struct tegra_dc *dc); 988unsigned tegra_dc_get_out_width(const struct tegra_dc *dc);
diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h
index dd73cd03f..9e8634432 100644
--- a/drivers/video/tegra/dc/dc_priv.h
+++ b/drivers/video/tegra/dc/dc_priv.h
@@ -976,6 +976,8 @@ static inline void tegra_dc_set_edid(struct tegra_dc *dc,
976 dc->edid = edid; 976 dc->edid = edid;
977} 977}
978 978
979int tegra_dc_set_fbcon_boot_mode(struct tegra_dc *dc, struct tegra_edid *edid);
980
979#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT 981#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
980static inline u32 tegra_dc_reg_l32(dma_addr_t v) 982static inline u32 tegra_dc_reg_l32(dma_addr_t v)
981{ 983{
diff --git a/drivers/video/tegra/dc/dp.c b/drivers/video/tegra/dc/dp.c
index 320a6e298..f76b7f8d7 100644
--- a/drivers/video/tegra/dc/dp.c
+++ b/drivers/video/tegra/dc/dp.c
@@ -2021,8 +2021,13 @@ static int tegra_dc_dp_init(struct tegra_dc *dc)
2021 tegra_hda_init(dc, dp); 2021 tegra_hda_init(dc, dp);
2022#endif 2022#endif
2023 2023
2024 if (!(dc->mode.pclk) && IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE)) 2024 if (!(dc->mode.pclk) && IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE)) {
2025 tegra_dc_set_fb_mode(dc, &tegra_dc_vga_mode, false); 2025 if (dc->out->fbcon_default_mode)
2026 tegra_dc_set_fb_mode(dc,
2027 dc->out->fbcon_default_mode, false);
2028 else
2029 tegra_dc_set_fb_mode(dc, &tegra_dc_vga_mode, false);
2030 }
2026 2031
2027 tegra_dc_dp_debugfs_create(dp); 2032 tegra_dc_dp_debugfs_create(dp);
2028 dp_instance++; 2033 dp_instance++;
diff --git a/drivers/video/tegra/dc/hdmi2.0.c b/drivers/video/tegra/dc/hdmi2.0.c
index f866db8f4..af10156ad 100644
--- a/drivers/video/tegra/dc/hdmi2.0.c
+++ b/drivers/video/tegra/dc/hdmi2.0.c
@@ -1687,57 +1687,16 @@ static int tegra_dc_hdmi_init(struct tegra_dc *dc)
1687 } 1687 }
1688 1688
1689 /* NOTE: Below code is applicable to L4T or embedded systems and is 1689 /* NOTE: Below code is applicable to L4T or embedded systems and is
1690 * protected accordingly. This section early enables DC with first mode 1690 * protected accordingly. This section chooses a mode to early
1691 * from the monitor specs. 1691 * enable DC.
1692 * In case there is no hotplug we are falling back
1693 * to default VGA mode.
1694 */ 1692 */
1695 if ((IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) || 1693 if ((IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) ||
1696 ((dc->pdata->flags & TEGRA_DC_FLAG_ENABLED) && 1694 ((dc->pdata->flags & TEGRA_DC_FLAG_ENABLED) &&
1697 (dc->pdata->flags & TEGRA_DC_FLAG_SET_EARLY_MODE))) && 1695 (dc->pdata->flags & TEGRA_DC_FLAG_SET_EARLY_MODE))) &&
1698 dc->out && (dc->out->type == TEGRA_DC_OUT_HDMI)) { 1696 dc->out && (dc->out->type == TEGRA_DC_OUT_HDMI)) {
1699 struct fb_monspecs specs; 1697 /* In case of seamless display, dc mode would already be set */
1700 1698 if (!dc->initialized)
1701 specs.modedb = NULL; 1699 tegra_dc_set_fbcon_boot_mode(dc, hdmi->edid);
1702
1703 /* If dc is initialized by bootloader or if display-timings
1704 * are specified in DT, dc mode would already be set.
1705 */
1706 if (!dc->initialized && !dc->out->n_modes) {
1707 if (tegra_dc_hpd(dc)) {
1708 if (!tegra_edid_get_monspecs(hdmi->edid,
1709 &specs)) {
1710 err = tegra_dc_set_fb_mode(dc,
1711 specs.modedb, false);
1712 if (err) {
1713 dev_err(&dc->ndev->dev,
1714 "%s: set DC mode from modedb,"
1715 " err = %d\n", __func__, err);
1716 }
1717 } else {
1718 /* Reading edid from monitor failed */
1719 err = tegra_dc_set_fb_mode(dc,
1720 &tegra_dc_vga_mode, false);
1721 if (err) {
1722 dev_err(&dc->ndev->dev,
1723 "%s: no edid, set VGA mode,"
1724 " err=%d\n", __func__, err);
1725 }
1726 }
1727 } else {
1728 /* No DT mode and HPD not detected */
1729 err = tegra_dc_set_fb_mode(dc,
1730 &tegra_dc_vga_mode, false);
1731 if (err) {
1732 dev_err(&dc->ndev->dev,
1733 "%s: fallback to VGA mode, err=%d\n",
1734 __func__, err);
1735 }
1736 }
1737
1738 if (specs.modedb != NULL)
1739 kfree(specs.modedb);
1740 }
1741 } 1700 }
1742 1701
1743#ifdef CONFIG_SWITCH 1702#ifdef CONFIG_SWITCH
diff --git a/drivers/video/tegra/dc/mode.c b/drivers/video/tegra/dc/mode.c
index ab3b2f523..d08af12aa 100644
--- a/drivers/video/tegra/dc/mode.c
+++ b/drivers/video/tegra/dc/mode.c
@@ -906,35 +906,66 @@ int tegra_dc_set_fb_mode(struct tegra_dc *dc,
906} 906}
907EXPORT_SYMBOL(tegra_dc_set_fb_mode); 907EXPORT_SYMBOL(tegra_dc_set_fb_mode);
908 908
909int tegra_dc_set_fbcon_boot_mode(struct tegra_dc *dc) 909int tegra_dc_set_fbcon_boot_mode(struct tegra_dc *dc, struct tegra_edid *edid)
910{ 910{
911 struct tegra_edid *edid = NULL;
912 struct fb_monspecs specs; 911 struct fb_monspecs specs;
913 int ret = 0; 912 int ret = 0;
914 913
915 specs.modedb = NULL; 914 specs.modedb = NULL;
916 if (tegra_fb_is_console_enabled(dc->pdata) && 915 if (tegra_fb_is_console_enabled(dc->pdata)) {
917 (!dc->initialized) && tegra_dc_hpd(dc)) {
918 switch (dc->out->type) { 916 switch (dc->out->type) {
919 case TEGRA_DC_OUT_HDMI: 917 case TEGRA_DC_OUT_HDMI:
920 break; 918 break;
921
922 case TEGRA_DC_OUT_DP: 919 case TEGRA_DC_OUT_DP:
923 if (!tegra_dc_is_ext_dp_panel(dc)) 920 if (!tegra_dc_is_ext_dp_panel(dc))
924 return 0; 921 return 0;
925
926 edid = dc->edid;
927 break; 922 break;
928 default: 923 default:
929 return -EINVAL; 924 return -EINVAL;
930 } 925 }
931 926
932 if (edid && !tegra_edid_get_monspecs(edid, &specs)) 927 /* In case of seamless display, dc mode would already be set */
933 ret = tegra_dc_set_fb_mode(dc, specs.modedb, false); 928 if (!dc->initialized) {
934 else 929 if (dc->out->fbcon_default_mode) {
935 ret = tegra_dc_set_fb_mode(dc, &tegra_dc_vga_mode, 930 ret = tegra_dc_set_fb_mode(dc,
936 false); 931 dc->out->fbcon_default_mode, false);
932 if (ret) {
933 dev_err(&dc->ndev->dev,
934 "%s: setting default fbcon mode failed,"
935 " err = %d\n", __func__, ret);
936 }
937 } else if (edid && tegra_dc_hpd(dc)) {
938 if (!tegra_edid_get_monspecs(edid, &specs)) {
939 ret = tegra_dc_set_fb_mode(dc,
940 specs.modedb, false);
941 if (ret) {
942 dev_err(&dc->ndev->dev,
943 "%s: set DC mode from modedb,"
944 " err = %d\n", __func__, ret);
945 }
946 } else {
947 /* Reading edid from monitor failed */
948 ret = tegra_dc_set_fb_mode(dc,
949 &tegra_dc_vga_mode, false);
950 if (ret) {
951 dev_err(&dc->ndev->dev,
952 "%s: no edid, set VGA mode,"
953 " err=%d\n", __func__, ret);
954 }
955 }
956 } else {
957 /* HPD not detected */
958 ret = tegra_dc_set_fb_mode(dc,
959 &tegra_dc_vga_mode, false);
960 if (ret) {
961 dev_err(&dc->ndev->dev,
962 "%s: fallback to VGA mode, err=%d\n",
963 __func__, ret);
964 }
965 }
966 }
937 } 967 }
968
938 if (specs.modedb != NULL) 969 if (specs.modedb != NULL)
939 kfree(specs.modedb); 970 kfree(specs.modedb);
940 return ret; 971 return ret;
diff --git a/drivers/video/tegra/dc/of_dc.c b/drivers/video/tegra/dc/of_dc.c
index b42c7042f..6e18a9371 100644
--- a/drivers/video/tegra/dc/of_dc.c
+++ b/drivers/video/tegra/dc/of_dc.c
@@ -931,25 +931,38 @@ static int parse_modes(struct tegra_dc_out *default_out,
931 OF_DC_LOG("of v_front_porch %d\n", temp); 931 OF_DC_LOG("of v_front_porch %d\n", temp);
932 goto parse_modes_fail; 932 goto parse_modes_fail;
933 } 933 }
934 934 /* Optional property. Don't fail if not specified */
935 for (i = 0; pins && (i < default_out->n_out_pins); i++) { 935 if (!of_property_read_u32(np, "vmode", &temp)) {
936 switch (pins[i].name) { 936 modes->vmode = temp;
937 case TEGRA_DC_OUT_PIN_DATA_ENABLE: 937 }
938 if (pins[i].pol == TEGRA_DC_OUT_PIN_POL_LOW) 938
939 modes->flags |= TEGRA_DC_MODE_FLAG_NEG_DE; 939 if (pins && default_out->n_out_pins) {
940 break; 940 for (i = 0; i < default_out->n_out_pins; i++) {
941 case TEGRA_DC_OUT_PIN_H_SYNC: 941 switch (pins[i].name) {
942 if (pins[i].pol == TEGRA_DC_OUT_PIN_POL_LOW) 942 case TEGRA_DC_OUT_PIN_DATA_ENABLE:
943 modes->flags |= TEGRA_DC_MODE_FLAG_NEG_H_SYNC; 943 if (pins[i].pol == TEGRA_DC_OUT_PIN_POL_LOW)
944 break; 944 modes->flags |=
945 case TEGRA_DC_OUT_PIN_V_SYNC: 945 TEGRA_DC_MODE_FLAG_NEG_DE;
946 if (pins[i].pol == TEGRA_DC_OUT_PIN_POL_LOW) 946 break;
947 modes->flags |= TEGRA_DC_MODE_FLAG_NEG_V_SYNC; 947 case TEGRA_DC_OUT_PIN_H_SYNC:
948 break; 948 if (pins[i].pol == TEGRA_DC_OUT_PIN_POL_LOW)
949 default: 949 modes->flags |=
950 /* Ignore other pin setting */ 950 TEGRA_DC_MODE_FLAG_NEG_H_SYNC;
951 break; 951 break;
952 case TEGRA_DC_OUT_PIN_V_SYNC:
953 if (pins[i].pol == TEGRA_DC_OUT_PIN_POL_LOW)
954 modes->flags |=
955 TEGRA_DC_MODE_FLAG_NEG_V_SYNC;
956 break;
957 default:
958 /* Ignore other pin setting */
959 break;
960 }
952 } 961 }
962 } else {
963 /* Optional property. Don't fail if not specified */
964 if (!of_property_read_u32(np, "flags", &temp))
965 modes->flags = temp;
953 } 966 }
954 967
955 return 0; 968 return 0;
@@ -958,6 +971,53 @@ parse_modes_fail:
958 return -EINVAL; 971 return -EINVAL;
959} 972}
960 973
974#if defined(CONFIG_FRAMEBUFFER_CONSOLE)
975int parse_fbcon_default_mode(struct device_node *np_target_disp,
976 struct platform_device *ndev,
977 struct tegra_dc_platform_data *pdata)
978{
979 struct device_node *fbcon_default_mode_np = NULL;
980 int err = 0;
981
982 fbcon_default_mode_np = of_get_child_by_name(np_target_disp,
983 "nvidia,fbcon-default-mode");
984
985 if (!fbcon_default_mode_np) {
986 pdata->default_out->fbcon_default_mode = NULL;
987 } else {
988 struct tegra_dc_mode fbcon_dc_mode;
989 memset(&fbcon_dc_mode, 0x0,
990 sizeof(struct tegra_dc_mode));
991 pdata->default_out->fbcon_default_mode =
992 devm_kzalloc(&ndev->dev,
993 sizeof(struct fb_videomode), GFP_KERNEL);
994 if (!pdata->default_out->fbcon_default_mode) {
995 pr_err("%s: not enough memory for fbcon mode\n",
996 __func__);
997 err = -ENOMEM;
998 goto fail_fbcon_parse;
999 }
1000
1001 err = parse_modes(pdata->default_out,
1002 fbcon_default_mode_np, &fbcon_dc_mode);
1003 if (err) {
1004 pr_err("%s: failed to parse fbcon mode\n", __func__);
1005 goto fail_fbcon_parse;
1006 }
1007
1008 err = tegra_dc_to_fb_videomode(
1009 pdata->default_out->fbcon_default_mode, &fbcon_dc_mode);
1010 if (err) {
1011 pr_err("%s: error converting fbcon mode\n", __func__);
1012 goto fail_fbcon_parse;
1013 }
1014 }
1015
1016fail_fbcon_parse:
1017 return err;
1018}
1019#endif
1020
961static int parse_cmu_data(struct device_node *np, 1021static int parse_cmu_data(struct device_node *np,
962 struct tegra_dc_cmu *cmu) 1022 struct tegra_dc_cmu *cmu)
963{ 1023{
@@ -3019,6 +3079,18 @@ struct tegra_dc_platform_data *of_dc_parse_platform_data(
3019 } 3079 }
3020 } 3080 }
3021 3081
3082#if defined(CONFIG_FRAMEBUFFER_CONSOLE)
3083 /* Default mode for fbconsole */
3084 if ((pdata->default_out->type == TEGRA_DC_OUT_HDMI) ||
3085 (pdata->default_out->type == TEGRA_DC_OUT_DP)) {
3086 err = parse_fbcon_default_mode(np_target_disp, ndev, pdata);
3087 if (err) {
3088 pr_err("%s: parsing fbcon mode failed\n", __func__);
3089 goto fail_parse;
3090 }
3091 }
3092#endif
3093
3022 vrr_np = of_get_child_by_name(np_target_disp, "vrr-settings"); 3094 vrr_np = of_get_child_by_name(np_target_disp, "vrr-settings");
3023 if (!vrr_np || (def_out->n_modes < 2)) { 3095 if (!vrr_np || (def_out->n_modes < 2)) {
3024 pr_debug("%s: could not find vrr-settings node\n", __func__); 3096 pr_debug("%s: could not find vrr-settings node\n", __func__);
diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c
index 94dbf8f90..0573bfeb1 100644
--- a/drivers/video/tegra/fb.c
+++ b/drivers/video/tegra/fb.c
@@ -927,7 +927,11 @@ void tegra_fb_update_monspecs(struct tegra_fb_info *fb_info,
927 tegra_dc_to_fb_videomode(&fb_mode, &dc->cached_mode); 927 tegra_dc_to_fb_videomode(&fb_mode, &dc->cached_mode);
928 dc->use_cached_mode = false; 928 dc->use_cached_mode = false;
929 } else { 929 } else {
930 memcpy(&fb_mode, &specs->modedb[0], 930 if (!dc->out->fbcon_default_mode)
931 memcpy(&fb_mode, &specs->modedb[0],
932 sizeof(struct fb_videomode));
933 else
934 memcpy(&fb_mode, dc->out->fbcon_default_mode,
931 sizeof(struct fb_videomode)); 935 sizeof(struct fb_videomode));
932 } 936 }
933 937