Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/tegra: sor: Add DisplayPort support

Add support for regular DisplayPort on Tegra210 and Tegra186.

Signed-off-by: Thierry Reding <treding@nvidia.com>

+348 -6
+6 -4
drivers/gpu/drm/tegra/dp.c
··· 623 623 return err; 624 624 } 625 625 626 - drm_dp_link_train_adjust(&link->train); 627 - 628 626 if (link->train.clock_recovered) 629 627 break; 628 + 629 + drm_dp_link_train_adjust(&link->train); 630 630 } 631 631 632 632 return 0; ··· 682 682 return err; 683 683 } 684 684 685 - drm_dp_link_train_adjust(&link->train); 686 - 687 685 if (link->train.channel_equalized) 688 686 break; 687 + 688 + drm_dp_link_train_adjust(&link->train); 689 689 } 690 690 691 691 return 0; ··· 850 850 int drm_dp_link_train(struct drm_dp_link *link) 851 851 { 852 852 int err; 853 + 854 + drm_dp_link_train_init(&link->train); 853 855 854 856 if (link->caps.fast_training) { 855 857 if (drm_dp_link_train_valid(&link->train)) {
+341 -2
drivers/gpu/drm/tegra/sor.c
··· 2904 2904 .atomic_check = tegra_sor_encoder_atomic_check, 2905 2905 }; 2906 2906 2907 + static void tegra_sor_dp_disable(struct drm_encoder *encoder) 2908 + { 2909 + struct tegra_output *output = encoder_to_output(encoder); 2910 + struct tegra_dc *dc = to_tegra_dc(encoder->crtc); 2911 + struct tegra_sor *sor = to_sor(output); 2912 + u32 value; 2913 + int err; 2914 + 2915 + err = drm_dp_link_power_down(sor->aux, &sor->link); 2916 + if (err < 0) 2917 + dev_err(sor->dev, "failed to power down link: %d\n", err); 2918 + 2919 + err = tegra_sor_detach(sor); 2920 + if (err < 0) 2921 + dev_err(sor->dev, "failed to detach SOR: %d\n", err); 2922 + 2923 + tegra_sor_writel(sor, 0, SOR_STATE1); 2924 + tegra_sor_update(sor); 2925 + 2926 + value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 2927 + 2928 + if (!sor->soc->has_nvdisplay) 2929 + value &= ~(SOR1_TIMING_CYA | SOR_ENABLE(1)); 2930 + else 2931 + value &= ~SOR_ENABLE(sor->index); 2932 + 2933 + tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 2934 + tegra_dc_commit(dc); 2935 + 2936 + value = tegra_sor_readl(sor, SOR_STATE1); 2937 + value &= ~SOR_STATE_ASY_PROTOCOL_MASK; 2938 + value &= ~SOR_STATE_ASY_SUBOWNER_MASK; 2939 + value &= ~SOR_STATE_ASY_OWNER_MASK; 2940 + tegra_sor_writel(sor, value, SOR_STATE1); 2941 + tegra_sor_update(sor); 2942 + 2943 + /* switch to safe parent clock */ 2944 + err = tegra_sor_set_parent_clock(sor, sor->clk_safe); 2945 + if (err < 0) 2946 + dev_err(sor->dev, "failed to set safe clock: %d\n", err); 2947 + 2948 + err = tegra_sor_power_down(sor); 2949 + if (err < 0) 2950 + dev_err(sor->dev, "failed to power down SOR: %d\n", err); 2951 + 2952 + err = tegra_io_pad_power_disable(sor->pad); 2953 + if (err < 0) 2954 + dev_err(sor->dev, "failed to power off I/O pad: %d\n", err); 2955 + 2956 + err = drm_dp_aux_disable(sor->aux); 2957 + if (err < 0) 2958 + dev_err(sor->dev, "failed disable DPAUX: %d\n", err); 2959 + 2960 + pm_runtime_put(sor->dev); 2961 + } 2962 + 2963 + static void tegra_sor_dp_enable(struct drm_encoder *encoder) 2964 + { 2965 + struct tegra_output *output = encoder_to_output(encoder); 2966 + struct tegra_dc *dc = to_tegra_dc(encoder->crtc); 2967 + struct tegra_sor *sor = to_sor(output); 2968 + struct tegra_sor_config config; 2969 + struct tegra_sor_state *state; 2970 + struct drm_display_mode *mode; 2971 + struct drm_display_info *info; 2972 + unsigned int i; 2973 + u32 value; 2974 + int err; 2975 + 2976 + state = to_sor_state(output->connector.state); 2977 + mode = &encoder->crtc->state->adjusted_mode; 2978 + info = &output->connector.display_info; 2979 + 2980 + pm_runtime_get_sync(sor->dev); 2981 + 2982 + /* switch to safe parent clock */ 2983 + err = tegra_sor_set_parent_clock(sor, sor->clk_safe); 2984 + if (err < 0) 2985 + dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); 2986 + 2987 + err = tegra_io_pad_power_enable(sor->pad); 2988 + if (err < 0) 2989 + dev_err(sor->dev, "failed to power on LVDS rail: %d\n", err); 2990 + 2991 + usleep_range(20, 100); 2992 + 2993 + err = drm_dp_aux_enable(sor->aux); 2994 + if (err < 0) 2995 + dev_err(sor->dev, "failed to enable DPAUX: %d\n", err); 2996 + 2997 + err = drm_dp_link_probe(sor->aux, &sor->link); 2998 + if (err < 0) 2999 + dev_err(sor->dev, "failed to probe DP link: %d\n", err); 3000 + 3001 + err = drm_dp_link_choose(&sor->link, mode, info); 3002 + if (err < 0) 3003 + dev_err(sor->dev, "failed to choose link: %d\n", err); 3004 + 3005 + value = tegra_sor_readl(sor, sor->soc->regs->pll2); 3006 + value &= ~SOR_PLL2_BANDGAP_POWERDOWN; 3007 + tegra_sor_writel(sor, value, sor->soc->regs->pll2); 3008 + 3009 + usleep_range(20, 40); 3010 + 3011 + value = tegra_sor_readl(sor, sor->soc->regs->pll3); 3012 + value |= SOR_PLL3_PLL_VDD_MODE_3V3; 3013 + tegra_sor_writel(sor, value, sor->soc->regs->pll3); 3014 + 3015 + value = tegra_sor_readl(sor, sor->soc->regs->pll0); 3016 + value &= ~(SOR_PLL0_VCOPD | SOR_PLL0_PWR); 3017 + tegra_sor_writel(sor, value, sor->soc->regs->pll0); 3018 + 3019 + value = tegra_sor_readl(sor, sor->soc->regs->pll2); 3020 + value &= ~SOR_PLL2_SEQ_PLLCAPPD_ENFORCE; 3021 + value |= SOR_PLL2_SEQ_PLLCAPPD; 3022 + tegra_sor_writel(sor, value, sor->soc->regs->pll2); 3023 + 3024 + usleep_range(200, 400); 3025 + 3026 + value = tegra_sor_readl(sor, sor->soc->regs->pll2); 3027 + value &= ~SOR_PLL2_POWERDOWN_OVERRIDE; 3028 + value &= ~SOR_PLL2_PORT_POWERDOWN; 3029 + tegra_sor_writel(sor, value, sor->soc->regs->pll2); 3030 + 3031 + value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 3032 + value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; 3033 + value |= SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_DPCLK; 3034 + tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 3035 + 3036 + usleep_range(200, 400); 3037 + 3038 + value = tegra_sor_readl(sor, SOR_DP_SPARE0); 3039 + /* XXX not in TRM */ 3040 + value &= ~SOR_DP_SPARE_PANEL_INTERNAL; 3041 + value |= SOR_DP_SPARE_SEQ_ENABLE; 3042 + tegra_sor_writel(sor, value, SOR_DP_SPARE0); 3043 + 3044 + /* XXX not in TRM */ 3045 + tegra_sor_writel(sor, 0, SOR_LVDS); 3046 + 3047 + value = tegra_sor_readl(sor, sor->soc->regs->pll0); 3048 + value &= ~SOR_PLL0_ICHPMP_MASK; 3049 + value &= ~SOR_PLL0_VCOCAP_MASK; 3050 + value |= SOR_PLL0_ICHPMP(0x1); 3051 + value |= SOR_PLL0_VCOCAP(0x3); 3052 + value |= SOR_PLL0_RESISTOR_EXT; 3053 + tegra_sor_writel(sor, value, sor->soc->regs->pll0); 3054 + 3055 + /* XXX not in TRM */ 3056 + for (value = 0, i = 0; i < 5; i++) 3057 + value |= SOR_XBAR_CTRL_LINK0_XSEL(i, sor->soc->xbar_cfg[i]) | 3058 + SOR_XBAR_CTRL_LINK1_XSEL(i, i); 3059 + 3060 + tegra_sor_writel(sor, 0x00000000, SOR_XBAR_POL); 3061 + tegra_sor_writel(sor, value, SOR_XBAR_CTRL); 3062 + 3063 + /* switch to DP parent clock */ 3064 + err = tegra_sor_set_parent_clock(sor, sor->clk_pad); 3065 + if (err < 0) { 3066 + dev_err(sor->dev, "failed to switch to pad clock: %d\n", err); 3067 + return; 3068 + } 3069 + 3070 + err = clk_set_parent(sor->clk, sor->clk_parent); 3071 + if (err < 0) { 3072 + dev_err(sor->dev, "failed to switch to parent clock: %d\n", err); 3073 + return; 3074 + } 3075 + 3076 + /* use DP-A protocol */ 3077 + value = tegra_sor_readl(sor, SOR_STATE1); 3078 + value &= ~SOR_STATE_ASY_PROTOCOL_MASK; 3079 + value |= SOR_STATE_ASY_PROTOCOL_DP_A; 3080 + tegra_sor_writel(sor, value, SOR_STATE1); 3081 + 3082 + /* enable port */ 3083 + value = tegra_sor_readl(sor, SOR_DP_LINKCTL0); 3084 + value |= SOR_DP_LINKCTL_ENABLE; 3085 + tegra_sor_writel(sor, value, SOR_DP_LINKCTL0); 3086 + 3087 + tegra_sor_dp_term_calibrate(sor); 3088 + 3089 + err = drm_dp_link_train(&sor->link); 3090 + if (err < 0) 3091 + dev_err(sor->dev, "link training failed: %d\n", err); 3092 + else 3093 + dev_dbg(sor->dev, "link training succeeded\n"); 3094 + 3095 + err = drm_dp_link_power_up(sor->aux, &sor->link); 3096 + if (err < 0) 3097 + dev_err(sor->dev, "failed to power up DP link: %d\n", err); 3098 + 3099 + /* compute configuration */ 3100 + memset(&config, 0, sizeof(config)); 3101 + config.bits_per_pixel = state->bpc * 3; 3102 + 3103 + err = tegra_sor_compute_config(sor, mode, &config, &sor->link); 3104 + if (err < 0) 3105 + dev_err(sor->dev, "failed to compute configuration: %d\n", err); 3106 + 3107 + tegra_sor_apply_config(sor, &config); 3108 + tegra_sor_mode_set(sor, mode, state); 3109 + tegra_sor_update(sor); 3110 + 3111 + err = tegra_sor_power_up(sor, 250); 3112 + if (err < 0) 3113 + dev_err(sor->dev, "failed to power up SOR: %d\n", err); 3114 + 3115 + /* attach and wake up */ 3116 + err = tegra_sor_attach(sor); 3117 + if (err < 0) 3118 + dev_err(sor->dev, "failed to attach SOR: %d\n", err); 3119 + 3120 + value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 3121 + value |= SOR_ENABLE(sor->index); 3122 + tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 3123 + 3124 + tegra_dc_commit(dc); 3125 + 3126 + err = tegra_sor_wakeup(sor); 3127 + if (err < 0) 3128 + dev_err(sor->dev, "failed to wakeup SOR: %d\n", err); 3129 + } 3130 + 3131 + static const struct drm_encoder_helper_funcs tegra_sor_dp_helpers = { 3132 + .disable = tegra_sor_dp_disable, 3133 + .enable = tegra_sor_dp_enable, 3134 + .atomic_check = tegra_sor_encoder_atomic_check, 3135 + }; 3136 + 2907 3137 static int tegra_sor_init(struct host1x_client *client) 2908 3138 { 2909 3139 struct drm_device *drm = dev_get_drvdata(client->parent); ··· 3160 2930 } else if (sor->soc->supports_dp) { 3161 2931 connector = DRM_MODE_CONNECTOR_DisplayPort; 3162 2932 encoder = DRM_MODE_ENCODER_TMDS; 2933 + helpers = &tegra_sor_dp_helpers; 3163 2934 } 3164 2935 3165 2936 sor->link.ops = &tegra_sor_dp_link_ops; ··· 3344 3113 .name = "HDMI", 3345 3114 .probe = tegra_sor_hdmi_probe, 3346 3115 .remove = tegra_sor_hdmi_remove, 3116 + }; 3117 + 3118 + static int tegra_sor_dp_probe(struct tegra_sor *sor) 3119 + { 3120 + int err; 3121 + 3122 + sor->avdd_io_supply = devm_regulator_get(sor->dev, "avdd-io-hdmi-dp"); 3123 + if (IS_ERR(sor->avdd_io_supply)) 3124 + return PTR_ERR(sor->avdd_io_supply); 3125 + 3126 + err = regulator_enable(sor->avdd_io_supply); 3127 + if (err < 0) 3128 + return err; 3129 + 3130 + sor->vdd_pll_supply = devm_regulator_get(sor->dev, "vdd-hdmi-dp-pll"); 3131 + if (IS_ERR(sor->vdd_pll_supply)) 3132 + return PTR_ERR(sor->vdd_pll_supply); 3133 + 3134 + err = regulator_enable(sor->vdd_pll_supply); 3135 + if (err < 0) 3136 + return err; 3137 + 3138 + return 0; 3139 + } 3140 + 3141 + static int tegra_sor_dp_remove(struct tegra_sor *sor) 3142 + { 3143 + regulator_disable(sor->vdd_pll_supply); 3144 + regulator_disable(sor->avdd_io_supply); 3145 + 3146 + return 0; 3147 + } 3148 + 3149 + static const struct tegra_sor_ops tegra_sor_dp_ops = { 3150 + .name = "DP", 3151 + .probe = tegra_sor_dp_probe, 3152 + .remove = tegra_sor_dp_remove, 3347 3153 }; 3348 3154 3349 3155 static const u8 tegra124_sor_xbar_cfg[5] = { ··· 3576 3308 2, 1, 0, 3, 4 3577 3309 }; 3578 3310 3311 + static const u8 tegra210_sor_lane_map[4] = { 3312 + 0, 1, 2, 3, 3313 + }; 3314 + 3579 3315 static const struct tegra_sor_soc tegra210_sor = { 3580 3316 .supports_edp = true, 3581 3317 .supports_lvds = false, ··· 3590 3318 .has_nvdisplay = false, 3591 3319 3592 3320 .xbar_cfg = tegra210_sor_xbar_cfg, 3321 + .lane_map = tegra210_sor_lane_map, 3322 + .voltage_swing = tegra124_sor_voltage_swing, 3323 + .pre_emphasis = tegra124_sor_pre_emphasis, 3324 + .post_cursor = tegra124_sor_post_cursor, 3325 + .tx_pu = tegra124_sor_tx_pu, 3593 3326 }; 3594 3327 3595 3328 static const struct tegra_sor_soc tegra210_sor1 = { ··· 3609 3332 .num_settings = ARRAY_SIZE(tegra210_sor_hdmi_defaults), 3610 3333 .settings = tegra210_sor_hdmi_defaults, 3611 3334 .xbar_cfg = tegra210_sor_xbar_cfg, 3335 + .lane_map = tegra210_sor_lane_map, 3336 + .voltage_swing = tegra124_sor_voltage_swing, 3337 + .pre_emphasis = tegra124_sor_pre_emphasis, 3338 + .post_cursor = tegra124_sor_post_cursor, 3339 + .tx_pu = tegra124_sor_tx_pu, 3612 3340 }; 3613 3341 3614 3342 static const struct tegra_sor_regs tegra186_sor_regs = { ··· 3631 3349 .dp_padctl2 = 0x16a, 3632 3350 }; 3633 3351 3352 + static const u8 tegra186_sor_voltage_swing[4][4][4] = { 3353 + { 3354 + { 0x13, 0x19, 0x1e, 0x28 }, 3355 + { 0x1e, 0x25, 0x2d, }, 3356 + { 0x28, 0x32, }, 3357 + { 0x39, }, 3358 + }, { 3359 + { 0x12, 0x16, 0x1b, 0x25 }, 3360 + { 0x1c, 0x23, 0x2a, }, 3361 + { 0x25, 0x2f, }, 3362 + { 0x37, } 3363 + }, { 3364 + { 0x12, 0x16, 0x1a, 0x22 }, 3365 + { 0x1b, 0x20, 0x27, }, 3366 + { 0x24, 0x2d, }, 3367 + { 0x35, }, 3368 + }, { 3369 + { 0x11, 0x14, 0x17, 0x1f }, 3370 + { 0x19, 0x1e, 0x24, }, 3371 + { 0x22, 0x2a, }, 3372 + { 0x32, }, 3373 + }, 3374 + }; 3375 + 3376 + static const u8 tegra186_sor_pre_emphasis[4][4][4] = { 3377 + { 3378 + { 0x00, 0x08, 0x12, 0x24 }, 3379 + { 0x01, 0x0e, 0x1d, }, 3380 + { 0x01, 0x13, }, 3381 + { 0x00, }, 3382 + }, { 3383 + { 0x00, 0x08, 0x12, 0x24 }, 3384 + { 0x00, 0x0e, 0x1d, }, 3385 + { 0x00, 0x13, }, 3386 + { 0x00 }, 3387 + }, { 3388 + { 0x00, 0x08, 0x14, 0x24 }, 3389 + { 0x00, 0x0e, 0x1d, }, 3390 + { 0x00, 0x13, }, 3391 + { 0x00, }, 3392 + }, { 3393 + { 0x00, 0x08, 0x12, 0x24 }, 3394 + { 0x00, 0x0e, 0x1d, }, 3395 + { 0x00, 0x13, }, 3396 + { 0x00, }, 3397 + }, 3398 + }; 3399 + 3634 3400 static const struct tegra_sor_soc tegra186_sor = { 3635 3401 .supports_edp = false, 3636 3402 .supports_lvds = false, ··· 3689 3359 .has_nvdisplay = true, 3690 3360 3691 3361 .xbar_cfg = tegra124_sor_xbar_cfg, 3362 + .lane_map = tegra124_sor_lane_map, 3363 + .voltage_swing = tegra186_sor_voltage_swing, 3364 + .pre_emphasis = tegra186_sor_pre_emphasis, 3365 + .post_cursor = tegra124_sor_post_cursor, 3366 + .tx_pu = tegra124_sor_tx_pu, 3692 3367 }; 3693 3368 3694 3369 static const struct tegra_sor_soc tegra186_sor1 = { ··· 3708 3373 .num_settings = ARRAY_SIZE(tegra186_sor_hdmi_defaults), 3709 3374 .settings = tegra186_sor_hdmi_defaults, 3710 3375 .xbar_cfg = tegra124_sor_xbar_cfg, 3376 + .lane_map = tegra124_sor_lane_map, 3377 + .voltage_swing = tegra186_sor_voltage_swing, 3378 + .pre_emphasis = tegra186_sor_pre_emphasis, 3379 + .post_cursor = tegra124_sor_post_cursor, 3380 + .tx_pu = tegra124_sor_tx_pu, 3711 3381 }; 3712 3382 3713 3383 static const struct tegra_sor_regs tegra194_sor_regs = { ··· 3870 3530 sor->ops = &tegra_sor_edp_ops; 3871 3531 sor->pad = TEGRA_IO_PAD_LVDS; 3872 3532 } else if (sor->soc->supports_dp) { 3873 - dev_err(&pdev->dev, "DisplayPort not supported yet\n"); 3874 - return -ENODEV; 3533 + sor->ops = &tegra_sor_dp_ops; 3875 3534 } else { 3876 3535 dev_err(&pdev->dev, "unknown (DP) support\n"); 3877 3536 return -ENODEV;
+1
drivers/gpu/drm/tegra/sor.h
··· 39 39 #define SOR_STATE_ASY_CRC_MODE_NON_ACTIVE (0x2 << 6) 40 40 #define SOR_STATE_ASY_CRC_MODE_COMPLETE (0x1 << 6) 41 41 #define SOR_STATE_ASY_CRC_MODE_ACTIVE (0x0 << 6) 42 + #define SOR_STATE_ASY_SUBOWNER_MASK (0x3 << 4) 42 43 #define SOR_STATE_ASY_OWNER_MASK 0xf 43 44 #define SOR_STATE_ASY_OWNER(x) (((x) & 0xf) << 0) 44 45