16b6b6042SThierry Reding /* 26b6b6042SThierry Reding * Copyright (C) 2013 NVIDIA Corporation 36b6b6042SThierry Reding * 46b6b6042SThierry Reding * This program is free software; you can redistribute it and/or modify 56b6b6042SThierry Reding * it under the terms of the GNU General Public License version 2 as 66b6b6042SThierry Reding * published by the Free Software Foundation. 76b6b6042SThierry Reding */ 86b6b6042SThierry Reding 96b6b6042SThierry Reding #include <linux/clk.h> 10b299221cSThierry Reding #include <linux/clk-provider.h> 11a82752e1SThierry Reding #include <linux/debugfs.h> 126fad8f66SThierry Reding #include <linux/gpio.h> 136b6b6042SThierry Reding #include <linux/io.h> 14459cc2c6SThierry Reding #include <linux/of_device.h> 156b6b6042SThierry Reding #include <linux/platform_device.h> 16aaff8bd2SThierry Reding #include <linux/pm_runtime.h> 17459cc2c6SThierry Reding #include <linux/regulator/consumer.h> 186b6b6042SThierry Reding #include <linux/reset.h> 19306a7f91SThierry Reding 207232398aSThierry Reding #include <soc/tegra/pmc.h> 216b6b6042SThierry Reding 224aa3df71SThierry Reding #include <drm/drm_atomic_helper.h> 236b6b6042SThierry Reding #include <drm/drm_dp_helper.h> 246fad8f66SThierry Reding #include <drm/drm_panel.h> 256b6b6042SThierry Reding 266b6b6042SThierry Reding #include "dc.h" 276b6b6042SThierry Reding #include "drm.h" 286b6b6042SThierry Reding #include "sor.h" 29932f6529SThierry Reding #include "trace.h" 306b6b6042SThierry Reding 31*c57997bcSThierry Reding /* 32*c57997bcSThierry Reding * XXX Remove this after the commit adding it to soc/tegra/pmc.h has been 33*c57997bcSThierry Reding * merged. Having this around after the commit is merged should be safe since 34*c57997bcSThierry Reding * the preprocessor will effectively replace all occurrences and therefore no 35*c57997bcSThierry Reding * duplicate will be defined. 36*c57997bcSThierry Reding */ 37*c57997bcSThierry Reding #define TEGRA_IO_PAD_HDMI_DP0 26 38*c57997bcSThierry Reding 39459cc2c6SThierry Reding #define SOR_REKEY 0x38 40459cc2c6SThierry Reding 41459cc2c6SThierry Reding struct tegra_sor_hdmi_settings { 42459cc2c6SThierry Reding unsigned long frequency; 43459cc2c6SThierry Reding 44459cc2c6SThierry Reding u8 vcocap; 45*c57997bcSThierry Reding u8 filter; 46459cc2c6SThierry Reding u8 ichpmp; 47459cc2c6SThierry Reding u8 loadadj; 48*c57997bcSThierry Reding u8 tmds_termadj; 49*c57997bcSThierry Reding u8 tx_pu_value; 50*c57997bcSThierry Reding u8 bg_temp_coef; 51*c57997bcSThierry Reding u8 bg_vref_level; 52*c57997bcSThierry Reding u8 avdd10_level; 53*c57997bcSThierry Reding u8 avdd14_level; 54*c57997bcSThierry Reding u8 sparepll; 55459cc2c6SThierry Reding 56459cc2c6SThierry Reding u8 drive_current[4]; 57459cc2c6SThierry Reding u8 preemphasis[4]; 58459cc2c6SThierry Reding }; 59459cc2c6SThierry Reding 60459cc2c6SThierry Reding #if 1 61459cc2c6SThierry Reding static const struct tegra_sor_hdmi_settings tegra210_sor_hdmi_defaults[] = { 62459cc2c6SThierry Reding { 63459cc2c6SThierry Reding .frequency = 54000000, 64459cc2c6SThierry Reding .vcocap = 0x0, 65*c57997bcSThierry Reding .filter = 0x0, 66459cc2c6SThierry Reding .ichpmp = 0x1, 67459cc2c6SThierry Reding .loadadj = 0x3, 68*c57997bcSThierry Reding .tmds_termadj = 0x9, 69*c57997bcSThierry Reding .tx_pu_value = 0x10, 70*c57997bcSThierry Reding .bg_temp_coef = 0x3, 71*c57997bcSThierry Reding .bg_vref_level = 0x8, 72*c57997bcSThierry Reding .avdd10_level = 0x4, 73*c57997bcSThierry Reding .avdd14_level = 0x4, 74*c57997bcSThierry Reding .sparepll = 0x0, 75459cc2c6SThierry Reding .drive_current = { 0x33, 0x3a, 0x3a, 0x3a }, 76459cc2c6SThierry Reding .preemphasis = { 0x00, 0x00, 0x00, 0x00 }, 77459cc2c6SThierry Reding }, { 78459cc2c6SThierry Reding .frequency = 75000000, 79459cc2c6SThierry Reding .vcocap = 0x3, 80*c57997bcSThierry Reding .filter = 0x0, 81459cc2c6SThierry Reding .ichpmp = 0x1, 82459cc2c6SThierry Reding .loadadj = 0x3, 83*c57997bcSThierry Reding .tmds_termadj = 0x9, 84*c57997bcSThierry Reding .tx_pu_value = 0x40, 85*c57997bcSThierry Reding .bg_temp_coef = 0x3, 86*c57997bcSThierry Reding .bg_vref_level = 0x8, 87*c57997bcSThierry Reding .avdd10_level = 0x4, 88*c57997bcSThierry Reding .avdd14_level = 0x4, 89*c57997bcSThierry Reding .sparepll = 0x0, 90459cc2c6SThierry Reding .drive_current = { 0x33, 0x3a, 0x3a, 0x3a }, 91459cc2c6SThierry Reding .preemphasis = { 0x00, 0x00, 0x00, 0x00 }, 92459cc2c6SThierry Reding }, { 93459cc2c6SThierry Reding .frequency = 150000000, 94459cc2c6SThierry Reding .vcocap = 0x3, 95*c57997bcSThierry Reding .filter = 0x0, 96459cc2c6SThierry Reding .ichpmp = 0x1, 97459cc2c6SThierry Reding .loadadj = 0x3, 98*c57997bcSThierry Reding .tmds_termadj = 0x9, 99*c57997bcSThierry Reding .tx_pu_value = 0x66, 100*c57997bcSThierry Reding .bg_temp_coef = 0x3, 101*c57997bcSThierry Reding .bg_vref_level = 0x8, 102*c57997bcSThierry Reding .avdd10_level = 0x4, 103*c57997bcSThierry Reding .avdd14_level = 0x4, 104*c57997bcSThierry Reding .sparepll = 0x0, 105459cc2c6SThierry Reding .drive_current = { 0x33, 0x3a, 0x3a, 0x3a }, 106459cc2c6SThierry Reding .preemphasis = { 0x00, 0x00, 0x00, 0x00 }, 107459cc2c6SThierry Reding }, { 108459cc2c6SThierry Reding .frequency = 300000000, 109459cc2c6SThierry Reding .vcocap = 0x3, 110*c57997bcSThierry Reding .filter = 0x0, 111459cc2c6SThierry Reding .ichpmp = 0x1, 112459cc2c6SThierry Reding .loadadj = 0x3, 113*c57997bcSThierry Reding .tmds_termadj = 0x9, 114*c57997bcSThierry Reding .tx_pu_value = 0x66, 115*c57997bcSThierry Reding .bg_temp_coef = 0x3, 116*c57997bcSThierry Reding .bg_vref_level = 0xa, 117*c57997bcSThierry Reding .avdd10_level = 0x4, 118*c57997bcSThierry Reding .avdd14_level = 0x4, 119*c57997bcSThierry Reding .sparepll = 0x0, 120459cc2c6SThierry Reding .drive_current = { 0x33, 0x3f, 0x3f, 0x3f }, 121459cc2c6SThierry Reding .preemphasis = { 0x00, 0x17, 0x17, 0x17 }, 122459cc2c6SThierry Reding }, { 123459cc2c6SThierry Reding .frequency = 600000000, 124459cc2c6SThierry Reding .vcocap = 0x3, 125*c57997bcSThierry Reding .filter = 0x0, 126459cc2c6SThierry Reding .ichpmp = 0x1, 127459cc2c6SThierry Reding .loadadj = 0x3, 128*c57997bcSThierry Reding .tmds_termadj = 0x9, 129*c57997bcSThierry Reding .tx_pu_value = 0x66, 130*c57997bcSThierry Reding .bg_temp_coef = 0x3, 131*c57997bcSThierry Reding .bg_vref_level = 0x8, 132*c57997bcSThierry Reding .avdd10_level = 0x4, 133*c57997bcSThierry Reding .avdd14_level = 0x4, 134*c57997bcSThierry Reding .sparepll = 0x0, 135459cc2c6SThierry Reding .drive_current = { 0x33, 0x3f, 0x3f, 0x3f }, 136459cc2c6SThierry Reding .preemphasis = { 0x00, 0x00, 0x00, 0x00 }, 137459cc2c6SThierry Reding }, 138459cc2c6SThierry Reding }; 139459cc2c6SThierry Reding #else 140459cc2c6SThierry Reding static const struct tegra_sor_hdmi_settings tegra210_sor_hdmi_defaults[] = { 141459cc2c6SThierry Reding { 142459cc2c6SThierry Reding .frequency = 75000000, 143459cc2c6SThierry Reding .vcocap = 0x3, 144*c57997bcSThierry Reding .filter = 0x0, 145459cc2c6SThierry Reding .ichpmp = 0x1, 146459cc2c6SThierry Reding .loadadj = 0x3, 147*c57997bcSThierry Reding .tmds_termadj = 0x9, 148*c57997bcSThierry Reding .tx_pu_value = 0x40, 149*c57997bcSThierry Reding .bg_temp_coef = 0x3, 150*c57997bcSThierry Reding .bg_vref_level = 0x8, 151*c57997bcSThierry Reding .avdd10_level = 0x4, 152*c57997bcSThierry Reding .avdd14_level = 0x4, 153*c57997bcSThierry Reding .sparepll = 0x0, 154459cc2c6SThierry Reding .drive_current = { 0x29, 0x29, 0x29, 0x29 }, 155459cc2c6SThierry Reding .preemphasis = { 0x00, 0x00, 0x00, 0x00 }, 156459cc2c6SThierry Reding }, { 157459cc2c6SThierry Reding .frequency = 150000000, 158459cc2c6SThierry Reding .vcocap = 0x3, 159*c57997bcSThierry Reding .filter = 0x0, 160459cc2c6SThierry Reding .ichpmp = 0x1, 161459cc2c6SThierry Reding .loadadj = 0x3, 162*c57997bcSThierry Reding .tmds_termadj = 0x9, 163*c57997bcSThierry Reding .tx_pu_value = 0x66, 164*c57997bcSThierry Reding .bg_temp_coef = 0x3, 165*c57997bcSThierry Reding .bg_vref_level = 0x8, 166*c57997bcSThierry Reding .avdd10_level = 0x4, 167*c57997bcSThierry Reding .avdd14_level = 0x4, 168*c57997bcSThierry Reding .sparepll = 0x0, 169459cc2c6SThierry Reding .drive_current = { 0x30, 0x37, 0x37, 0x37 }, 170459cc2c6SThierry Reding .preemphasis = { 0x01, 0x02, 0x02, 0x02 }, 171459cc2c6SThierry Reding }, { 172459cc2c6SThierry Reding .frequency = 300000000, 173459cc2c6SThierry Reding .vcocap = 0x3, 174*c57997bcSThierry Reding .filter = 0x0, 175459cc2c6SThierry Reding .ichpmp = 0x6, 176459cc2c6SThierry Reding .loadadj = 0x3, 177*c57997bcSThierry Reding .tmds_termadj = 0x9, 178*c57997bcSThierry Reding .tx_pu_value = 0x66, 179*c57997bcSThierry Reding .bg_temp_coef = 0x3, 180*c57997bcSThierry Reding .bg_vref_level = 0xf, 181*c57997bcSThierry Reding .avdd10_level = 0x4, 182*c57997bcSThierry Reding .avdd14_level = 0x4, 183*c57997bcSThierry Reding .sparepll = 0x0, 184459cc2c6SThierry Reding .drive_current = { 0x30, 0x37, 0x37, 0x37 }, 185459cc2c6SThierry Reding .preemphasis = { 0x10, 0x3e, 0x3e, 0x3e }, 186459cc2c6SThierry Reding }, { 187459cc2c6SThierry Reding .frequency = 600000000, 188459cc2c6SThierry Reding .vcocap = 0x3, 189*c57997bcSThierry Reding .filter = 0x0, 190459cc2c6SThierry Reding .ichpmp = 0xa, 191459cc2c6SThierry Reding .loadadj = 0x3, 192*c57997bcSThierry Reding .tmds_termadj = 0xb, 193*c57997bcSThierry Reding .tx_pu_value = 0x66, 194*c57997bcSThierry Reding .bg_temp_coef = 0x3, 195*c57997bcSThierry Reding .bg_vref_level = 0xe, 196*c57997bcSThierry Reding .avdd10_level = 0x4, 197*c57997bcSThierry Reding .avdd14_level = 0x4, 198*c57997bcSThierry Reding .sparepll = 0x0, 199459cc2c6SThierry Reding .drive_current = { 0x35, 0x3e, 0x3e, 0x3e }, 200459cc2c6SThierry Reding .preemphasis = { 0x02, 0x3f, 0x3f, 0x3f }, 201459cc2c6SThierry Reding }, 202459cc2c6SThierry Reding }; 203459cc2c6SThierry Reding #endif 204459cc2c6SThierry Reding 205*c57997bcSThierry Reding static const struct tegra_sor_hdmi_settings tegra186_sor_hdmi_defaults[] = { 206*c57997bcSThierry Reding { 207*c57997bcSThierry Reding .frequency = 54000000, 208*c57997bcSThierry Reding .vcocap = 0, 209*c57997bcSThierry Reding .filter = 5, 210*c57997bcSThierry Reding .ichpmp = 5, 211*c57997bcSThierry Reding .loadadj = 3, 212*c57997bcSThierry Reding .tmds_termadj = 0xf, 213*c57997bcSThierry Reding .tx_pu_value = 0, 214*c57997bcSThierry Reding .bg_temp_coef = 3, 215*c57997bcSThierry Reding .bg_vref_level = 8, 216*c57997bcSThierry Reding .avdd10_level = 4, 217*c57997bcSThierry Reding .avdd14_level = 4, 218*c57997bcSThierry Reding .sparepll = 0x54, 219*c57997bcSThierry Reding .drive_current = { 0x3a, 0x3a, 0x3a, 0x33 }, 220*c57997bcSThierry Reding .preemphasis = { 0x00, 0x00, 0x00, 0x00 }, 221*c57997bcSThierry Reding }, { 222*c57997bcSThierry Reding .frequency = 75000000, 223*c57997bcSThierry Reding .vcocap = 1, 224*c57997bcSThierry Reding .filter = 5, 225*c57997bcSThierry Reding .ichpmp = 5, 226*c57997bcSThierry Reding .loadadj = 3, 227*c57997bcSThierry Reding .tmds_termadj = 0xf, 228*c57997bcSThierry Reding .tx_pu_value = 0, 229*c57997bcSThierry Reding .bg_temp_coef = 3, 230*c57997bcSThierry Reding .bg_vref_level = 8, 231*c57997bcSThierry Reding .avdd10_level = 4, 232*c57997bcSThierry Reding .avdd14_level = 4, 233*c57997bcSThierry Reding .sparepll = 0x44, 234*c57997bcSThierry Reding .drive_current = { 0x3a, 0x3a, 0x3a, 0x33 }, 235*c57997bcSThierry Reding .preemphasis = { 0x00, 0x00, 0x00, 0x00 }, 236*c57997bcSThierry Reding }, { 237*c57997bcSThierry Reding .frequency = 150000000, 238*c57997bcSThierry Reding .vcocap = 3, 239*c57997bcSThierry Reding .filter = 5, 240*c57997bcSThierry Reding .ichpmp = 5, 241*c57997bcSThierry Reding .loadadj = 3, 242*c57997bcSThierry Reding .tmds_termadj = 15, 243*c57997bcSThierry Reding .tx_pu_value = 0x66 /* 0 */, 244*c57997bcSThierry Reding .bg_temp_coef = 3, 245*c57997bcSThierry Reding .bg_vref_level = 8, 246*c57997bcSThierry Reding .avdd10_level = 4, 247*c57997bcSThierry Reding .avdd14_level = 4, 248*c57997bcSThierry Reding .sparepll = 0x00, /* 0x34 */ 249*c57997bcSThierry Reding .drive_current = { 0x3a, 0x3a, 0x3a, 0x37 }, 250*c57997bcSThierry Reding .preemphasis = { 0x00, 0x00, 0x00, 0x00 }, 251*c57997bcSThierry Reding }, { 252*c57997bcSThierry Reding .frequency = 300000000, 253*c57997bcSThierry Reding .vcocap = 3, 254*c57997bcSThierry Reding .filter = 5, 255*c57997bcSThierry Reding .ichpmp = 5, 256*c57997bcSThierry Reding .loadadj = 3, 257*c57997bcSThierry Reding .tmds_termadj = 15, 258*c57997bcSThierry Reding .tx_pu_value = 64, 259*c57997bcSThierry Reding .bg_temp_coef = 3, 260*c57997bcSThierry Reding .bg_vref_level = 8, 261*c57997bcSThierry Reding .avdd10_level = 4, 262*c57997bcSThierry Reding .avdd14_level = 4, 263*c57997bcSThierry Reding .sparepll = 0x34, 264*c57997bcSThierry Reding .drive_current = { 0x3d, 0x3d, 0x3d, 0x33 }, 265*c57997bcSThierry Reding .preemphasis = { 0x00, 0x00, 0x00, 0x00 }, 266*c57997bcSThierry Reding }, { 267*c57997bcSThierry Reding .frequency = 600000000, 268*c57997bcSThierry Reding .vcocap = 3, 269*c57997bcSThierry Reding .filter = 5, 270*c57997bcSThierry Reding .ichpmp = 5, 271*c57997bcSThierry Reding .loadadj = 3, 272*c57997bcSThierry Reding .tmds_termadj = 12, 273*c57997bcSThierry Reding .tx_pu_value = 96, 274*c57997bcSThierry Reding .bg_temp_coef = 3, 275*c57997bcSThierry Reding .bg_vref_level = 8, 276*c57997bcSThierry Reding .avdd10_level = 4, 277*c57997bcSThierry Reding .avdd14_level = 4, 278*c57997bcSThierry Reding .sparepll = 0x34, 279*c57997bcSThierry Reding .drive_current = { 0x3d, 0x3d, 0x3d, 0x33 }, 280*c57997bcSThierry Reding .preemphasis = { 0x00, 0x00, 0x00, 0x00 }, 281*c57997bcSThierry Reding } 282*c57997bcSThierry Reding }; 283*c57997bcSThierry Reding 284880cee0bSThierry Reding struct tegra_sor_regs { 285880cee0bSThierry Reding unsigned int head_state0; 286880cee0bSThierry Reding unsigned int head_state1; 287880cee0bSThierry Reding unsigned int head_state2; 288880cee0bSThierry Reding unsigned int head_state3; 289880cee0bSThierry Reding unsigned int head_state4; 290880cee0bSThierry Reding unsigned int head_state5; 291880cee0bSThierry Reding unsigned int pll0; 292880cee0bSThierry Reding unsigned int pll1; 293880cee0bSThierry Reding unsigned int pll2; 294880cee0bSThierry Reding unsigned int pll3; 295880cee0bSThierry Reding unsigned int dp_padctl0; 296880cee0bSThierry Reding unsigned int dp_padctl2; 297880cee0bSThierry Reding }; 298880cee0bSThierry Reding 299459cc2c6SThierry Reding struct tegra_sor_soc { 300459cc2c6SThierry Reding bool supports_edp; 301459cc2c6SThierry Reding bool supports_lvds; 302459cc2c6SThierry Reding bool supports_hdmi; 303459cc2c6SThierry Reding bool supports_dp; 304459cc2c6SThierry Reding 305880cee0bSThierry Reding const struct tegra_sor_regs *regs; 306*c57997bcSThierry Reding bool has_nvdisplay; 307880cee0bSThierry Reding 308459cc2c6SThierry Reding const struct tegra_sor_hdmi_settings *settings; 309459cc2c6SThierry Reding unsigned int num_settings; 31030b49435SThierry Reding 31130b49435SThierry Reding const u8 *xbar_cfg; 312459cc2c6SThierry Reding }; 313459cc2c6SThierry Reding 314459cc2c6SThierry Reding struct tegra_sor; 315459cc2c6SThierry Reding 316459cc2c6SThierry Reding struct tegra_sor_ops { 317459cc2c6SThierry Reding const char *name; 318459cc2c6SThierry Reding int (*probe)(struct tegra_sor *sor); 319459cc2c6SThierry Reding int (*remove)(struct tegra_sor *sor); 320459cc2c6SThierry Reding }; 321459cc2c6SThierry Reding 3226b6b6042SThierry Reding struct tegra_sor { 3236b6b6042SThierry Reding struct host1x_client client; 3246b6b6042SThierry Reding struct tegra_output output; 3256b6b6042SThierry Reding struct device *dev; 3266b6b6042SThierry Reding 327459cc2c6SThierry Reding const struct tegra_sor_soc *soc; 3286b6b6042SThierry Reding void __iomem *regs; 329*c57997bcSThierry Reding unsigned int index; 3306b6b6042SThierry Reding 3316b6b6042SThierry Reding struct reset_control *rst; 3326b6b6042SThierry Reding struct clk *clk_parent; 3336b6b6042SThierry Reding struct clk *clk_safe; 334e1335e2fSThierry Reding struct clk *clk_out; 335e1335e2fSThierry Reding struct clk *clk_pad; 3366b6b6042SThierry Reding struct clk *clk_dp; 3376b6b6042SThierry Reding struct clk *clk; 3386b6b6042SThierry Reding 3399542c237SThierry Reding struct drm_dp_aux *aux; 3406b6b6042SThierry Reding 341dab16336SThierry Reding struct drm_info_list *debugfs_files; 342459cc2c6SThierry Reding 343459cc2c6SThierry Reding const struct tegra_sor_ops *ops; 344*c57997bcSThierry Reding enum tegra_io_pad pad; 345459cc2c6SThierry Reding 346459cc2c6SThierry Reding /* for HDMI 2.0 */ 347459cc2c6SThierry Reding struct tegra_sor_hdmi_settings *settings; 348459cc2c6SThierry Reding unsigned int num_settings; 349459cc2c6SThierry Reding 350459cc2c6SThierry Reding struct regulator *avdd_io_supply; 351459cc2c6SThierry Reding struct regulator *vdd_pll_supply; 352459cc2c6SThierry Reding struct regulator *hdmi_supply; 3536b6b6042SThierry Reding }; 3546b6b6042SThierry Reding 355c31efa7aSThierry Reding struct tegra_sor_state { 356c31efa7aSThierry Reding struct drm_connector_state base; 357c31efa7aSThierry Reding 358c31efa7aSThierry Reding unsigned int bpc; 359c31efa7aSThierry Reding }; 360c31efa7aSThierry Reding 361c31efa7aSThierry Reding static inline struct tegra_sor_state * 362c31efa7aSThierry Reding to_sor_state(struct drm_connector_state *state) 363c31efa7aSThierry Reding { 364c31efa7aSThierry Reding return container_of(state, struct tegra_sor_state, base); 365c31efa7aSThierry Reding } 366c31efa7aSThierry Reding 36734fa183bSThierry Reding struct tegra_sor_config { 36834fa183bSThierry Reding u32 bits_per_pixel; 36934fa183bSThierry Reding 37034fa183bSThierry Reding u32 active_polarity; 37134fa183bSThierry Reding u32 active_count; 37234fa183bSThierry Reding u32 tu_size; 37334fa183bSThierry Reding u32 active_frac; 37434fa183bSThierry Reding u32 watermark; 3757890b576SThierry Reding 3767890b576SThierry Reding u32 hblank_symbols; 3777890b576SThierry Reding u32 vblank_symbols; 37834fa183bSThierry Reding }; 37934fa183bSThierry Reding 3806b6b6042SThierry Reding static inline struct tegra_sor * 3816b6b6042SThierry Reding host1x_client_to_sor(struct host1x_client *client) 3826b6b6042SThierry Reding { 3836b6b6042SThierry Reding return container_of(client, struct tegra_sor, client); 3846b6b6042SThierry Reding } 3856b6b6042SThierry Reding 3866b6b6042SThierry Reding static inline struct tegra_sor *to_sor(struct tegra_output *output) 3876b6b6042SThierry Reding { 3886b6b6042SThierry Reding return container_of(output, struct tegra_sor, output); 3896b6b6042SThierry Reding } 3906b6b6042SThierry Reding 3915c5f1301SThierry Reding static inline u32 tegra_sor_readl(struct tegra_sor *sor, unsigned int offset) 3926b6b6042SThierry Reding { 393932f6529SThierry Reding u32 value = readl(sor->regs + (offset << 2)); 394932f6529SThierry Reding 395932f6529SThierry Reding trace_sor_readl(sor->dev, offset, value); 396932f6529SThierry Reding 397932f6529SThierry Reding return value; 3986b6b6042SThierry Reding } 3996b6b6042SThierry Reding 40028fe2076SThierry Reding static inline void tegra_sor_writel(struct tegra_sor *sor, u32 value, 4015c5f1301SThierry Reding unsigned int offset) 4026b6b6042SThierry Reding { 403932f6529SThierry Reding trace_sor_writel(sor->dev, offset, value); 4046b6b6042SThierry Reding writel(value, sor->regs + (offset << 2)); 4056b6b6042SThierry Reding } 4066b6b6042SThierry Reding 40725bb2cecSThierry Reding static int tegra_sor_set_parent_clock(struct tegra_sor *sor, struct clk *parent) 40825bb2cecSThierry Reding { 40925bb2cecSThierry Reding int err; 41025bb2cecSThierry Reding 41125bb2cecSThierry Reding clk_disable_unprepare(sor->clk); 41225bb2cecSThierry Reding 413e1335e2fSThierry Reding err = clk_set_parent(sor->clk_out, parent); 41425bb2cecSThierry Reding if (err < 0) 41525bb2cecSThierry Reding return err; 41625bb2cecSThierry Reding 41725bb2cecSThierry Reding err = clk_prepare_enable(sor->clk); 41825bb2cecSThierry Reding if (err < 0) 41925bb2cecSThierry Reding return err; 42025bb2cecSThierry Reding 42125bb2cecSThierry Reding return 0; 42225bb2cecSThierry Reding } 42325bb2cecSThierry Reding 424e1335e2fSThierry Reding struct tegra_clk_sor_pad { 425b299221cSThierry Reding struct clk_hw hw; 426b299221cSThierry Reding struct tegra_sor *sor; 427b299221cSThierry Reding }; 428b299221cSThierry Reding 429e1335e2fSThierry Reding static inline struct tegra_clk_sor_pad *to_pad(struct clk_hw *hw) 430b299221cSThierry Reding { 431e1335e2fSThierry Reding return container_of(hw, struct tegra_clk_sor_pad, hw); 432b299221cSThierry Reding } 433b299221cSThierry Reding 434e1335e2fSThierry Reding static const char * const tegra_clk_sor_pad_parents[] = { 435b299221cSThierry Reding "pll_d2_out0", "pll_dp" 436b299221cSThierry Reding }; 437b299221cSThierry Reding 438e1335e2fSThierry Reding static int tegra_clk_sor_pad_set_parent(struct clk_hw *hw, u8 index) 439b299221cSThierry Reding { 440e1335e2fSThierry Reding struct tegra_clk_sor_pad *pad = to_pad(hw); 441e1335e2fSThierry Reding struct tegra_sor *sor = pad->sor; 442b299221cSThierry Reding u32 value; 443b299221cSThierry Reding 444b299221cSThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 445b299221cSThierry Reding value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; 446b299221cSThierry Reding 447b299221cSThierry Reding switch (index) { 448b299221cSThierry Reding case 0: 449b299221cSThierry Reding value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK; 450b299221cSThierry Reding break; 451b299221cSThierry Reding 452b299221cSThierry Reding case 1: 453b299221cSThierry Reding value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK; 454b299221cSThierry Reding break; 455b299221cSThierry Reding } 456b299221cSThierry Reding 457b299221cSThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 458b299221cSThierry Reding 459b299221cSThierry Reding return 0; 460b299221cSThierry Reding } 461b299221cSThierry Reding 462e1335e2fSThierry Reding static u8 tegra_clk_sor_pad_get_parent(struct clk_hw *hw) 463b299221cSThierry Reding { 464e1335e2fSThierry Reding struct tegra_clk_sor_pad *pad = to_pad(hw); 465e1335e2fSThierry Reding struct tegra_sor *sor = pad->sor; 466b299221cSThierry Reding u8 parent = U8_MAX; 467b299221cSThierry Reding u32 value; 468b299221cSThierry Reding 469b299221cSThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 470b299221cSThierry Reding 471b299221cSThierry Reding switch (value & SOR_CLK_CNTRL_DP_CLK_SEL_MASK) { 472b299221cSThierry Reding case SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK: 473b299221cSThierry Reding case SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_PCLK: 474b299221cSThierry Reding parent = 0; 475b299221cSThierry Reding break; 476b299221cSThierry Reding 477b299221cSThierry Reding case SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK: 478b299221cSThierry Reding case SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_DPCLK: 479b299221cSThierry Reding parent = 1; 480b299221cSThierry Reding break; 481b299221cSThierry Reding } 482b299221cSThierry Reding 483b299221cSThierry Reding return parent; 484b299221cSThierry Reding } 485b299221cSThierry Reding 486e1335e2fSThierry Reding static const struct clk_ops tegra_clk_sor_pad_ops = { 487e1335e2fSThierry Reding .set_parent = tegra_clk_sor_pad_set_parent, 488e1335e2fSThierry Reding .get_parent = tegra_clk_sor_pad_get_parent, 489b299221cSThierry Reding }; 490b299221cSThierry Reding 491e1335e2fSThierry Reding static struct clk *tegra_clk_sor_pad_register(struct tegra_sor *sor, 492b299221cSThierry Reding const char *name) 493b299221cSThierry Reding { 494e1335e2fSThierry Reding struct tegra_clk_sor_pad *pad; 495b299221cSThierry Reding struct clk_init_data init; 496b299221cSThierry Reding struct clk *clk; 497b299221cSThierry Reding 498e1335e2fSThierry Reding pad = devm_kzalloc(sor->dev, sizeof(*pad), GFP_KERNEL); 499e1335e2fSThierry Reding if (!pad) 500b299221cSThierry Reding return ERR_PTR(-ENOMEM); 501b299221cSThierry Reding 502e1335e2fSThierry Reding pad->sor = sor; 503b299221cSThierry Reding 504b299221cSThierry Reding init.name = name; 505b299221cSThierry Reding init.flags = 0; 506e1335e2fSThierry Reding init.parent_names = tegra_clk_sor_pad_parents; 507e1335e2fSThierry Reding init.num_parents = ARRAY_SIZE(tegra_clk_sor_pad_parents); 508e1335e2fSThierry Reding init.ops = &tegra_clk_sor_pad_ops; 509b299221cSThierry Reding 510e1335e2fSThierry Reding pad->hw.init = &init; 511b299221cSThierry Reding 512e1335e2fSThierry Reding clk = devm_clk_register(sor->dev, &pad->hw); 513b299221cSThierry Reding 514b299221cSThierry Reding return clk; 515b299221cSThierry Reding } 516b299221cSThierry Reding 5176b6b6042SThierry Reding static int tegra_sor_dp_train_fast(struct tegra_sor *sor, 5186b6b6042SThierry Reding struct drm_dp_link *link) 5196b6b6042SThierry Reding { 5206b6b6042SThierry Reding unsigned int i; 5216b6b6042SThierry Reding u8 pattern; 52228fe2076SThierry Reding u32 value; 5236b6b6042SThierry Reding int err; 5246b6b6042SThierry Reding 5256b6b6042SThierry Reding /* setup lane parameters */ 5266b6b6042SThierry Reding value = SOR_LANE_DRIVE_CURRENT_LANE3(0x40) | 5276b6b6042SThierry Reding SOR_LANE_DRIVE_CURRENT_LANE2(0x40) | 5286b6b6042SThierry Reding SOR_LANE_DRIVE_CURRENT_LANE1(0x40) | 5296b6b6042SThierry Reding SOR_LANE_DRIVE_CURRENT_LANE0(0x40); 530a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_LANE_DRIVE_CURRENT0); 5316b6b6042SThierry Reding 5326b6b6042SThierry Reding value = SOR_LANE_PREEMPHASIS_LANE3(0x0f) | 5336b6b6042SThierry Reding SOR_LANE_PREEMPHASIS_LANE2(0x0f) | 5346b6b6042SThierry Reding SOR_LANE_PREEMPHASIS_LANE1(0x0f) | 5356b6b6042SThierry Reding SOR_LANE_PREEMPHASIS_LANE0(0x0f); 536a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_LANE_PREEMPHASIS0); 5376b6b6042SThierry Reding 538a9a9e4fdSThierry Reding value = SOR_LANE_POSTCURSOR_LANE3(0x00) | 539a9a9e4fdSThierry Reding SOR_LANE_POSTCURSOR_LANE2(0x00) | 540a9a9e4fdSThierry Reding SOR_LANE_POSTCURSOR_LANE1(0x00) | 541a9a9e4fdSThierry Reding SOR_LANE_POSTCURSOR_LANE0(0x00); 542a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_LANE_POSTCURSOR0); 5436b6b6042SThierry Reding 5446b6b6042SThierry Reding /* disable LVDS mode */ 5456b6b6042SThierry Reding tegra_sor_writel(sor, 0, SOR_LVDS); 5466b6b6042SThierry Reding 547880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->dp_padctl0); 5486b6b6042SThierry Reding value |= SOR_DP_PADCTL_TX_PU_ENABLE; 5496b6b6042SThierry Reding value &= ~SOR_DP_PADCTL_TX_PU_MASK; 5506b6b6042SThierry Reding value |= SOR_DP_PADCTL_TX_PU(2); /* XXX: don't hardcode? */ 551880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->dp_padctl0); 5526b6b6042SThierry Reding 553880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->dp_padctl0); 5546b6b6042SThierry Reding value |= SOR_DP_PADCTL_CM_TXD_3 | SOR_DP_PADCTL_CM_TXD_2 | 5556b6b6042SThierry Reding SOR_DP_PADCTL_CM_TXD_1 | SOR_DP_PADCTL_CM_TXD_0; 556880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->dp_padctl0); 5576b6b6042SThierry Reding 5586b6b6042SThierry Reding usleep_range(10, 100); 5596b6b6042SThierry Reding 560880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->dp_padctl0); 5616b6b6042SThierry Reding value &= ~(SOR_DP_PADCTL_CM_TXD_3 | SOR_DP_PADCTL_CM_TXD_2 | 5626b6b6042SThierry Reding SOR_DP_PADCTL_CM_TXD_1 | SOR_DP_PADCTL_CM_TXD_0); 563880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->dp_padctl0); 5646b6b6042SThierry Reding 5659542c237SThierry Reding err = drm_dp_aux_prepare(sor->aux, DP_SET_ANSI_8B10B); 5666b6b6042SThierry Reding if (err < 0) 5676b6b6042SThierry Reding return err; 5686b6b6042SThierry Reding 5696b6b6042SThierry Reding for (i = 0, value = 0; i < link->num_lanes; i++) { 5706b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 5716b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_NONE | 5726b6b6042SThierry Reding SOR_DP_TPG_PATTERN_TRAIN1; 5736b6b6042SThierry Reding value = (value << 8) | lane; 5746b6b6042SThierry Reding } 5756b6b6042SThierry Reding 5766b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 5776b6b6042SThierry Reding 5786b6b6042SThierry Reding pattern = DP_TRAINING_PATTERN_1; 5796b6b6042SThierry Reding 5809542c237SThierry Reding err = drm_dp_aux_train(sor->aux, link, pattern); 5816b6b6042SThierry Reding if (err < 0) 5826b6b6042SThierry Reding return err; 5836b6b6042SThierry Reding 584a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_SPARE0); 5856b6b6042SThierry Reding value |= SOR_DP_SPARE_SEQ_ENABLE; 5866b6b6042SThierry Reding value &= ~SOR_DP_SPARE_PANEL_INTERNAL; 5876b6b6042SThierry Reding value |= SOR_DP_SPARE_MACRO_SOR_CLK; 588a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_SPARE0); 5896b6b6042SThierry Reding 5906b6b6042SThierry Reding for (i = 0, value = 0; i < link->num_lanes; i++) { 5916b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 5926b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_NONE | 5936b6b6042SThierry Reding SOR_DP_TPG_PATTERN_TRAIN2; 5946b6b6042SThierry Reding value = (value << 8) | lane; 5956b6b6042SThierry Reding } 5966b6b6042SThierry Reding 5976b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 5986b6b6042SThierry Reding 5996b6b6042SThierry Reding pattern = DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_2; 6006b6b6042SThierry Reding 6019542c237SThierry Reding err = drm_dp_aux_train(sor->aux, link, pattern); 6026b6b6042SThierry Reding if (err < 0) 6036b6b6042SThierry Reding return err; 6046b6b6042SThierry Reding 6056b6b6042SThierry Reding for (i = 0, value = 0; i < link->num_lanes; i++) { 6066b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 6076b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_GALIOS | 6086b6b6042SThierry Reding SOR_DP_TPG_PATTERN_NONE; 6096b6b6042SThierry Reding value = (value << 8) | lane; 6106b6b6042SThierry Reding } 6116b6b6042SThierry Reding 6126b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 6136b6b6042SThierry Reding 6146b6b6042SThierry Reding pattern = DP_TRAINING_PATTERN_DISABLE; 6156b6b6042SThierry Reding 6169542c237SThierry Reding err = drm_dp_aux_train(sor->aux, link, pattern); 6176b6b6042SThierry Reding if (err < 0) 6186b6b6042SThierry Reding return err; 6196b6b6042SThierry Reding 6206b6b6042SThierry Reding return 0; 6216b6b6042SThierry Reding } 6226b6b6042SThierry Reding 6236b6b6042SThierry Reding static void tegra_sor_super_update(struct tegra_sor *sor) 6246b6b6042SThierry Reding { 625a9a9e4fdSThierry Reding tegra_sor_writel(sor, 0, SOR_SUPER_STATE0); 626a9a9e4fdSThierry Reding tegra_sor_writel(sor, 1, SOR_SUPER_STATE0); 627a9a9e4fdSThierry Reding tegra_sor_writel(sor, 0, SOR_SUPER_STATE0); 6286b6b6042SThierry Reding } 6296b6b6042SThierry Reding 6306b6b6042SThierry Reding static void tegra_sor_update(struct tegra_sor *sor) 6316b6b6042SThierry Reding { 632a9a9e4fdSThierry Reding tegra_sor_writel(sor, 0, SOR_STATE0); 633a9a9e4fdSThierry Reding tegra_sor_writel(sor, 1, SOR_STATE0); 634a9a9e4fdSThierry Reding tegra_sor_writel(sor, 0, SOR_STATE0); 6356b6b6042SThierry Reding } 6366b6b6042SThierry Reding 6376b6b6042SThierry Reding static int tegra_sor_setup_pwm(struct tegra_sor *sor, unsigned long timeout) 6386b6b6042SThierry Reding { 63928fe2076SThierry Reding u32 value; 6406b6b6042SThierry Reding 6416b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWM_DIV); 6426b6b6042SThierry Reding value &= ~SOR_PWM_DIV_MASK; 6436b6b6042SThierry Reding value |= 0x400; /* period */ 6446b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PWM_DIV); 6456b6b6042SThierry Reding 6466b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWM_CTL); 6476b6b6042SThierry Reding value &= ~SOR_PWM_CTL_DUTY_CYCLE_MASK; 6486b6b6042SThierry Reding value |= 0x400; /* duty cycle */ 6496b6b6042SThierry Reding value &= ~SOR_PWM_CTL_CLK_SEL; /* clock source: PCLK */ 6506b6b6042SThierry Reding value |= SOR_PWM_CTL_TRIGGER; 6516b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PWM_CTL); 6526b6b6042SThierry Reding 6536b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(timeout); 6546b6b6042SThierry Reding 6556b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 6566b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWM_CTL); 6576b6b6042SThierry Reding if ((value & SOR_PWM_CTL_TRIGGER) == 0) 6586b6b6042SThierry Reding return 0; 6596b6b6042SThierry Reding 6606b6b6042SThierry Reding usleep_range(25, 100); 6616b6b6042SThierry Reding } 6626b6b6042SThierry Reding 6636b6b6042SThierry Reding return -ETIMEDOUT; 6646b6b6042SThierry Reding } 6656b6b6042SThierry Reding 6666b6b6042SThierry Reding static int tegra_sor_attach(struct tegra_sor *sor) 6676b6b6042SThierry Reding { 6686b6b6042SThierry Reding unsigned long value, timeout; 6696b6b6042SThierry Reding 6706b6b6042SThierry Reding /* wake up in normal mode */ 671a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE1); 6726b6b6042SThierry Reding value |= SOR_SUPER_STATE_HEAD_MODE_AWAKE; 6736b6b6042SThierry Reding value |= SOR_SUPER_STATE_MODE_NORMAL; 674a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE1); 6756b6b6042SThierry Reding tegra_sor_super_update(sor); 6766b6b6042SThierry Reding 6776b6b6042SThierry Reding /* attach */ 678a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE1); 6796b6b6042SThierry Reding value |= SOR_SUPER_STATE_ATTACHED; 680a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE1); 6816b6b6042SThierry Reding tegra_sor_super_update(sor); 6826b6b6042SThierry Reding 6836b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 6846b6b6042SThierry Reding 6856b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 6866b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_TEST); 6876b6b6042SThierry Reding if ((value & SOR_TEST_ATTACHED) != 0) 6886b6b6042SThierry Reding return 0; 6896b6b6042SThierry Reding 6906b6b6042SThierry Reding usleep_range(25, 100); 6916b6b6042SThierry Reding } 6926b6b6042SThierry Reding 6936b6b6042SThierry Reding return -ETIMEDOUT; 6946b6b6042SThierry Reding } 6956b6b6042SThierry Reding 6966b6b6042SThierry Reding static int tegra_sor_wakeup(struct tegra_sor *sor) 6976b6b6042SThierry Reding { 6986b6b6042SThierry Reding unsigned long value, timeout; 6996b6b6042SThierry Reding 7006b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 7016b6b6042SThierry Reding 7026b6b6042SThierry Reding /* wait for head to wake up */ 7036b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 7046b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_TEST); 7056b6b6042SThierry Reding value &= SOR_TEST_HEAD_MODE_MASK; 7066b6b6042SThierry Reding 7076b6b6042SThierry Reding if (value == SOR_TEST_HEAD_MODE_AWAKE) 7086b6b6042SThierry Reding return 0; 7096b6b6042SThierry Reding 7106b6b6042SThierry Reding usleep_range(25, 100); 7116b6b6042SThierry Reding } 7126b6b6042SThierry Reding 7136b6b6042SThierry Reding return -ETIMEDOUT; 7146b6b6042SThierry Reding } 7156b6b6042SThierry Reding 7166b6b6042SThierry Reding static int tegra_sor_power_up(struct tegra_sor *sor, unsigned long timeout) 7176b6b6042SThierry Reding { 71828fe2076SThierry Reding u32 value; 7196b6b6042SThierry Reding 7206b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 7216b6b6042SThierry Reding value |= SOR_PWR_TRIGGER | SOR_PWR_NORMAL_STATE_PU; 7226b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PWR); 7236b6b6042SThierry Reding 7246b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(timeout); 7256b6b6042SThierry Reding 7266b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 7276b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 7286b6b6042SThierry Reding if ((value & SOR_PWR_TRIGGER) == 0) 7296b6b6042SThierry Reding return 0; 7306b6b6042SThierry Reding 7316b6b6042SThierry Reding usleep_range(25, 100); 7326b6b6042SThierry Reding } 7336b6b6042SThierry Reding 7346b6b6042SThierry Reding return -ETIMEDOUT; 7356b6b6042SThierry Reding } 7366b6b6042SThierry Reding 73734fa183bSThierry Reding struct tegra_sor_params { 73834fa183bSThierry Reding /* number of link clocks per line */ 73934fa183bSThierry Reding unsigned int num_clocks; 74034fa183bSThierry Reding /* ratio between input and output */ 74134fa183bSThierry Reding u64 ratio; 74234fa183bSThierry Reding /* precision factor */ 74334fa183bSThierry Reding u64 precision; 74434fa183bSThierry Reding 74534fa183bSThierry Reding unsigned int active_polarity; 74634fa183bSThierry Reding unsigned int active_count; 74734fa183bSThierry Reding unsigned int active_frac; 74834fa183bSThierry Reding unsigned int tu_size; 74934fa183bSThierry Reding unsigned int error; 75034fa183bSThierry Reding }; 75134fa183bSThierry Reding 75234fa183bSThierry Reding static int tegra_sor_compute_params(struct tegra_sor *sor, 75334fa183bSThierry Reding struct tegra_sor_params *params, 75434fa183bSThierry Reding unsigned int tu_size) 75534fa183bSThierry Reding { 75634fa183bSThierry Reding u64 active_sym, active_count, frac, approx; 75734fa183bSThierry Reding u32 active_polarity, active_frac = 0; 75834fa183bSThierry Reding const u64 f = params->precision; 75934fa183bSThierry Reding s64 error; 76034fa183bSThierry Reding 76134fa183bSThierry Reding active_sym = params->ratio * tu_size; 76234fa183bSThierry Reding active_count = div_u64(active_sym, f) * f; 76334fa183bSThierry Reding frac = active_sym - active_count; 76434fa183bSThierry Reding 76534fa183bSThierry Reding /* fraction < 0.5 */ 76634fa183bSThierry Reding if (frac >= (f / 2)) { 76734fa183bSThierry Reding active_polarity = 1; 76834fa183bSThierry Reding frac = f - frac; 76934fa183bSThierry Reding } else { 77034fa183bSThierry Reding active_polarity = 0; 77134fa183bSThierry Reding } 77234fa183bSThierry Reding 77334fa183bSThierry Reding if (frac != 0) { 77434fa183bSThierry Reding frac = div_u64(f * f, frac); /* 1/fraction */ 77534fa183bSThierry Reding if (frac <= (15 * f)) { 77634fa183bSThierry Reding active_frac = div_u64(frac, f); 77734fa183bSThierry Reding 77834fa183bSThierry Reding /* round up */ 77934fa183bSThierry Reding if (active_polarity) 78034fa183bSThierry Reding active_frac++; 78134fa183bSThierry Reding } else { 78234fa183bSThierry Reding active_frac = active_polarity ? 1 : 15; 78334fa183bSThierry Reding } 78434fa183bSThierry Reding } 78534fa183bSThierry Reding 78634fa183bSThierry Reding if (active_frac == 1) 78734fa183bSThierry Reding active_polarity = 0; 78834fa183bSThierry Reding 78934fa183bSThierry Reding if (active_polarity == 1) { 79034fa183bSThierry Reding if (active_frac) { 79134fa183bSThierry Reding approx = active_count + (active_frac * (f - 1)) * f; 79234fa183bSThierry Reding approx = div_u64(approx, active_frac * f); 79334fa183bSThierry Reding } else { 79434fa183bSThierry Reding approx = active_count + f; 79534fa183bSThierry Reding } 79634fa183bSThierry Reding } else { 79734fa183bSThierry Reding if (active_frac) 79834fa183bSThierry Reding approx = active_count + div_u64(f, active_frac); 79934fa183bSThierry Reding else 80034fa183bSThierry Reding approx = active_count; 80134fa183bSThierry Reding } 80234fa183bSThierry Reding 80334fa183bSThierry Reding error = div_s64(active_sym - approx, tu_size); 80434fa183bSThierry Reding error *= params->num_clocks; 80534fa183bSThierry Reding 80679211c8eSAndrew Morton if (error <= 0 && abs(error) < params->error) { 80734fa183bSThierry Reding params->active_count = div_u64(active_count, f); 80834fa183bSThierry Reding params->active_polarity = active_polarity; 80934fa183bSThierry Reding params->active_frac = active_frac; 81079211c8eSAndrew Morton params->error = abs(error); 81134fa183bSThierry Reding params->tu_size = tu_size; 81234fa183bSThierry Reding 81334fa183bSThierry Reding if (error == 0) 81434fa183bSThierry Reding return true; 81534fa183bSThierry Reding } 81634fa183bSThierry Reding 81734fa183bSThierry Reding return false; 81834fa183bSThierry Reding } 81934fa183bSThierry Reding 820a198359eSThierry Reding static int tegra_sor_compute_config(struct tegra_sor *sor, 82180444495SThierry Reding const struct drm_display_mode *mode, 82234fa183bSThierry Reding struct tegra_sor_config *config, 82334fa183bSThierry Reding struct drm_dp_link *link) 82434fa183bSThierry Reding { 82534fa183bSThierry Reding const u64 f = 100000, link_rate = link->rate * 1000; 82634fa183bSThierry Reding const u64 pclk = mode->clock * 1000; 8277890b576SThierry Reding u64 input, output, watermark, num; 82834fa183bSThierry Reding struct tegra_sor_params params; 82934fa183bSThierry Reding u32 num_syms_per_line; 83034fa183bSThierry Reding unsigned int i; 83134fa183bSThierry Reding 83234fa183bSThierry Reding if (!link_rate || !link->num_lanes || !pclk || !config->bits_per_pixel) 83334fa183bSThierry Reding return -EINVAL; 83434fa183bSThierry Reding 83534fa183bSThierry Reding output = link_rate * 8 * link->num_lanes; 83634fa183bSThierry Reding input = pclk * config->bits_per_pixel; 83734fa183bSThierry Reding 83834fa183bSThierry Reding if (input >= output) 83934fa183bSThierry Reding return -ERANGE; 84034fa183bSThierry Reding 84134fa183bSThierry Reding memset(¶ms, 0, sizeof(params)); 84234fa183bSThierry Reding params.ratio = div64_u64(input * f, output); 84334fa183bSThierry Reding params.num_clocks = div_u64(link_rate * mode->hdisplay, pclk); 84434fa183bSThierry Reding params.precision = f; 84534fa183bSThierry Reding params.error = 64 * f; 84634fa183bSThierry Reding params.tu_size = 64; 84734fa183bSThierry Reding 84834fa183bSThierry Reding for (i = params.tu_size; i >= 32; i--) 84934fa183bSThierry Reding if (tegra_sor_compute_params(sor, ¶ms, i)) 85034fa183bSThierry Reding break; 85134fa183bSThierry Reding 85234fa183bSThierry Reding if (params.active_frac == 0) { 85334fa183bSThierry Reding config->active_polarity = 0; 85434fa183bSThierry Reding config->active_count = params.active_count; 85534fa183bSThierry Reding 85634fa183bSThierry Reding if (!params.active_polarity) 85734fa183bSThierry Reding config->active_count--; 85834fa183bSThierry Reding 85934fa183bSThierry Reding config->tu_size = params.tu_size; 86034fa183bSThierry Reding config->active_frac = 1; 86134fa183bSThierry Reding } else { 86234fa183bSThierry Reding config->active_polarity = params.active_polarity; 86334fa183bSThierry Reding config->active_count = params.active_count; 86434fa183bSThierry Reding config->active_frac = params.active_frac; 86534fa183bSThierry Reding config->tu_size = params.tu_size; 86634fa183bSThierry Reding } 86734fa183bSThierry Reding 86834fa183bSThierry Reding dev_dbg(sor->dev, 86934fa183bSThierry Reding "polarity: %d active count: %d tu size: %d active frac: %d\n", 87034fa183bSThierry Reding config->active_polarity, config->active_count, 87134fa183bSThierry Reding config->tu_size, config->active_frac); 87234fa183bSThierry Reding 87334fa183bSThierry Reding watermark = params.ratio * config->tu_size * (f - params.ratio); 87434fa183bSThierry Reding watermark = div_u64(watermark, f); 87534fa183bSThierry Reding 87634fa183bSThierry Reding watermark = div_u64(watermark + params.error, f); 87734fa183bSThierry Reding config->watermark = watermark + (config->bits_per_pixel / 8) + 2; 87834fa183bSThierry Reding num_syms_per_line = (mode->hdisplay * config->bits_per_pixel) * 87934fa183bSThierry Reding (link->num_lanes * 8); 88034fa183bSThierry Reding 88134fa183bSThierry Reding if (config->watermark > 30) { 88234fa183bSThierry Reding config->watermark = 30; 88334fa183bSThierry Reding dev_err(sor->dev, 88434fa183bSThierry Reding "unable to compute TU size, forcing watermark to %u\n", 88534fa183bSThierry Reding config->watermark); 88634fa183bSThierry Reding } else if (config->watermark > num_syms_per_line) { 88734fa183bSThierry Reding config->watermark = num_syms_per_line; 88834fa183bSThierry Reding dev_err(sor->dev, "watermark too high, forcing to %u\n", 88934fa183bSThierry Reding config->watermark); 89034fa183bSThierry Reding } 89134fa183bSThierry Reding 8927890b576SThierry Reding /* compute the number of symbols per horizontal blanking interval */ 8937890b576SThierry Reding num = ((mode->htotal - mode->hdisplay) - 7) * link_rate; 8947890b576SThierry Reding config->hblank_symbols = div_u64(num, pclk); 8957890b576SThierry Reding 8967890b576SThierry Reding if (link->capabilities & DP_LINK_CAP_ENHANCED_FRAMING) 8977890b576SThierry Reding config->hblank_symbols -= 3; 8987890b576SThierry Reding 8997890b576SThierry Reding config->hblank_symbols -= 12 / link->num_lanes; 9007890b576SThierry Reding 9017890b576SThierry Reding /* compute the number of symbols per vertical blanking interval */ 9027890b576SThierry Reding num = (mode->hdisplay - 25) * link_rate; 9037890b576SThierry Reding config->vblank_symbols = div_u64(num, pclk); 9047890b576SThierry Reding config->vblank_symbols -= 36 / link->num_lanes + 4; 9057890b576SThierry Reding 9067890b576SThierry Reding dev_dbg(sor->dev, "blank symbols: H:%u V:%u\n", config->hblank_symbols, 9077890b576SThierry Reding config->vblank_symbols); 9087890b576SThierry Reding 90934fa183bSThierry Reding return 0; 91034fa183bSThierry Reding } 91134fa183bSThierry Reding 912402f6bcdSThierry Reding static void tegra_sor_apply_config(struct tegra_sor *sor, 913402f6bcdSThierry Reding const struct tegra_sor_config *config) 914402f6bcdSThierry Reding { 915402f6bcdSThierry Reding u32 value; 916402f6bcdSThierry Reding 917402f6bcdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_LINKCTL0); 918402f6bcdSThierry Reding value &= ~SOR_DP_LINKCTL_TU_SIZE_MASK; 919402f6bcdSThierry Reding value |= SOR_DP_LINKCTL_TU_SIZE(config->tu_size); 920402f6bcdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_LINKCTL0); 921402f6bcdSThierry Reding 922402f6bcdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_CONFIG0); 923402f6bcdSThierry Reding value &= ~SOR_DP_CONFIG_WATERMARK_MASK; 924402f6bcdSThierry Reding value |= SOR_DP_CONFIG_WATERMARK(config->watermark); 925402f6bcdSThierry Reding 926402f6bcdSThierry Reding value &= ~SOR_DP_CONFIG_ACTIVE_SYM_COUNT_MASK; 927402f6bcdSThierry Reding value |= SOR_DP_CONFIG_ACTIVE_SYM_COUNT(config->active_count); 928402f6bcdSThierry Reding 929402f6bcdSThierry Reding value &= ~SOR_DP_CONFIG_ACTIVE_SYM_FRAC_MASK; 930402f6bcdSThierry Reding value |= SOR_DP_CONFIG_ACTIVE_SYM_FRAC(config->active_frac); 931402f6bcdSThierry Reding 932402f6bcdSThierry Reding if (config->active_polarity) 933402f6bcdSThierry Reding value |= SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; 934402f6bcdSThierry Reding else 935402f6bcdSThierry Reding value &= ~SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; 936402f6bcdSThierry Reding 937402f6bcdSThierry Reding value |= SOR_DP_CONFIG_ACTIVE_SYM_ENABLE; 938402f6bcdSThierry Reding value |= SOR_DP_CONFIG_DISPARITY_NEGATIVE; 939402f6bcdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_CONFIG0); 940402f6bcdSThierry Reding 941402f6bcdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_AUDIO_HBLANK_SYMBOLS); 942402f6bcdSThierry Reding value &= ~SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK; 943402f6bcdSThierry Reding value |= config->hblank_symbols & 0xffff; 944402f6bcdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_AUDIO_HBLANK_SYMBOLS); 945402f6bcdSThierry Reding 946402f6bcdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_AUDIO_VBLANK_SYMBOLS); 947402f6bcdSThierry Reding value &= ~SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK; 948402f6bcdSThierry Reding value |= config->vblank_symbols & 0xffff; 949402f6bcdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_AUDIO_VBLANK_SYMBOLS); 950402f6bcdSThierry Reding } 951402f6bcdSThierry Reding 9522bd1dd39SThierry Reding static void tegra_sor_mode_set(struct tegra_sor *sor, 9532bd1dd39SThierry Reding const struct drm_display_mode *mode, 954c31efa7aSThierry Reding struct tegra_sor_state *state) 9552bd1dd39SThierry Reding { 9562bd1dd39SThierry Reding struct tegra_dc *dc = to_tegra_dc(sor->output.encoder.crtc); 9572bd1dd39SThierry Reding unsigned int vbe, vse, hbe, hse, vbs, hbs; 9582bd1dd39SThierry Reding u32 value; 9592bd1dd39SThierry Reding 9602bd1dd39SThierry Reding value = tegra_sor_readl(sor, SOR_STATE1); 9612bd1dd39SThierry Reding value &= ~SOR_STATE_ASY_PIXELDEPTH_MASK; 9622bd1dd39SThierry Reding value &= ~SOR_STATE_ASY_CRC_MODE_MASK; 9632bd1dd39SThierry Reding value &= ~SOR_STATE_ASY_OWNER_MASK; 9642bd1dd39SThierry Reding 9652bd1dd39SThierry Reding value |= SOR_STATE_ASY_CRC_MODE_COMPLETE | 9662bd1dd39SThierry Reding SOR_STATE_ASY_OWNER(dc->pipe + 1); 9672bd1dd39SThierry Reding 9682bd1dd39SThierry Reding if (mode->flags & DRM_MODE_FLAG_PHSYNC) 9692bd1dd39SThierry Reding value &= ~SOR_STATE_ASY_HSYNCPOL; 9702bd1dd39SThierry Reding 9712bd1dd39SThierry Reding if (mode->flags & DRM_MODE_FLAG_NHSYNC) 9722bd1dd39SThierry Reding value |= SOR_STATE_ASY_HSYNCPOL; 9732bd1dd39SThierry Reding 9742bd1dd39SThierry Reding if (mode->flags & DRM_MODE_FLAG_PVSYNC) 9752bd1dd39SThierry Reding value &= ~SOR_STATE_ASY_VSYNCPOL; 9762bd1dd39SThierry Reding 9772bd1dd39SThierry Reding if (mode->flags & DRM_MODE_FLAG_NVSYNC) 9782bd1dd39SThierry Reding value |= SOR_STATE_ASY_VSYNCPOL; 9792bd1dd39SThierry Reding 980c31efa7aSThierry Reding switch (state->bpc) { 981c31efa7aSThierry Reding case 16: 982c31efa7aSThierry Reding value |= SOR_STATE_ASY_PIXELDEPTH_BPP_48_444; 983c31efa7aSThierry Reding break; 984c31efa7aSThierry Reding 985c31efa7aSThierry Reding case 12: 986c31efa7aSThierry Reding value |= SOR_STATE_ASY_PIXELDEPTH_BPP_36_444; 987c31efa7aSThierry Reding break; 988c31efa7aSThierry Reding 989c31efa7aSThierry Reding case 10: 990c31efa7aSThierry Reding value |= SOR_STATE_ASY_PIXELDEPTH_BPP_30_444; 991c31efa7aSThierry Reding break; 992c31efa7aSThierry Reding 9932bd1dd39SThierry Reding case 8: 9942bd1dd39SThierry Reding value |= SOR_STATE_ASY_PIXELDEPTH_BPP_24_444; 9952bd1dd39SThierry Reding break; 9962bd1dd39SThierry Reding 9972bd1dd39SThierry Reding case 6: 9982bd1dd39SThierry Reding value |= SOR_STATE_ASY_PIXELDEPTH_BPP_18_444; 9992bd1dd39SThierry Reding break; 10002bd1dd39SThierry Reding 10012bd1dd39SThierry Reding default: 1002c31efa7aSThierry Reding value |= SOR_STATE_ASY_PIXELDEPTH_BPP_24_444; 10032bd1dd39SThierry Reding break; 10042bd1dd39SThierry Reding } 10052bd1dd39SThierry Reding 10062bd1dd39SThierry Reding tegra_sor_writel(sor, value, SOR_STATE1); 10072bd1dd39SThierry Reding 10082bd1dd39SThierry Reding /* 10092bd1dd39SThierry Reding * TODO: The video timing programming below doesn't seem to match the 10102bd1dd39SThierry Reding * register definitions. 10112bd1dd39SThierry Reding */ 10122bd1dd39SThierry Reding 10132bd1dd39SThierry Reding value = ((mode->vtotal & 0x7fff) << 16) | (mode->htotal & 0x7fff); 1014880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->head_state1 + dc->pipe); 10152bd1dd39SThierry Reding 10162bd1dd39SThierry Reding /* sync end = sync width - 1 */ 10172bd1dd39SThierry Reding vse = mode->vsync_end - mode->vsync_start - 1; 10182bd1dd39SThierry Reding hse = mode->hsync_end - mode->hsync_start - 1; 10192bd1dd39SThierry Reding 10202bd1dd39SThierry Reding value = ((vse & 0x7fff) << 16) | (hse & 0x7fff); 1021880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->head_state2 + dc->pipe); 10222bd1dd39SThierry Reding 10232bd1dd39SThierry Reding /* blank end = sync end + back porch */ 10242bd1dd39SThierry Reding vbe = vse + (mode->vtotal - mode->vsync_end); 10252bd1dd39SThierry Reding hbe = hse + (mode->htotal - mode->hsync_end); 10262bd1dd39SThierry Reding 10272bd1dd39SThierry Reding value = ((vbe & 0x7fff) << 16) | (hbe & 0x7fff); 1028880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->head_state3 + dc->pipe); 10292bd1dd39SThierry Reding 10302bd1dd39SThierry Reding /* blank start = blank end + active */ 10312bd1dd39SThierry Reding vbs = vbe + mode->vdisplay; 10322bd1dd39SThierry Reding hbs = hbe + mode->hdisplay; 10332bd1dd39SThierry Reding 10342bd1dd39SThierry Reding value = ((vbs & 0x7fff) << 16) | (hbs & 0x7fff); 1035880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->head_state4 + dc->pipe); 10362bd1dd39SThierry Reding 10372bd1dd39SThierry Reding /* XXX interlacing support */ 1038880cee0bSThierry Reding tegra_sor_writel(sor, 0x001, sor->soc->regs->head_state5 + dc->pipe); 10392bd1dd39SThierry Reding } 10402bd1dd39SThierry Reding 10416fad8f66SThierry Reding static int tegra_sor_detach(struct tegra_sor *sor) 10426b6b6042SThierry Reding { 10436fad8f66SThierry Reding unsigned long value, timeout; 10446fad8f66SThierry Reding 10456fad8f66SThierry Reding /* switch to safe mode */ 1046a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE1); 10476fad8f66SThierry Reding value &= ~SOR_SUPER_STATE_MODE_NORMAL; 1048a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE1); 10496fad8f66SThierry Reding tegra_sor_super_update(sor); 10506fad8f66SThierry Reding 10516fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 10526fad8f66SThierry Reding 10536fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 10546fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 10556fad8f66SThierry Reding if (value & SOR_PWR_MODE_SAFE) 10566fad8f66SThierry Reding break; 10576fad8f66SThierry Reding } 10586fad8f66SThierry Reding 10596fad8f66SThierry Reding if ((value & SOR_PWR_MODE_SAFE) == 0) 10606fad8f66SThierry Reding return -ETIMEDOUT; 10616fad8f66SThierry Reding 10626fad8f66SThierry Reding /* go to sleep */ 1063a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE1); 10646fad8f66SThierry Reding value &= ~SOR_SUPER_STATE_HEAD_MODE_MASK; 1065a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE1); 10666fad8f66SThierry Reding tegra_sor_super_update(sor); 10676fad8f66SThierry Reding 10686fad8f66SThierry Reding /* detach */ 1069a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE1); 10706fad8f66SThierry Reding value &= ~SOR_SUPER_STATE_ATTACHED; 1071a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE1); 10726fad8f66SThierry Reding tegra_sor_super_update(sor); 10736fad8f66SThierry Reding 10746fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 10756fad8f66SThierry Reding 10766fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 10776fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_TEST); 10786fad8f66SThierry Reding if ((value & SOR_TEST_ATTACHED) == 0) 10796fad8f66SThierry Reding break; 10806fad8f66SThierry Reding 10816fad8f66SThierry Reding usleep_range(25, 100); 10826fad8f66SThierry Reding } 10836fad8f66SThierry Reding 10846fad8f66SThierry Reding if ((value & SOR_TEST_ATTACHED) != 0) 10856fad8f66SThierry Reding return -ETIMEDOUT; 10866fad8f66SThierry Reding 10876fad8f66SThierry Reding return 0; 10886fad8f66SThierry Reding } 10896fad8f66SThierry Reding 10906fad8f66SThierry Reding static int tegra_sor_power_down(struct tegra_sor *sor) 10916fad8f66SThierry Reding { 10926fad8f66SThierry Reding unsigned long value, timeout; 10936fad8f66SThierry Reding int err; 10946fad8f66SThierry Reding 10956fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 10966fad8f66SThierry Reding value &= ~SOR_PWR_NORMAL_STATE_PU; 10976fad8f66SThierry Reding value |= SOR_PWR_TRIGGER; 10986fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_PWR); 10996fad8f66SThierry Reding 11006fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 11016fad8f66SThierry Reding 11026fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 11036fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 11046fad8f66SThierry Reding if ((value & SOR_PWR_TRIGGER) == 0) 11056fad8f66SThierry Reding return 0; 11066fad8f66SThierry Reding 11076fad8f66SThierry Reding usleep_range(25, 100); 11086fad8f66SThierry Reding } 11096fad8f66SThierry Reding 11106fad8f66SThierry Reding if ((value & SOR_PWR_TRIGGER) != 0) 11116fad8f66SThierry Reding return -ETIMEDOUT; 11126fad8f66SThierry Reding 111325bb2cecSThierry Reding /* switch to safe parent clock */ 111425bb2cecSThierry Reding err = tegra_sor_set_parent_clock(sor, sor->clk_safe); 1115e1335e2fSThierry Reding if (err < 0) { 11166fad8f66SThierry Reding dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); 1117e1335e2fSThierry Reding return err; 1118e1335e2fSThierry Reding } 11196fad8f66SThierry Reding 1120880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->dp_padctl0); 11216fad8f66SThierry Reding value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 | 11226fad8f66SThierry Reding SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2); 1123880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->dp_padctl0); 11246fad8f66SThierry Reding 11256fad8f66SThierry Reding /* stop lane sequencer */ 11266fad8f66SThierry Reding value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_UP | 11276fad8f66SThierry Reding SOR_LANE_SEQ_CTL_POWER_STATE_DOWN; 11286fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL); 11296fad8f66SThierry Reding 11306fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 11316fad8f66SThierry Reding 11326fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 11336fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL); 11346fad8f66SThierry Reding if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0) 11356fad8f66SThierry Reding break; 11366fad8f66SThierry Reding 11376fad8f66SThierry Reding usleep_range(25, 100); 11386fad8f66SThierry Reding } 11396fad8f66SThierry Reding 11406fad8f66SThierry Reding if ((value & SOR_LANE_SEQ_CTL_TRIGGER) != 0) 11416fad8f66SThierry Reding return -ETIMEDOUT; 11426fad8f66SThierry Reding 1143880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll2); 1144a9a9e4fdSThierry Reding value |= SOR_PLL2_PORT_POWERDOWN; 1145880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll2); 11466fad8f66SThierry Reding 11476fad8f66SThierry Reding usleep_range(20, 100); 11486fad8f66SThierry Reding 1149880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll0); 1150a9a9e4fdSThierry Reding value |= SOR_PLL0_VCOPD | SOR_PLL0_PWR; 1151880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll0); 11526fad8f66SThierry Reding 1153880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll2); 1154a9a9e4fdSThierry Reding value |= SOR_PLL2_SEQ_PLLCAPPD; 1155a9a9e4fdSThierry Reding value |= SOR_PLL2_SEQ_PLLCAPPD_ENFORCE; 1156880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll2); 11576fad8f66SThierry Reding 11586fad8f66SThierry Reding usleep_range(20, 100); 11596fad8f66SThierry Reding 11606fad8f66SThierry Reding return 0; 11616fad8f66SThierry Reding } 11626fad8f66SThierry Reding 11636fad8f66SThierry Reding static int tegra_sor_crc_wait(struct tegra_sor *sor, unsigned long timeout) 11646fad8f66SThierry Reding { 11656fad8f66SThierry Reding u32 value; 11666fad8f66SThierry Reding 11676fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(timeout); 11686fad8f66SThierry Reding 11696fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 1170a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_CRCA); 1171a9a9e4fdSThierry Reding if (value & SOR_CRCA_VALID) 11726fad8f66SThierry Reding return 0; 11736fad8f66SThierry Reding 11746fad8f66SThierry Reding usleep_range(100, 200); 11756fad8f66SThierry Reding } 11766fad8f66SThierry Reding 11776fad8f66SThierry Reding return -ETIMEDOUT; 11786fad8f66SThierry Reding } 11796fad8f66SThierry Reding 1180530239a8SThierry Reding static int tegra_sor_show_crc(struct seq_file *s, void *data) 11816fad8f66SThierry Reding { 1182530239a8SThierry Reding struct drm_info_node *node = s->private; 1183530239a8SThierry Reding struct tegra_sor *sor = node->info_ent->data; 1184850bab44SThierry Reding struct drm_crtc *crtc = sor->output.encoder.crtc; 1185850bab44SThierry Reding struct drm_device *drm = node->minor->dev; 1186530239a8SThierry Reding int err = 0; 11876fad8f66SThierry Reding u32 value; 11886fad8f66SThierry Reding 1189850bab44SThierry Reding drm_modeset_lock_all(drm); 11906fad8f66SThierry Reding 1191850bab44SThierry Reding if (!crtc || !crtc->state->active) { 1192850bab44SThierry Reding err = -EBUSY; 11936fad8f66SThierry Reding goto unlock; 11946fad8f66SThierry Reding } 11956fad8f66SThierry Reding 1196a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_STATE1); 11976fad8f66SThierry Reding value &= ~SOR_STATE_ASY_CRC_MODE_MASK; 1198a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_STATE1); 11996fad8f66SThierry Reding 12006fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_CRC_CNTRL); 12016fad8f66SThierry Reding value |= SOR_CRC_CNTRL_ENABLE; 12026fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_CRC_CNTRL); 12036fad8f66SThierry Reding 12046fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_TEST); 12056fad8f66SThierry Reding value &= ~SOR_TEST_CRC_POST_SERIALIZE; 12066fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_TEST); 12076fad8f66SThierry Reding 12086fad8f66SThierry Reding err = tegra_sor_crc_wait(sor, 100); 12096fad8f66SThierry Reding if (err < 0) 12106fad8f66SThierry Reding goto unlock; 12116fad8f66SThierry Reding 1212a9a9e4fdSThierry Reding tegra_sor_writel(sor, SOR_CRCA_RESET, SOR_CRCA); 1213a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_CRCB); 12146fad8f66SThierry Reding 1215530239a8SThierry Reding seq_printf(s, "%08x\n", value); 12166fad8f66SThierry Reding 12176fad8f66SThierry Reding unlock: 1218850bab44SThierry Reding drm_modeset_unlock_all(drm); 12196fad8f66SThierry Reding return err; 12206fad8f66SThierry Reding } 12216fad8f66SThierry Reding 1222062f5b2cSThierry Reding #define DEBUGFS_REG32(_name) { .name = #_name, .offset = _name } 1223062f5b2cSThierry Reding 1224062f5b2cSThierry Reding static const struct debugfs_reg32 tegra_sor_regs[] = { 1225062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CTXSW), 1226062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SUPER_STATE0), 1227062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SUPER_STATE1), 1228062f5b2cSThierry Reding DEBUGFS_REG32(SOR_STATE0), 1229062f5b2cSThierry Reding DEBUGFS_REG32(SOR_STATE1), 1230062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE0(0)), 1231062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE0(1)), 1232062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE1(0)), 1233062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE1(1)), 1234062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE2(0)), 1235062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE2(1)), 1236062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE3(0)), 1237062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE3(1)), 1238062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE4(0)), 1239062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE4(1)), 1240062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE5(0)), 1241062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE5(1)), 1242062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CRC_CNTRL), 1243062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_DEBUG_MVID), 1244062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CLK_CNTRL), 1245062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CAP), 1246062f5b2cSThierry Reding DEBUGFS_REG32(SOR_PWR), 1247062f5b2cSThierry Reding DEBUGFS_REG32(SOR_TEST), 1248062f5b2cSThierry Reding DEBUGFS_REG32(SOR_PLL0), 1249062f5b2cSThierry Reding DEBUGFS_REG32(SOR_PLL1), 1250062f5b2cSThierry Reding DEBUGFS_REG32(SOR_PLL2), 1251062f5b2cSThierry Reding DEBUGFS_REG32(SOR_PLL3), 1252062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CSTM), 1253062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LVDS), 1254062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CRCA), 1255062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CRCB), 1256062f5b2cSThierry Reding DEBUGFS_REG32(SOR_BLANK), 1257062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_CTL), 1258062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE_SEQ_CTL), 1259062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(0)), 1260062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(1)), 1261062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(2)), 1262062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(3)), 1263062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(4)), 1264062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(5)), 1265062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(6)), 1266062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(7)), 1267062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(8)), 1268062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(9)), 1269062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(10)), 1270062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(11)), 1271062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(12)), 1272062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(13)), 1273062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(14)), 1274062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(15)), 1275062f5b2cSThierry Reding DEBUGFS_REG32(SOR_PWM_DIV), 1276062f5b2cSThierry Reding DEBUGFS_REG32(SOR_PWM_CTL), 1277062f5b2cSThierry Reding DEBUGFS_REG32(SOR_VCRC_A0), 1278062f5b2cSThierry Reding DEBUGFS_REG32(SOR_VCRC_A1), 1279062f5b2cSThierry Reding DEBUGFS_REG32(SOR_VCRC_B0), 1280062f5b2cSThierry Reding DEBUGFS_REG32(SOR_VCRC_B1), 1281062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CCRC_A0), 1282062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CCRC_A1), 1283062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CCRC_B0), 1284062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CCRC_B1), 1285062f5b2cSThierry Reding DEBUGFS_REG32(SOR_EDATA_A0), 1286062f5b2cSThierry Reding DEBUGFS_REG32(SOR_EDATA_A1), 1287062f5b2cSThierry Reding DEBUGFS_REG32(SOR_EDATA_B0), 1288062f5b2cSThierry Reding DEBUGFS_REG32(SOR_EDATA_B1), 1289062f5b2cSThierry Reding DEBUGFS_REG32(SOR_COUNT_A0), 1290062f5b2cSThierry Reding DEBUGFS_REG32(SOR_COUNT_A1), 1291062f5b2cSThierry Reding DEBUGFS_REG32(SOR_COUNT_B0), 1292062f5b2cSThierry Reding DEBUGFS_REG32(SOR_COUNT_B1), 1293062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DEBUG_A0), 1294062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DEBUG_A1), 1295062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DEBUG_B0), 1296062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DEBUG_B1), 1297062f5b2cSThierry Reding DEBUGFS_REG32(SOR_TRIG), 1298062f5b2cSThierry Reding DEBUGFS_REG32(SOR_MSCHECK), 1299062f5b2cSThierry Reding DEBUGFS_REG32(SOR_XBAR_CTRL), 1300062f5b2cSThierry Reding DEBUGFS_REG32(SOR_XBAR_POL), 1301062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_LINKCTL0), 1302062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_LINKCTL1), 1303062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE_DRIVE_CURRENT0), 1304062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE_DRIVE_CURRENT1), 1305062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE4_DRIVE_CURRENT0), 1306062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE4_DRIVE_CURRENT1), 1307062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE_PREEMPHASIS0), 1308062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE_PREEMPHASIS1), 1309062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE4_PREEMPHASIS0), 1310062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE4_PREEMPHASIS1), 1311062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE_POSTCURSOR0), 1312062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE_POSTCURSOR1), 1313062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_CONFIG0), 1314062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_CONFIG1), 1315062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_MN0), 1316062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_MN1), 1317062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_PADCTL0), 1318062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_PADCTL1), 1319*c57997bcSThierry Reding DEBUGFS_REG32(SOR_DP_PADCTL2), 1320062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_DEBUG0), 1321062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_DEBUG1), 1322062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_SPARE0), 1323062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_SPARE1), 1324062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_AUDIO_CTRL), 1325062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_AUDIO_HBLANK_SYMBOLS), 1326062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_AUDIO_VBLANK_SYMBOLS), 1327062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_GENERIC_INFOFRAME_HEADER), 1328062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_GENERIC_INFOFRAME_SUBPACK0), 1329062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_GENERIC_INFOFRAME_SUBPACK1), 1330062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_GENERIC_INFOFRAME_SUBPACK2), 1331062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_GENERIC_INFOFRAME_SUBPACK3), 1332062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_GENERIC_INFOFRAME_SUBPACK4), 1333062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_GENERIC_INFOFRAME_SUBPACK5), 1334062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_GENERIC_INFOFRAME_SUBPACK6), 1335062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_TPG), 1336062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_TPG_CONFIG), 1337062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_LQ_CSTM0), 1338062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_LQ_CSTM1), 1339062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_LQ_CSTM2), 1340062f5b2cSThierry Reding }; 1341062f5b2cSThierry Reding 1342dab16336SThierry Reding static int tegra_sor_show_regs(struct seq_file *s, void *data) 1343dab16336SThierry Reding { 1344dab16336SThierry Reding struct drm_info_node *node = s->private; 1345dab16336SThierry Reding struct tegra_sor *sor = node->info_ent->data; 1346850bab44SThierry Reding struct drm_crtc *crtc = sor->output.encoder.crtc; 1347850bab44SThierry Reding struct drm_device *drm = node->minor->dev; 1348062f5b2cSThierry Reding unsigned int i; 1349850bab44SThierry Reding int err = 0; 1350850bab44SThierry Reding 1351850bab44SThierry Reding drm_modeset_lock_all(drm); 1352850bab44SThierry Reding 1353850bab44SThierry Reding if (!crtc || !crtc->state->active) { 1354850bab44SThierry Reding err = -EBUSY; 1355850bab44SThierry Reding goto unlock; 1356850bab44SThierry Reding } 1357dab16336SThierry Reding 1358062f5b2cSThierry Reding for (i = 0; i < ARRAY_SIZE(tegra_sor_regs); i++) { 1359062f5b2cSThierry Reding unsigned int offset = tegra_sor_regs[i].offset; 1360dab16336SThierry Reding 1361062f5b2cSThierry Reding seq_printf(s, "%-38s %#05x %08x\n", tegra_sor_regs[i].name, 1362062f5b2cSThierry Reding offset, tegra_sor_readl(sor, offset)); 1363062f5b2cSThierry Reding } 1364dab16336SThierry Reding 1365850bab44SThierry Reding unlock: 1366850bab44SThierry Reding drm_modeset_unlock_all(drm); 1367850bab44SThierry Reding return err; 1368dab16336SThierry Reding } 1369dab16336SThierry Reding 1370dab16336SThierry Reding static const struct drm_info_list debugfs_files[] = { 1371530239a8SThierry Reding { "crc", tegra_sor_show_crc, 0, NULL }, 1372dab16336SThierry Reding { "regs", tegra_sor_show_regs, 0, NULL }, 1373dab16336SThierry Reding }; 1374dab16336SThierry Reding 13755b8e043bSThierry Reding static int tegra_sor_late_register(struct drm_connector *connector) 13766fad8f66SThierry Reding { 13775b8e043bSThierry Reding struct tegra_output *output = connector_to_output(connector); 13785b8e043bSThierry Reding unsigned int i, count = ARRAY_SIZE(debugfs_files); 13795b8e043bSThierry Reding struct drm_minor *minor = connector->dev->primary; 13805b8e043bSThierry Reding struct dentry *root = connector->debugfs_entry; 13815b8e043bSThierry Reding struct tegra_sor *sor = to_sor(output); 1382530239a8SThierry Reding int err; 13836fad8f66SThierry Reding 1384dab16336SThierry Reding sor->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files), 1385dab16336SThierry Reding GFP_KERNEL); 13865b8e043bSThierry Reding if (!sor->debugfs_files) 13875b8e043bSThierry Reding return -ENOMEM; 13886fad8f66SThierry Reding 13895b8e043bSThierry Reding for (i = 0; i < count; i++) 1390dab16336SThierry Reding sor->debugfs_files[i].data = sor; 1391dab16336SThierry Reding 13925b8e043bSThierry Reding err = drm_debugfs_create_files(sor->debugfs_files, count, root, minor); 1393dab16336SThierry Reding if (err < 0) 1394dab16336SThierry Reding goto free; 1395dab16336SThierry Reding 1396530239a8SThierry Reding return 0; 13976fad8f66SThierry Reding 1398dab16336SThierry Reding free: 1399dab16336SThierry Reding kfree(sor->debugfs_files); 1400dab16336SThierry Reding sor->debugfs_files = NULL; 14015b8e043bSThierry Reding 14026fad8f66SThierry Reding return err; 14036fad8f66SThierry Reding } 14046fad8f66SThierry Reding 14055b8e043bSThierry Reding static void tegra_sor_early_unregister(struct drm_connector *connector) 14066fad8f66SThierry Reding { 14075b8e043bSThierry Reding struct tegra_output *output = connector_to_output(connector); 14085b8e043bSThierry Reding unsigned int count = ARRAY_SIZE(debugfs_files); 14095b8e043bSThierry Reding struct tegra_sor *sor = to_sor(output); 1410d92e6009SThierry Reding 14115b8e043bSThierry Reding drm_debugfs_remove_files(sor->debugfs_files, count, 14125b8e043bSThierry Reding connector->dev->primary); 1413dab16336SThierry Reding kfree(sor->debugfs_files); 1414066d30f8SThierry Reding sor->debugfs_files = NULL; 14156fad8f66SThierry Reding } 14166fad8f66SThierry Reding 1417c31efa7aSThierry Reding static void tegra_sor_connector_reset(struct drm_connector *connector) 1418c31efa7aSThierry Reding { 1419c31efa7aSThierry Reding struct tegra_sor_state *state; 1420c31efa7aSThierry Reding 1421c31efa7aSThierry Reding state = kzalloc(sizeof(*state), GFP_KERNEL); 1422c31efa7aSThierry Reding if (!state) 1423c31efa7aSThierry Reding return; 1424c31efa7aSThierry Reding 1425c31efa7aSThierry Reding if (connector->state) { 1426c31efa7aSThierry Reding __drm_atomic_helper_connector_destroy_state(connector->state); 1427c31efa7aSThierry Reding kfree(connector->state); 1428c31efa7aSThierry Reding } 1429c31efa7aSThierry Reding 1430c31efa7aSThierry Reding __drm_atomic_helper_connector_reset(connector, &state->base); 1431c31efa7aSThierry Reding } 1432c31efa7aSThierry Reding 14336fad8f66SThierry Reding static enum drm_connector_status 14346fad8f66SThierry Reding tegra_sor_connector_detect(struct drm_connector *connector, bool force) 14356fad8f66SThierry Reding { 14366fad8f66SThierry Reding struct tegra_output *output = connector_to_output(connector); 14376fad8f66SThierry Reding struct tegra_sor *sor = to_sor(output); 14386fad8f66SThierry Reding 14399542c237SThierry Reding if (sor->aux) 14409542c237SThierry Reding return drm_dp_aux_detect(sor->aux); 14416fad8f66SThierry Reding 1442459cc2c6SThierry Reding return tegra_output_connector_detect(connector, force); 14436fad8f66SThierry Reding } 14446fad8f66SThierry Reding 1445c31efa7aSThierry Reding static struct drm_connector_state * 1446c31efa7aSThierry Reding tegra_sor_connector_duplicate_state(struct drm_connector *connector) 1447c31efa7aSThierry Reding { 1448c31efa7aSThierry Reding struct tegra_sor_state *state = to_sor_state(connector->state); 1449c31efa7aSThierry Reding struct tegra_sor_state *copy; 1450c31efa7aSThierry Reding 1451c31efa7aSThierry Reding copy = kmemdup(state, sizeof(*state), GFP_KERNEL); 1452c31efa7aSThierry Reding if (!copy) 1453c31efa7aSThierry Reding return NULL; 1454c31efa7aSThierry Reding 1455c31efa7aSThierry Reding __drm_atomic_helper_connector_duplicate_state(connector, ©->base); 1456c31efa7aSThierry Reding 1457c31efa7aSThierry Reding return ©->base; 1458c31efa7aSThierry Reding } 1459c31efa7aSThierry Reding 14606fad8f66SThierry Reding static const struct drm_connector_funcs tegra_sor_connector_funcs = { 1461c31efa7aSThierry Reding .reset = tegra_sor_connector_reset, 14626fad8f66SThierry Reding .detect = tegra_sor_connector_detect, 14636fad8f66SThierry Reding .fill_modes = drm_helper_probe_single_connector_modes, 14646fad8f66SThierry Reding .destroy = tegra_output_connector_destroy, 1465c31efa7aSThierry Reding .atomic_duplicate_state = tegra_sor_connector_duplicate_state, 14664aa3df71SThierry Reding .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 14675b8e043bSThierry Reding .late_register = tegra_sor_late_register, 14685b8e043bSThierry Reding .early_unregister = tegra_sor_early_unregister, 14696fad8f66SThierry Reding }; 14706fad8f66SThierry Reding 14716fad8f66SThierry Reding static int tegra_sor_connector_get_modes(struct drm_connector *connector) 14726fad8f66SThierry Reding { 14736fad8f66SThierry Reding struct tegra_output *output = connector_to_output(connector); 14746fad8f66SThierry Reding struct tegra_sor *sor = to_sor(output); 14756fad8f66SThierry Reding int err; 14766fad8f66SThierry Reding 14779542c237SThierry Reding if (sor->aux) 14789542c237SThierry Reding drm_dp_aux_enable(sor->aux); 14796fad8f66SThierry Reding 14806fad8f66SThierry Reding err = tegra_output_connector_get_modes(connector); 14816fad8f66SThierry Reding 14829542c237SThierry Reding if (sor->aux) 14839542c237SThierry Reding drm_dp_aux_disable(sor->aux); 14846fad8f66SThierry Reding 14856fad8f66SThierry Reding return err; 14866fad8f66SThierry Reding } 14876fad8f66SThierry Reding 14886fad8f66SThierry Reding static enum drm_mode_status 14896fad8f66SThierry Reding tegra_sor_connector_mode_valid(struct drm_connector *connector, 14906fad8f66SThierry Reding struct drm_display_mode *mode) 14916fad8f66SThierry Reding { 149264ea25c3SThierry Reding /* HDMI 2.0 modes are not yet supported */ 149364ea25c3SThierry Reding if (mode->clock > 340000) 149464ea25c3SThierry Reding return MODE_NOCLOCK; 149564ea25c3SThierry Reding 14966fad8f66SThierry Reding return MODE_OK; 14976fad8f66SThierry Reding } 14986fad8f66SThierry Reding 14996fad8f66SThierry Reding static const struct drm_connector_helper_funcs tegra_sor_connector_helper_funcs = { 15006fad8f66SThierry Reding .get_modes = tegra_sor_connector_get_modes, 15016fad8f66SThierry Reding .mode_valid = tegra_sor_connector_mode_valid, 15026fad8f66SThierry Reding }; 15036fad8f66SThierry Reding 15046fad8f66SThierry Reding static const struct drm_encoder_funcs tegra_sor_encoder_funcs = { 15056fad8f66SThierry Reding .destroy = tegra_output_encoder_destroy, 15066fad8f66SThierry Reding }; 15076fad8f66SThierry Reding 1508850bab44SThierry Reding static void tegra_sor_edp_disable(struct drm_encoder *encoder) 15096fad8f66SThierry Reding { 1510850bab44SThierry Reding struct tegra_output *output = encoder_to_output(encoder); 1511850bab44SThierry Reding struct tegra_dc *dc = to_tegra_dc(encoder->crtc); 1512850bab44SThierry Reding struct tegra_sor *sor = to_sor(output); 1513850bab44SThierry Reding u32 value; 1514850bab44SThierry Reding int err; 1515850bab44SThierry Reding 1516850bab44SThierry Reding if (output->panel) 1517850bab44SThierry Reding drm_panel_disable(output->panel); 1518850bab44SThierry Reding 1519850bab44SThierry Reding err = tegra_sor_detach(sor); 1520850bab44SThierry Reding if (err < 0) 1521850bab44SThierry Reding dev_err(sor->dev, "failed to detach SOR: %d\n", err); 1522850bab44SThierry Reding 1523850bab44SThierry Reding tegra_sor_writel(sor, 0, SOR_STATE1); 1524850bab44SThierry Reding tegra_sor_update(sor); 1525850bab44SThierry Reding 1526850bab44SThierry Reding /* 1527850bab44SThierry Reding * The following accesses registers of the display controller, so make 1528850bab44SThierry Reding * sure it's only executed when the output is attached to one. 1529850bab44SThierry Reding */ 1530850bab44SThierry Reding if (dc) { 1531850bab44SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 1532*c57997bcSThierry Reding value &= ~SOR_ENABLE(0); 1533850bab44SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 1534850bab44SThierry Reding 1535850bab44SThierry Reding tegra_dc_commit(dc); 15366fad8f66SThierry Reding } 15376fad8f66SThierry Reding 1538850bab44SThierry Reding err = tegra_sor_power_down(sor); 1539850bab44SThierry Reding if (err < 0) 1540850bab44SThierry Reding dev_err(sor->dev, "failed to power down SOR: %d\n", err); 1541850bab44SThierry Reding 15429542c237SThierry Reding if (sor->aux) { 15439542c237SThierry Reding err = drm_dp_aux_disable(sor->aux); 1544850bab44SThierry Reding if (err < 0) 1545850bab44SThierry Reding dev_err(sor->dev, "failed to disable DP: %d\n", err); 15466fad8f66SThierry Reding } 15476fad8f66SThierry Reding 1548*c57997bcSThierry Reding err = tegra_io_pad_power_disable(sor->pad); 1549850bab44SThierry Reding if (err < 0) 1550*c57997bcSThierry Reding dev_err(sor->dev, "failed to power off I/O pad: %d\n", err); 1551850bab44SThierry Reding 1552850bab44SThierry Reding if (output->panel) 1553850bab44SThierry Reding drm_panel_unprepare(output->panel); 1554850bab44SThierry Reding 1555aaff8bd2SThierry Reding pm_runtime_put(sor->dev); 15566fad8f66SThierry Reding } 15576fad8f66SThierry Reding 1558459cc2c6SThierry Reding #if 0 1559459cc2c6SThierry Reding static int calc_h_ref_to_sync(const struct drm_display_mode *mode, 1560459cc2c6SThierry Reding unsigned int *value) 1561459cc2c6SThierry Reding { 1562459cc2c6SThierry Reding unsigned int hfp, hsw, hbp, a = 0, b; 1563459cc2c6SThierry Reding 1564459cc2c6SThierry Reding hfp = mode->hsync_start - mode->hdisplay; 1565459cc2c6SThierry Reding hsw = mode->hsync_end - mode->hsync_start; 1566459cc2c6SThierry Reding hbp = mode->htotal - mode->hsync_end; 1567459cc2c6SThierry Reding 1568459cc2c6SThierry Reding pr_info("hfp: %u, hsw: %u, hbp: %u\n", hfp, hsw, hbp); 1569459cc2c6SThierry Reding 1570459cc2c6SThierry Reding b = hfp - 1; 1571459cc2c6SThierry Reding 1572459cc2c6SThierry Reding pr_info("a: %u, b: %u\n", a, b); 1573459cc2c6SThierry Reding pr_info("a + hsw + hbp = %u\n", a + hsw + hbp); 1574459cc2c6SThierry Reding 1575459cc2c6SThierry Reding if (a + hsw + hbp <= 11) { 1576459cc2c6SThierry Reding a = 1 + 11 - hsw - hbp; 1577459cc2c6SThierry Reding pr_info("a: %u\n", a); 1578459cc2c6SThierry Reding } 1579459cc2c6SThierry Reding 1580459cc2c6SThierry Reding if (a > b) 1581459cc2c6SThierry Reding return -EINVAL; 1582459cc2c6SThierry Reding 1583459cc2c6SThierry Reding if (hsw < 1) 1584459cc2c6SThierry Reding return -EINVAL; 1585459cc2c6SThierry Reding 1586459cc2c6SThierry Reding if (mode->hdisplay < 16) 1587459cc2c6SThierry Reding return -EINVAL; 1588459cc2c6SThierry Reding 1589459cc2c6SThierry Reding if (value) { 1590459cc2c6SThierry Reding if (b > a && a % 2) 1591459cc2c6SThierry Reding *value = a + 1; 1592459cc2c6SThierry Reding else 1593459cc2c6SThierry Reding *value = a; 1594459cc2c6SThierry Reding } 1595459cc2c6SThierry Reding 1596459cc2c6SThierry Reding return 0; 1597459cc2c6SThierry Reding } 1598459cc2c6SThierry Reding #endif 1599459cc2c6SThierry Reding 1600850bab44SThierry Reding static void tegra_sor_edp_enable(struct drm_encoder *encoder) 16016fad8f66SThierry Reding { 1602850bab44SThierry Reding struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; 16036fad8f66SThierry Reding struct tegra_output *output = encoder_to_output(encoder); 16046fad8f66SThierry Reding struct tegra_dc *dc = to_tegra_dc(encoder->crtc); 16056b6b6042SThierry Reding struct tegra_sor *sor = to_sor(output); 160634fa183bSThierry Reding struct tegra_sor_config config; 1607c31efa7aSThierry Reding struct tegra_sor_state *state; 160834fa183bSThierry Reding struct drm_dp_link link; 160901b9bea0SThierry Reding u8 rate, lanes; 16102bd1dd39SThierry Reding unsigned int i; 161186f5c52dSThierry Reding int err = 0; 161228fe2076SThierry Reding u32 value; 161386f5c52dSThierry Reding 1614c31efa7aSThierry Reding state = to_sor_state(output->connector.state); 16156b6b6042SThierry Reding 1616aaff8bd2SThierry Reding pm_runtime_get_sync(sor->dev); 16176b6b6042SThierry Reding 16186fad8f66SThierry Reding if (output->panel) 16196fad8f66SThierry Reding drm_panel_prepare(output->panel); 16206fad8f66SThierry Reding 16219542c237SThierry Reding err = drm_dp_aux_enable(sor->aux); 16226b6b6042SThierry Reding if (err < 0) 16236b6b6042SThierry Reding dev_err(sor->dev, "failed to enable DP: %d\n", err); 162434fa183bSThierry Reding 16259542c237SThierry Reding err = drm_dp_link_probe(sor->aux, &link); 162634fa183bSThierry Reding if (err < 0) { 162701b9bea0SThierry Reding dev_err(sor->dev, "failed to probe eDP link: %d\n", err); 1628850bab44SThierry Reding return; 162934fa183bSThierry Reding } 16306b6b6042SThierry Reding 163125bb2cecSThierry Reding /* switch to safe parent clock */ 163225bb2cecSThierry Reding err = tegra_sor_set_parent_clock(sor, sor->clk_safe); 16336b6b6042SThierry Reding if (err < 0) 16346b6b6042SThierry Reding dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); 16356b6b6042SThierry Reding 163634fa183bSThierry Reding memset(&config, 0, sizeof(config)); 1637c31efa7aSThierry Reding config.bits_per_pixel = state->bpc * 3; 163834fa183bSThierry Reding 1639a198359eSThierry Reding err = tegra_sor_compute_config(sor, mode, &config, &link); 164034fa183bSThierry Reding if (err < 0) 1641a198359eSThierry Reding dev_err(sor->dev, "failed to compute configuration: %d\n", err); 164234fa183bSThierry Reding 16436b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 16446b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; 16456b6b6042SThierry Reding value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK; 16466b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 16476b6b6042SThierry Reding 1648880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll2); 1649a9a9e4fdSThierry Reding value &= ~SOR_PLL2_BANDGAP_POWERDOWN; 1650880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll2); 16516b6b6042SThierry Reding usleep_range(20, 100); 16526b6b6042SThierry Reding 1653880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll3); 1654a9a9e4fdSThierry Reding value |= SOR_PLL3_PLL_VDD_MODE_3V3; 1655880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll3); 16566b6b6042SThierry Reding 1657a9a9e4fdSThierry Reding value = SOR_PLL0_ICHPMP(0xf) | SOR_PLL0_VCOCAP_RST | 1658a9a9e4fdSThierry Reding SOR_PLL0_PLLREG_LEVEL_V45 | SOR_PLL0_RESISTOR_EXT; 1659880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll0); 16606b6b6042SThierry Reding 1661880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll2); 1662a9a9e4fdSThierry Reding value |= SOR_PLL2_SEQ_PLLCAPPD; 1663a9a9e4fdSThierry Reding value &= ~SOR_PLL2_SEQ_PLLCAPPD_ENFORCE; 1664a9a9e4fdSThierry Reding value |= SOR_PLL2_LVDS_ENABLE; 1665880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll2); 16666b6b6042SThierry Reding 1667a9a9e4fdSThierry Reding value = SOR_PLL1_TERM_COMPOUT | SOR_PLL1_TMDS_TERM; 1668880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll1); 16696b6b6042SThierry Reding 16706b6b6042SThierry Reding while (true) { 1671880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll2); 1672a9a9e4fdSThierry Reding if ((value & SOR_PLL2_SEQ_PLLCAPPD_ENFORCE) == 0) 16736b6b6042SThierry Reding break; 16746b6b6042SThierry Reding 16756b6b6042SThierry Reding usleep_range(250, 1000); 16766b6b6042SThierry Reding } 16776b6b6042SThierry Reding 1678880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll2); 1679a9a9e4fdSThierry Reding value &= ~SOR_PLL2_POWERDOWN_OVERRIDE; 1680a9a9e4fdSThierry Reding value &= ~SOR_PLL2_PORT_POWERDOWN; 1681880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll2); 16826b6b6042SThierry Reding 16836b6b6042SThierry Reding /* 16846b6b6042SThierry Reding * power up 16856b6b6042SThierry Reding */ 16866b6b6042SThierry Reding 16876b6b6042SThierry Reding /* set safe link bandwidth (1.62 Gbps) */ 16886b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 16896b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; 16906b6b6042SThierry Reding value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G1_62; 16916b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 16926b6b6042SThierry Reding 16936b6b6042SThierry Reding /* step 1 */ 1694880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll2); 1695a9a9e4fdSThierry Reding value |= SOR_PLL2_SEQ_PLLCAPPD_ENFORCE | SOR_PLL2_PORT_POWERDOWN | 1696a9a9e4fdSThierry Reding SOR_PLL2_BANDGAP_POWERDOWN; 1697880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll2); 16986b6b6042SThierry Reding 1699880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll0); 1700a9a9e4fdSThierry Reding value |= SOR_PLL0_VCOPD | SOR_PLL0_PWR; 1701880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll0); 17026b6b6042SThierry Reding 1703880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->dp_padctl0); 17046b6b6042SThierry Reding value &= ~SOR_DP_PADCTL_PAD_CAL_PD; 1705880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->dp_padctl0); 17066b6b6042SThierry Reding 17076b6b6042SThierry Reding /* step 2 */ 1708*c57997bcSThierry Reding err = tegra_io_pad_power_enable(sor->pad); 1709850bab44SThierry Reding if (err < 0) 1710*c57997bcSThierry Reding dev_err(sor->dev, "failed to power on I/O pad: %d\n", err); 17116b6b6042SThierry Reding 17126b6b6042SThierry Reding usleep_range(5, 100); 17136b6b6042SThierry Reding 17146b6b6042SThierry Reding /* step 3 */ 1715880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll2); 1716a9a9e4fdSThierry Reding value &= ~SOR_PLL2_BANDGAP_POWERDOWN; 1717880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll2); 17186b6b6042SThierry Reding 17196b6b6042SThierry Reding usleep_range(20, 100); 17206b6b6042SThierry Reding 17216b6b6042SThierry Reding /* step 4 */ 1722880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll0); 1723a9a9e4fdSThierry Reding value &= ~SOR_PLL0_VCOPD; 1724a9a9e4fdSThierry Reding value &= ~SOR_PLL0_PWR; 1725880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll0); 17266b6b6042SThierry Reding 1727880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll2); 1728a9a9e4fdSThierry Reding value &= ~SOR_PLL2_SEQ_PLLCAPPD_ENFORCE; 1729880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll2); 17306b6b6042SThierry Reding 17316b6b6042SThierry Reding usleep_range(200, 1000); 17326b6b6042SThierry Reding 17336b6b6042SThierry Reding /* step 5 */ 1734880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll2); 1735a9a9e4fdSThierry Reding value &= ~SOR_PLL2_PORT_POWERDOWN; 1736880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll2); 17376b6b6042SThierry Reding 173830b49435SThierry Reding /* XXX not in TRM */ 173930b49435SThierry Reding for (value = 0, i = 0; i < 5; i++) 174030b49435SThierry Reding value |= SOR_XBAR_CTRL_LINK0_XSEL(i, sor->soc->xbar_cfg[i]) | 174130b49435SThierry Reding SOR_XBAR_CTRL_LINK1_XSEL(i, i); 174230b49435SThierry Reding 174330b49435SThierry Reding tegra_sor_writel(sor, 0x00000000, SOR_XBAR_POL); 174430b49435SThierry Reding tegra_sor_writel(sor, value, SOR_XBAR_CTRL); 174530b49435SThierry Reding 174625bb2cecSThierry Reding /* switch to DP parent clock */ 174725bb2cecSThierry Reding err = tegra_sor_set_parent_clock(sor, sor->clk_dp); 17486b6b6042SThierry Reding if (err < 0) 174925bb2cecSThierry Reding dev_err(sor->dev, "failed to set parent clock: %d\n", err); 17506b6b6042SThierry Reding 1751899451b7SThierry Reding /* power DP lanes */ 1752880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->dp_padctl0); 1753899451b7SThierry Reding 1754899451b7SThierry Reding if (link.num_lanes <= 2) 1755899451b7SThierry Reding value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_2); 1756899451b7SThierry Reding else 1757899451b7SThierry Reding value |= SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_2; 1758899451b7SThierry Reding 1759899451b7SThierry Reding if (link.num_lanes <= 1) 1760899451b7SThierry Reding value &= ~SOR_DP_PADCTL_PD_TXD_1; 1761899451b7SThierry Reding else 1762899451b7SThierry Reding value |= SOR_DP_PADCTL_PD_TXD_1; 1763899451b7SThierry Reding 1764899451b7SThierry Reding if (link.num_lanes == 0) 1765899451b7SThierry Reding value &= ~SOR_DP_PADCTL_PD_TXD_0; 1766899451b7SThierry Reding else 1767899451b7SThierry Reding value |= SOR_DP_PADCTL_PD_TXD_0; 1768899451b7SThierry Reding 1769880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->dp_padctl0); 17706b6b6042SThierry Reding 1771a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_LINKCTL0); 17726b6b6042SThierry Reding value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK; 17730c90a184SThierry Reding value |= SOR_DP_LINKCTL_LANE_COUNT(link.num_lanes); 1774a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_LINKCTL0); 17756b6b6042SThierry Reding 17766b6b6042SThierry Reding /* start lane sequencer */ 17776b6b6042SThierry Reding value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_DOWN | 17786b6b6042SThierry Reding SOR_LANE_SEQ_CTL_POWER_STATE_UP; 17796b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL); 17806b6b6042SThierry Reding 17816b6b6042SThierry Reding while (true) { 17826b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL); 17836b6b6042SThierry Reding if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0) 17846b6b6042SThierry Reding break; 17856b6b6042SThierry Reding 17866b6b6042SThierry Reding usleep_range(250, 1000); 17876b6b6042SThierry Reding } 17886b6b6042SThierry Reding 1789a4263fedSThierry Reding /* set link bandwidth */ 17906b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 17916b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; 1792a4263fedSThierry Reding value |= drm_dp_link_rate_to_bw_code(link.rate) << 2; 17936b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 17946b6b6042SThierry Reding 1795402f6bcdSThierry Reding tegra_sor_apply_config(sor, &config); 1796402f6bcdSThierry Reding 1797402f6bcdSThierry Reding /* enable link */ 1798a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_LINKCTL0); 17996b6b6042SThierry Reding value |= SOR_DP_LINKCTL_ENABLE; 18006b6b6042SThierry Reding value |= SOR_DP_LINKCTL_ENHANCED_FRAME; 1801a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_LINKCTL0); 18026b6b6042SThierry Reding 18036b6b6042SThierry Reding for (i = 0, value = 0; i < 4; i++) { 18046b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 18056b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_GALIOS | 18066b6b6042SThierry Reding SOR_DP_TPG_PATTERN_NONE; 18076b6b6042SThierry Reding value = (value << 8) | lane; 18086b6b6042SThierry Reding } 18096b6b6042SThierry Reding 18106b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 18116b6b6042SThierry Reding 18126b6b6042SThierry Reding /* enable pad calibration logic */ 1813880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->dp_padctl0); 18146b6b6042SThierry Reding value |= SOR_DP_PADCTL_PAD_CAL_PD; 1815880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->dp_padctl0); 18166b6b6042SThierry Reding 18179542c237SThierry Reding err = drm_dp_link_probe(sor->aux, &link); 1818850bab44SThierry Reding if (err < 0) 181901b9bea0SThierry Reding dev_err(sor->dev, "failed to probe eDP link: %d\n", err); 18206b6b6042SThierry Reding 18219542c237SThierry Reding err = drm_dp_link_power_up(sor->aux, &link); 1822850bab44SThierry Reding if (err < 0) 182301b9bea0SThierry Reding dev_err(sor->dev, "failed to power up eDP link: %d\n", err); 18246b6b6042SThierry Reding 18259542c237SThierry Reding err = drm_dp_link_configure(sor->aux, &link); 1826850bab44SThierry Reding if (err < 0) 182701b9bea0SThierry Reding dev_err(sor->dev, "failed to configure eDP link: %d\n", err); 18286b6b6042SThierry Reding 18296b6b6042SThierry Reding rate = drm_dp_link_rate_to_bw_code(link.rate); 18306b6b6042SThierry Reding lanes = link.num_lanes; 18316b6b6042SThierry Reding 18326b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 18336b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; 18346b6b6042SThierry Reding value |= SOR_CLK_CNTRL_DP_LINK_SPEED(rate); 18356b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 18366b6b6042SThierry Reding 1837a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_LINKCTL0); 18386b6b6042SThierry Reding value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK; 18396b6b6042SThierry Reding value |= SOR_DP_LINKCTL_LANE_COUNT(lanes); 18406b6b6042SThierry Reding 18416b6b6042SThierry Reding if (link.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) 18426b6b6042SThierry Reding value |= SOR_DP_LINKCTL_ENHANCED_FRAME; 18436b6b6042SThierry Reding 1844a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_LINKCTL0); 18456b6b6042SThierry Reding 18466b6b6042SThierry Reding /* disable training pattern generator */ 18476b6b6042SThierry Reding 18486b6b6042SThierry Reding for (i = 0; i < link.num_lanes; i++) { 18496b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 18506b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_GALIOS | 18516b6b6042SThierry Reding SOR_DP_TPG_PATTERN_NONE; 18526b6b6042SThierry Reding value = (value << 8) | lane; 18536b6b6042SThierry Reding } 18546b6b6042SThierry Reding 18556b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 18566b6b6042SThierry Reding 18576b6b6042SThierry Reding err = tegra_sor_dp_train_fast(sor, &link); 185801b9bea0SThierry Reding if (err < 0) 185901b9bea0SThierry Reding dev_err(sor->dev, "DP fast link training failed: %d\n", err); 18606b6b6042SThierry Reding 18616b6b6042SThierry Reding dev_dbg(sor->dev, "fast link training succeeded\n"); 18626b6b6042SThierry Reding 18636b6b6042SThierry Reding err = tegra_sor_power_up(sor, 250); 1864850bab44SThierry Reding if (err < 0) 18656b6b6042SThierry Reding dev_err(sor->dev, "failed to power up SOR: %d\n", err); 18666b6b6042SThierry Reding 18676b6b6042SThierry Reding /* CSTM (LVDS, link A/B, upper) */ 1868143b1df2SStéphane Marchesin value = SOR_CSTM_LVDS | SOR_CSTM_LINK_ACT_A | SOR_CSTM_LINK_ACT_B | 18696b6b6042SThierry Reding SOR_CSTM_UPPER; 18706b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CSTM); 18716b6b6042SThierry Reding 18722bd1dd39SThierry Reding /* use DP-A protocol */ 18732bd1dd39SThierry Reding value = tegra_sor_readl(sor, SOR_STATE1); 18742bd1dd39SThierry Reding value &= ~SOR_STATE_ASY_PROTOCOL_MASK; 18752bd1dd39SThierry Reding value |= SOR_STATE_ASY_PROTOCOL_DP_A; 18762bd1dd39SThierry Reding tegra_sor_writel(sor, value, SOR_STATE1); 18772bd1dd39SThierry Reding 1878c31efa7aSThierry Reding tegra_sor_mode_set(sor, mode, state); 18792bd1dd39SThierry Reding 18806b6b6042SThierry Reding /* PWM setup */ 18816b6b6042SThierry Reding err = tegra_sor_setup_pwm(sor, 250); 1882850bab44SThierry Reding if (err < 0) 18836b6b6042SThierry Reding dev_err(sor->dev, "failed to setup PWM: %d\n", err); 18846b6b6042SThierry Reding 1885666cb873SThierry Reding tegra_sor_update(sor); 1886666cb873SThierry Reding 18876b6b6042SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 1888*c57997bcSThierry Reding value |= SOR_ENABLE(0); 18896b6b6042SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 18906b6b6042SThierry Reding 1891666cb873SThierry Reding tegra_dc_commit(dc); 18926b6b6042SThierry Reding 18936b6b6042SThierry Reding err = tegra_sor_attach(sor); 1894850bab44SThierry Reding if (err < 0) 18956b6b6042SThierry Reding dev_err(sor->dev, "failed to attach SOR: %d\n", err); 18966b6b6042SThierry Reding 18976b6b6042SThierry Reding err = tegra_sor_wakeup(sor); 1898850bab44SThierry Reding if (err < 0) 18996b6b6042SThierry Reding dev_err(sor->dev, "failed to enable DC: %d\n", err); 19006b6b6042SThierry Reding 19016fad8f66SThierry Reding if (output->panel) 19026fad8f66SThierry Reding drm_panel_enable(output->panel); 19036b6b6042SThierry Reding } 19046b6b6042SThierry Reding 190582f1511cSThierry Reding static int 190682f1511cSThierry Reding tegra_sor_encoder_atomic_check(struct drm_encoder *encoder, 190782f1511cSThierry Reding struct drm_crtc_state *crtc_state, 190882f1511cSThierry Reding struct drm_connector_state *conn_state) 190982f1511cSThierry Reding { 191082f1511cSThierry Reding struct tegra_output *output = encoder_to_output(encoder); 1911c31efa7aSThierry Reding struct tegra_sor_state *state = to_sor_state(conn_state); 191282f1511cSThierry Reding struct tegra_dc *dc = to_tegra_dc(conn_state->crtc); 191382f1511cSThierry Reding unsigned long pclk = crtc_state->mode.clock * 1000; 191482f1511cSThierry Reding struct tegra_sor *sor = to_sor(output); 1915c31efa7aSThierry Reding struct drm_display_info *info; 191682f1511cSThierry Reding int err; 191782f1511cSThierry Reding 1918c31efa7aSThierry Reding info = &output->connector.display_info; 1919c31efa7aSThierry Reding 192082f1511cSThierry Reding err = tegra_dc_state_setup_clock(dc, crtc_state, sor->clk_parent, 192182f1511cSThierry Reding pclk, 0); 192282f1511cSThierry Reding if (err < 0) { 192382f1511cSThierry Reding dev_err(output->dev, "failed to setup CRTC state: %d\n", err); 192482f1511cSThierry Reding return err; 192582f1511cSThierry Reding } 192682f1511cSThierry Reding 1927c31efa7aSThierry Reding switch (info->bpc) { 1928c31efa7aSThierry Reding case 8: 1929c31efa7aSThierry Reding case 6: 1930c31efa7aSThierry Reding state->bpc = info->bpc; 1931c31efa7aSThierry Reding break; 1932c31efa7aSThierry Reding 1933c31efa7aSThierry Reding default: 1934c31efa7aSThierry Reding DRM_DEBUG_KMS("%u bits-per-color not supported\n", info->bpc); 1935c31efa7aSThierry Reding state->bpc = 8; 1936c31efa7aSThierry Reding break; 1937c31efa7aSThierry Reding } 1938c31efa7aSThierry Reding 193982f1511cSThierry Reding return 0; 194082f1511cSThierry Reding } 194182f1511cSThierry Reding 1942459cc2c6SThierry Reding static const struct drm_encoder_helper_funcs tegra_sor_edp_helpers = { 1943850bab44SThierry Reding .disable = tegra_sor_edp_disable, 1944850bab44SThierry Reding .enable = tegra_sor_edp_enable, 194582f1511cSThierry Reding .atomic_check = tegra_sor_encoder_atomic_check, 19466b6b6042SThierry Reding }; 19476b6b6042SThierry Reding 1948459cc2c6SThierry Reding static inline u32 tegra_sor_hdmi_subpack(const u8 *ptr, size_t size) 1949459cc2c6SThierry Reding { 1950459cc2c6SThierry Reding u32 value = 0; 1951459cc2c6SThierry Reding size_t i; 1952459cc2c6SThierry Reding 1953459cc2c6SThierry Reding for (i = size; i > 0; i--) 1954459cc2c6SThierry Reding value = (value << 8) | ptr[i - 1]; 1955459cc2c6SThierry Reding 1956459cc2c6SThierry Reding return value; 1957459cc2c6SThierry Reding } 1958459cc2c6SThierry Reding 1959459cc2c6SThierry Reding static void tegra_sor_hdmi_write_infopack(struct tegra_sor *sor, 1960459cc2c6SThierry Reding const void *data, size_t size) 1961459cc2c6SThierry Reding { 1962459cc2c6SThierry Reding const u8 *ptr = data; 1963459cc2c6SThierry Reding unsigned long offset; 1964459cc2c6SThierry Reding size_t i, j; 1965459cc2c6SThierry Reding u32 value; 1966459cc2c6SThierry Reding 1967459cc2c6SThierry Reding switch (ptr[0]) { 1968459cc2c6SThierry Reding case HDMI_INFOFRAME_TYPE_AVI: 1969459cc2c6SThierry Reding offset = SOR_HDMI_AVI_INFOFRAME_HEADER; 1970459cc2c6SThierry Reding break; 1971459cc2c6SThierry Reding 1972459cc2c6SThierry Reding case HDMI_INFOFRAME_TYPE_AUDIO: 1973459cc2c6SThierry Reding offset = SOR_HDMI_AUDIO_INFOFRAME_HEADER; 1974459cc2c6SThierry Reding break; 1975459cc2c6SThierry Reding 1976459cc2c6SThierry Reding case HDMI_INFOFRAME_TYPE_VENDOR: 1977459cc2c6SThierry Reding offset = SOR_HDMI_VSI_INFOFRAME_HEADER; 1978459cc2c6SThierry Reding break; 1979459cc2c6SThierry Reding 1980459cc2c6SThierry Reding default: 1981459cc2c6SThierry Reding dev_err(sor->dev, "unsupported infoframe type: %02x\n", 1982459cc2c6SThierry Reding ptr[0]); 1983459cc2c6SThierry Reding return; 1984459cc2c6SThierry Reding } 1985459cc2c6SThierry Reding 1986459cc2c6SThierry Reding value = INFOFRAME_HEADER_TYPE(ptr[0]) | 1987459cc2c6SThierry Reding INFOFRAME_HEADER_VERSION(ptr[1]) | 1988459cc2c6SThierry Reding INFOFRAME_HEADER_LEN(ptr[2]); 1989459cc2c6SThierry Reding tegra_sor_writel(sor, value, offset); 1990459cc2c6SThierry Reding offset++; 1991459cc2c6SThierry Reding 1992459cc2c6SThierry Reding /* 1993459cc2c6SThierry Reding * Each subpack contains 7 bytes, divided into: 1994459cc2c6SThierry Reding * - subpack_low: bytes 0 - 3 1995459cc2c6SThierry Reding * - subpack_high: bytes 4 - 6 (with byte 7 padded to 0x00) 1996459cc2c6SThierry Reding */ 1997459cc2c6SThierry Reding for (i = 3, j = 0; i < size; i += 7, j += 8) { 1998459cc2c6SThierry Reding size_t rem = size - i, num = min_t(size_t, rem, 4); 1999459cc2c6SThierry Reding 2000459cc2c6SThierry Reding value = tegra_sor_hdmi_subpack(&ptr[i], num); 2001459cc2c6SThierry Reding tegra_sor_writel(sor, value, offset++); 2002459cc2c6SThierry Reding 2003459cc2c6SThierry Reding num = min_t(size_t, rem - num, 3); 2004459cc2c6SThierry Reding 2005459cc2c6SThierry Reding value = tegra_sor_hdmi_subpack(&ptr[i + 4], num); 2006459cc2c6SThierry Reding tegra_sor_writel(sor, value, offset++); 2007459cc2c6SThierry Reding } 2008459cc2c6SThierry Reding } 2009459cc2c6SThierry Reding 2010459cc2c6SThierry Reding static int 2011459cc2c6SThierry Reding tegra_sor_hdmi_setup_avi_infoframe(struct tegra_sor *sor, 2012459cc2c6SThierry Reding const struct drm_display_mode *mode) 2013459cc2c6SThierry Reding { 2014459cc2c6SThierry Reding u8 buffer[HDMI_INFOFRAME_SIZE(AVI)]; 2015459cc2c6SThierry Reding struct hdmi_avi_infoframe frame; 2016459cc2c6SThierry Reding u32 value; 2017459cc2c6SThierry Reding int err; 2018459cc2c6SThierry Reding 2019459cc2c6SThierry Reding /* disable AVI infoframe */ 2020459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_HDMI_AVI_INFOFRAME_CTRL); 2021459cc2c6SThierry Reding value &= ~INFOFRAME_CTRL_SINGLE; 2022459cc2c6SThierry Reding value &= ~INFOFRAME_CTRL_OTHER; 2023459cc2c6SThierry Reding value &= ~INFOFRAME_CTRL_ENABLE; 2024459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_HDMI_AVI_INFOFRAME_CTRL); 2025459cc2c6SThierry Reding 20260c1f528cSShashank Sharma err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); 2027459cc2c6SThierry Reding if (err < 0) { 2028459cc2c6SThierry Reding dev_err(sor->dev, "failed to setup AVI infoframe: %d\n", err); 2029459cc2c6SThierry Reding return err; 2030459cc2c6SThierry Reding } 2031459cc2c6SThierry Reding 2032459cc2c6SThierry Reding err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); 2033459cc2c6SThierry Reding if (err < 0) { 2034459cc2c6SThierry Reding dev_err(sor->dev, "failed to pack AVI infoframe: %d\n", err); 2035459cc2c6SThierry Reding return err; 2036459cc2c6SThierry Reding } 2037459cc2c6SThierry Reding 2038459cc2c6SThierry Reding tegra_sor_hdmi_write_infopack(sor, buffer, err); 2039459cc2c6SThierry Reding 2040459cc2c6SThierry Reding /* enable AVI infoframe */ 2041459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_HDMI_AVI_INFOFRAME_CTRL); 2042459cc2c6SThierry Reding value |= INFOFRAME_CTRL_CHECKSUM_ENABLE; 2043459cc2c6SThierry Reding value |= INFOFRAME_CTRL_ENABLE; 2044459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_HDMI_AVI_INFOFRAME_CTRL); 2045459cc2c6SThierry Reding 2046459cc2c6SThierry Reding return 0; 2047459cc2c6SThierry Reding } 2048459cc2c6SThierry Reding 2049459cc2c6SThierry Reding static void tegra_sor_hdmi_disable_audio_infoframe(struct tegra_sor *sor) 2050459cc2c6SThierry Reding { 2051459cc2c6SThierry Reding u32 value; 2052459cc2c6SThierry Reding 2053459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_HDMI_AUDIO_INFOFRAME_CTRL); 2054459cc2c6SThierry Reding value &= ~INFOFRAME_CTRL_ENABLE; 2055459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_HDMI_AUDIO_INFOFRAME_CTRL); 2056459cc2c6SThierry Reding } 2057459cc2c6SThierry Reding 2058459cc2c6SThierry Reding static struct tegra_sor_hdmi_settings * 2059459cc2c6SThierry Reding tegra_sor_hdmi_find_settings(struct tegra_sor *sor, unsigned long frequency) 2060459cc2c6SThierry Reding { 2061459cc2c6SThierry Reding unsigned int i; 2062459cc2c6SThierry Reding 2063459cc2c6SThierry Reding for (i = 0; i < sor->num_settings; i++) 2064459cc2c6SThierry Reding if (frequency <= sor->settings[i].frequency) 2065459cc2c6SThierry Reding return &sor->settings[i]; 2066459cc2c6SThierry Reding 2067459cc2c6SThierry Reding return NULL; 2068459cc2c6SThierry Reding } 2069459cc2c6SThierry Reding 2070459cc2c6SThierry Reding static void tegra_sor_hdmi_disable(struct drm_encoder *encoder) 2071459cc2c6SThierry Reding { 2072459cc2c6SThierry Reding struct tegra_output *output = encoder_to_output(encoder); 2073459cc2c6SThierry Reding struct tegra_dc *dc = to_tegra_dc(encoder->crtc); 2074459cc2c6SThierry Reding struct tegra_sor *sor = to_sor(output); 2075459cc2c6SThierry Reding u32 value; 2076459cc2c6SThierry Reding int err; 2077459cc2c6SThierry Reding 2078459cc2c6SThierry Reding err = tegra_sor_detach(sor); 2079459cc2c6SThierry Reding if (err < 0) 2080459cc2c6SThierry Reding dev_err(sor->dev, "failed to detach SOR: %d\n", err); 2081459cc2c6SThierry Reding 2082459cc2c6SThierry Reding tegra_sor_writel(sor, 0, SOR_STATE1); 2083459cc2c6SThierry Reding tegra_sor_update(sor); 2084459cc2c6SThierry Reding 2085459cc2c6SThierry Reding /* disable display to SOR clock */ 2086459cc2c6SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 2087*c57997bcSThierry Reding 2088*c57997bcSThierry Reding if (!sor->soc->has_nvdisplay) 2089*c57997bcSThierry Reding value &= ~(SOR1_TIMING_CYA | SOR_ENABLE(1)); 2090*c57997bcSThierry Reding else 2091*c57997bcSThierry Reding value &= ~SOR_ENABLE(sor->index); 2092*c57997bcSThierry Reding 2093459cc2c6SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 2094459cc2c6SThierry Reding 2095459cc2c6SThierry Reding tegra_dc_commit(dc); 2096459cc2c6SThierry Reding 2097459cc2c6SThierry Reding err = tegra_sor_power_down(sor); 2098459cc2c6SThierry Reding if (err < 0) 2099459cc2c6SThierry Reding dev_err(sor->dev, "failed to power down SOR: %d\n", err); 2100459cc2c6SThierry Reding 2101*c57997bcSThierry Reding err = tegra_io_pad_power_disable(sor->pad); 2102459cc2c6SThierry Reding if (err < 0) 2103*c57997bcSThierry Reding dev_err(sor->dev, "failed to power off I/O pad: %d\n", err); 2104459cc2c6SThierry Reding 2105aaff8bd2SThierry Reding pm_runtime_put(sor->dev); 2106459cc2c6SThierry Reding } 2107459cc2c6SThierry Reding 2108459cc2c6SThierry Reding static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) 2109459cc2c6SThierry Reding { 2110459cc2c6SThierry Reding struct tegra_output *output = encoder_to_output(encoder); 2111459cc2c6SThierry Reding unsigned int h_ref_to_sync = 1, pulse_start, max_ac; 2112459cc2c6SThierry Reding struct tegra_dc *dc = to_tegra_dc(encoder->crtc); 2113459cc2c6SThierry Reding struct tegra_sor_hdmi_settings *settings; 2114459cc2c6SThierry Reding struct tegra_sor *sor = to_sor(output); 2115c31efa7aSThierry Reding struct tegra_sor_state *state; 2116459cc2c6SThierry Reding struct drm_display_mode *mode; 211730b49435SThierry Reding unsigned int div, i; 2118459cc2c6SThierry Reding u32 value; 2119459cc2c6SThierry Reding int err; 2120459cc2c6SThierry Reding 2121c31efa7aSThierry Reding state = to_sor_state(output->connector.state); 2122459cc2c6SThierry Reding mode = &encoder->crtc->state->adjusted_mode; 2123459cc2c6SThierry Reding 2124aaff8bd2SThierry Reding pm_runtime_get_sync(sor->dev); 2125459cc2c6SThierry Reding 212625bb2cecSThierry Reding /* switch to safe parent clock */ 212725bb2cecSThierry Reding err = tegra_sor_set_parent_clock(sor, sor->clk_safe); 2128e1335e2fSThierry Reding if (err < 0) { 2129459cc2c6SThierry Reding dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); 2130e1335e2fSThierry Reding return; 2131e1335e2fSThierry Reding } 2132459cc2c6SThierry Reding 2133459cc2c6SThierry Reding div = clk_get_rate(sor->clk) / 1000000 * 4; 2134459cc2c6SThierry Reding 2135*c57997bcSThierry Reding err = tegra_io_pad_power_enable(sor->pad); 2136459cc2c6SThierry Reding if (err < 0) 2137*c57997bcSThierry Reding dev_err(sor->dev, "failed to power on I/O pad: %d\n", err); 2138459cc2c6SThierry Reding 2139459cc2c6SThierry Reding usleep_range(20, 100); 2140459cc2c6SThierry Reding 2141880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll2); 2142459cc2c6SThierry Reding value &= ~SOR_PLL2_BANDGAP_POWERDOWN; 2143880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll2); 2144459cc2c6SThierry Reding 2145459cc2c6SThierry Reding usleep_range(20, 100); 2146459cc2c6SThierry Reding 2147880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll3); 2148459cc2c6SThierry Reding value &= ~SOR_PLL3_PLL_VDD_MODE_3V3; 2149880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll3); 2150459cc2c6SThierry Reding 2151880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll0); 2152459cc2c6SThierry Reding value &= ~SOR_PLL0_VCOPD; 2153459cc2c6SThierry Reding value &= ~SOR_PLL0_PWR; 2154880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll0); 2155459cc2c6SThierry Reding 2156880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll2); 2157459cc2c6SThierry Reding value &= ~SOR_PLL2_SEQ_PLLCAPPD_ENFORCE; 2158880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll2); 2159459cc2c6SThierry Reding 2160459cc2c6SThierry Reding usleep_range(200, 400); 2161459cc2c6SThierry Reding 2162880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll2); 2163459cc2c6SThierry Reding value &= ~SOR_PLL2_POWERDOWN_OVERRIDE; 2164459cc2c6SThierry Reding value &= ~SOR_PLL2_PORT_POWERDOWN; 2165880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll2); 2166459cc2c6SThierry Reding 2167459cc2c6SThierry Reding usleep_range(20, 100); 2168459cc2c6SThierry Reding 2169880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->dp_padctl0); 2170459cc2c6SThierry Reding value |= SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 | 2171459cc2c6SThierry Reding SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2; 2172880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->dp_padctl0); 2173459cc2c6SThierry Reding 2174459cc2c6SThierry Reding while (true) { 2175459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL); 2176459cc2c6SThierry Reding if ((value & SOR_LANE_SEQ_CTL_STATE_BUSY) == 0) 2177459cc2c6SThierry Reding break; 2178459cc2c6SThierry Reding 2179459cc2c6SThierry Reding usleep_range(250, 1000); 2180459cc2c6SThierry Reding } 2181459cc2c6SThierry Reding 2182459cc2c6SThierry Reding value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_DOWN | 2183459cc2c6SThierry Reding SOR_LANE_SEQ_CTL_POWER_STATE_UP | SOR_LANE_SEQ_CTL_DELAY(5); 2184459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL); 2185459cc2c6SThierry Reding 2186459cc2c6SThierry Reding while (true) { 2187459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL); 2188459cc2c6SThierry Reding if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0) 2189459cc2c6SThierry Reding break; 2190459cc2c6SThierry Reding 2191459cc2c6SThierry Reding usleep_range(250, 1000); 2192459cc2c6SThierry Reding } 2193459cc2c6SThierry Reding 2194459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 2195459cc2c6SThierry Reding value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; 2196459cc2c6SThierry Reding value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; 2197459cc2c6SThierry Reding 2198459cc2c6SThierry Reding if (mode->clock < 340000) 2199459cc2c6SThierry Reding value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G2_70; 2200459cc2c6SThierry Reding else 2201459cc2c6SThierry Reding value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G5_40; 2202459cc2c6SThierry Reding 2203459cc2c6SThierry Reding value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK; 2204459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 2205459cc2c6SThierry Reding 2206*c57997bcSThierry Reding /* SOR pad PLL stabilization time */ 2207*c57997bcSThierry Reding usleep_range(250, 1000); 2208*c57997bcSThierry Reding 2209*c57997bcSThierry Reding value = tegra_sor_readl(sor, SOR_DP_LINKCTL0); 2210*c57997bcSThierry Reding value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK; 2211*c57997bcSThierry Reding value |= SOR_DP_LINKCTL_LANE_COUNT(4); 2212*c57997bcSThierry Reding tegra_sor_writel(sor, value, SOR_DP_LINKCTL0); 2213*c57997bcSThierry Reding 2214459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_DP_SPARE0); 2215*c57997bcSThierry Reding value &= ~SOR_DP_SPARE_DISP_VIDEO_PREAMBLE; 2216459cc2c6SThierry Reding value &= ~SOR_DP_SPARE_PANEL_INTERNAL; 2217*c57997bcSThierry Reding value &= ~SOR_DP_SPARE_SEQ_ENABLE; 2218*c57997bcSThierry Reding value &= ~SOR_DP_SPARE_MACRO_SOR_CLK; 2219459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_DP_SPARE0); 2220459cc2c6SThierry Reding 2221459cc2c6SThierry Reding value = SOR_SEQ_CTL_PU_PC(0) | SOR_SEQ_CTL_PU_PC_ALT(0) | 2222459cc2c6SThierry Reding SOR_SEQ_CTL_PD_PC(8) | SOR_SEQ_CTL_PD_PC_ALT(8); 2223459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_SEQ_CTL); 2224459cc2c6SThierry Reding 2225459cc2c6SThierry Reding value = SOR_SEQ_INST_DRIVE_PWM_OUT_LO | SOR_SEQ_INST_HALT | 2226459cc2c6SThierry Reding SOR_SEQ_INST_WAIT_VSYNC | SOR_SEQ_INST_WAIT(1); 2227459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_SEQ_INST(0)); 2228459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_SEQ_INST(8)); 2229459cc2c6SThierry Reding 2230*c57997bcSThierry Reding if (!sor->soc->has_nvdisplay) { 2231459cc2c6SThierry Reding /* program the reference clock */ 2232459cc2c6SThierry Reding value = SOR_REFCLK_DIV_INT(div) | SOR_REFCLK_DIV_FRAC(div); 2233459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_REFCLK); 2234*c57997bcSThierry Reding } 2235459cc2c6SThierry Reding 223630b49435SThierry Reding /* XXX not in TRM */ 223730b49435SThierry Reding for (value = 0, i = 0; i < 5; i++) 223830b49435SThierry Reding value |= SOR_XBAR_CTRL_LINK0_XSEL(i, sor->soc->xbar_cfg[i]) | 223930b49435SThierry Reding SOR_XBAR_CTRL_LINK1_XSEL(i, i); 2240459cc2c6SThierry Reding 2241459cc2c6SThierry Reding tegra_sor_writel(sor, 0x00000000, SOR_XBAR_POL); 224230b49435SThierry Reding tegra_sor_writel(sor, value, SOR_XBAR_CTRL); 2243459cc2c6SThierry Reding 224425bb2cecSThierry Reding /* switch to parent clock */ 2245e1335e2fSThierry Reding err = clk_set_parent(sor->clk, sor->clk_parent); 2246e1335e2fSThierry Reding if (err < 0) { 2247459cc2c6SThierry Reding dev_err(sor->dev, "failed to set parent clock: %d\n", err); 2248e1335e2fSThierry Reding return; 2249e1335e2fSThierry Reding } 2250e1335e2fSThierry Reding 2251e1335e2fSThierry Reding err = tegra_sor_set_parent_clock(sor, sor->clk_pad); 2252e1335e2fSThierry Reding if (err < 0) { 2253e1335e2fSThierry Reding dev_err(sor->dev, "failed to set pad clock: %d\n", err); 2254e1335e2fSThierry Reding return; 2255e1335e2fSThierry Reding } 2256459cc2c6SThierry Reding 2257*c57997bcSThierry Reding 2258*c57997bcSThierry Reding if (!sor->soc->has_nvdisplay) { 2259459cc2c6SThierry Reding value = SOR_INPUT_CONTROL_HDMI_SRC_SELECT(dc->pipe); 2260459cc2c6SThierry Reding 2261459cc2c6SThierry Reding /* XXX is this the proper check? */ 2262459cc2c6SThierry Reding if (mode->clock < 75000) 2263459cc2c6SThierry Reding value |= SOR_INPUT_CONTROL_ARM_VIDEO_RANGE_LIMITED; 2264459cc2c6SThierry Reding 2265459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_INPUT_CONTROL); 2266*c57997bcSThierry Reding } 2267459cc2c6SThierry Reding 2268459cc2c6SThierry Reding max_ac = ((mode->htotal - mode->hdisplay) - SOR_REKEY - 18) / 32; 2269459cc2c6SThierry Reding 2270459cc2c6SThierry Reding value = SOR_HDMI_CTRL_ENABLE | SOR_HDMI_CTRL_MAX_AC_PACKET(max_ac) | 2271459cc2c6SThierry Reding SOR_HDMI_CTRL_AUDIO_LAYOUT | SOR_HDMI_CTRL_REKEY(SOR_REKEY); 2272459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_HDMI_CTRL); 2273459cc2c6SThierry Reding 2274*c57997bcSThierry Reding if (!dc->soc->has_nvdisplay) { 2275459cc2c6SThierry Reding /* H_PULSE2 setup */ 2276*c57997bcSThierry Reding pulse_start = h_ref_to_sync + 2277*c57997bcSThierry Reding (mode->hsync_end - mode->hsync_start) + 2278459cc2c6SThierry Reding (mode->htotal - mode->hsync_end) - 10; 2279459cc2c6SThierry Reding 2280459cc2c6SThierry Reding value = PULSE_LAST_END_A | PULSE_QUAL_VACTIVE | 2281459cc2c6SThierry Reding PULSE_POLARITY_HIGH | PULSE_MODE_NORMAL; 2282459cc2c6SThierry Reding tegra_dc_writel(dc, value, DC_DISP_H_PULSE2_CONTROL); 2283459cc2c6SThierry Reding 2284459cc2c6SThierry Reding value = PULSE_END(pulse_start + 8) | PULSE_START(pulse_start); 2285459cc2c6SThierry Reding tegra_dc_writel(dc, value, DC_DISP_H_PULSE2_POSITION_A); 2286459cc2c6SThierry Reding 2287459cc2c6SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_SIGNAL_OPTIONS0); 2288459cc2c6SThierry Reding value |= H_PULSE2_ENABLE; 2289459cc2c6SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_SIGNAL_OPTIONS0); 2290*c57997bcSThierry Reding } 2291459cc2c6SThierry Reding 2292459cc2c6SThierry Reding /* infoframe setup */ 2293459cc2c6SThierry Reding err = tegra_sor_hdmi_setup_avi_infoframe(sor, mode); 2294459cc2c6SThierry Reding if (err < 0) 2295459cc2c6SThierry Reding dev_err(sor->dev, "failed to setup AVI infoframe: %d\n", err); 2296459cc2c6SThierry Reding 2297459cc2c6SThierry Reding /* XXX HDMI audio support not implemented yet */ 2298459cc2c6SThierry Reding tegra_sor_hdmi_disable_audio_infoframe(sor); 2299459cc2c6SThierry Reding 2300459cc2c6SThierry Reding /* use single TMDS protocol */ 2301459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_STATE1); 2302459cc2c6SThierry Reding value &= ~SOR_STATE_ASY_PROTOCOL_MASK; 2303459cc2c6SThierry Reding value |= SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A; 2304459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_STATE1); 2305459cc2c6SThierry Reding 2306459cc2c6SThierry Reding /* power up pad calibration */ 2307880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->dp_padctl0); 2308459cc2c6SThierry Reding value &= ~SOR_DP_PADCTL_PAD_CAL_PD; 2309880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->dp_padctl0); 2310459cc2c6SThierry Reding 2311459cc2c6SThierry Reding /* production settings */ 2312459cc2c6SThierry Reding settings = tegra_sor_hdmi_find_settings(sor, mode->clock * 1000); 2313db8b42fbSDan Carpenter if (!settings) { 2314db8b42fbSDan Carpenter dev_err(sor->dev, "no settings for pixel clock %d Hz\n", 2315db8b42fbSDan Carpenter mode->clock * 1000); 2316459cc2c6SThierry Reding return; 2317459cc2c6SThierry Reding } 2318459cc2c6SThierry Reding 2319880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll0); 2320459cc2c6SThierry Reding value &= ~SOR_PLL0_ICHPMP_MASK; 2321*c57997bcSThierry Reding value &= ~SOR_PLL0_FILTER_MASK; 2322459cc2c6SThierry Reding value &= ~SOR_PLL0_VCOCAP_MASK; 2323459cc2c6SThierry Reding value |= SOR_PLL0_ICHPMP(settings->ichpmp); 2324*c57997bcSThierry Reding value |= SOR_PLL0_FILTER(settings->filter); 2325459cc2c6SThierry Reding value |= SOR_PLL0_VCOCAP(settings->vcocap); 2326880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll0); 2327459cc2c6SThierry Reding 2328*c57997bcSThierry Reding /* XXX not in TRM */ 2329880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll1); 2330459cc2c6SThierry Reding value &= ~SOR_PLL1_LOADADJ_MASK; 2331*c57997bcSThierry Reding value &= ~SOR_PLL1_TMDS_TERMADJ_MASK; 2332459cc2c6SThierry Reding value |= SOR_PLL1_LOADADJ(settings->loadadj); 2333*c57997bcSThierry Reding value |= SOR_PLL1_TMDS_TERMADJ(settings->tmds_termadj); 2334*c57997bcSThierry Reding value |= SOR_PLL1_TMDS_TERM; 2335880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll1); 2336459cc2c6SThierry Reding 2337880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->pll3); 2338*c57997bcSThierry Reding value &= ~SOR_PLL3_BG_TEMP_COEF_MASK; 2339459cc2c6SThierry Reding value &= ~SOR_PLL3_BG_VREF_LEVEL_MASK; 2340*c57997bcSThierry Reding value &= ~SOR_PLL3_AVDD10_LEVEL_MASK; 2341*c57997bcSThierry Reding value &= ~SOR_PLL3_AVDD14_LEVEL_MASK; 2342*c57997bcSThierry Reding value |= SOR_PLL3_BG_TEMP_COEF(settings->bg_temp_coef); 2343*c57997bcSThierry Reding value |= SOR_PLL3_BG_VREF_LEVEL(settings->bg_vref_level); 2344*c57997bcSThierry Reding value |= SOR_PLL3_AVDD10_LEVEL(settings->avdd10_level); 2345*c57997bcSThierry Reding value |= SOR_PLL3_AVDD14_LEVEL(settings->avdd14_level); 2346880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->pll3); 2347459cc2c6SThierry Reding 2348*c57997bcSThierry Reding value = settings->drive_current[3] << 24 | 2349*c57997bcSThierry Reding settings->drive_current[2] << 16 | 2350*c57997bcSThierry Reding settings->drive_current[1] << 8 | 2351*c57997bcSThierry Reding settings->drive_current[0] << 0; 2352459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_DRIVE_CURRENT0); 2353459cc2c6SThierry Reding 2354*c57997bcSThierry Reding value = settings->preemphasis[3] << 24 | 2355*c57997bcSThierry Reding settings->preemphasis[2] << 16 | 2356*c57997bcSThierry Reding settings->preemphasis[1] << 8 | 2357*c57997bcSThierry Reding settings->preemphasis[0] << 0; 2358459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_PREEMPHASIS0); 2359459cc2c6SThierry Reding 2360880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->dp_padctl0); 2361459cc2c6SThierry Reding value &= ~SOR_DP_PADCTL_TX_PU_MASK; 2362459cc2c6SThierry Reding value |= SOR_DP_PADCTL_TX_PU_ENABLE; 2363*c57997bcSThierry Reding value |= SOR_DP_PADCTL_TX_PU(settings->tx_pu_value); 2364880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->dp_padctl0); 2365459cc2c6SThierry Reding 2366*c57997bcSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->dp_padctl2); 2367*c57997bcSThierry Reding value &= ~SOR_DP_PADCTL_SPAREPLL_MASK; 2368*c57997bcSThierry Reding value |= SOR_DP_PADCTL_SPAREPLL(settings->sparepll); 2369*c57997bcSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->dp_padctl2); 2370*c57997bcSThierry Reding 2371459cc2c6SThierry Reding /* power down pad calibration */ 2372880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->dp_padctl0); 2373459cc2c6SThierry Reding value |= SOR_DP_PADCTL_PAD_CAL_PD; 2374880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->dp_padctl0); 2375459cc2c6SThierry Reding 2376*c57997bcSThierry Reding if (!dc->soc->has_nvdisplay) { 2377459cc2c6SThierry Reding /* miscellaneous display controller settings */ 2378459cc2c6SThierry Reding value = VSYNC_H_POSITION(1); 2379459cc2c6SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_TIMING_OPTIONS); 2380*c57997bcSThierry Reding } 2381459cc2c6SThierry Reding 2382459cc2c6SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_COLOR_CONTROL); 2383459cc2c6SThierry Reding value &= ~DITHER_CONTROL_MASK; 2384459cc2c6SThierry Reding value &= ~BASE_COLOR_SIZE_MASK; 2385459cc2c6SThierry Reding 2386c31efa7aSThierry Reding switch (state->bpc) { 2387459cc2c6SThierry Reding case 6: 2388459cc2c6SThierry Reding value |= BASE_COLOR_SIZE_666; 2389459cc2c6SThierry Reding break; 2390459cc2c6SThierry Reding 2391459cc2c6SThierry Reding case 8: 2392459cc2c6SThierry Reding value |= BASE_COLOR_SIZE_888; 2393459cc2c6SThierry Reding break; 2394459cc2c6SThierry Reding 2395*c57997bcSThierry Reding case 10: 2396*c57997bcSThierry Reding value |= BASE_COLOR_SIZE_101010; 2397*c57997bcSThierry Reding break; 2398*c57997bcSThierry Reding 2399*c57997bcSThierry Reding case 12: 2400*c57997bcSThierry Reding value |= BASE_COLOR_SIZE_121212; 2401*c57997bcSThierry Reding break; 2402*c57997bcSThierry Reding 2403459cc2c6SThierry Reding default: 2404c31efa7aSThierry Reding WARN(1, "%u bits-per-color not supported\n", state->bpc); 2405c31efa7aSThierry Reding value |= BASE_COLOR_SIZE_888; 2406459cc2c6SThierry Reding break; 2407459cc2c6SThierry Reding } 2408459cc2c6SThierry Reding 2409459cc2c6SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_COLOR_CONTROL); 2410459cc2c6SThierry Reding 2411*c57997bcSThierry Reding /* XXX set display head owner */ 2412*c57997bcSThierry Reding value = tegra_sor_readl(sor, SOR_STATE1); 2413*c57997bcSThierry Reding value &= ~SOR_STATE_ASY_OWNER_MASK; 2414*c57997bcSThierry Reding value |= SOR_STATE_ASY_OWNER(1 + dc->pipe); 2415*c57997bcSThierry Reding tegra_sor_writel(sor, value, SOR_STATE1); 2416*c57997bcSThierry Reding 2417459cc2c6SThierry Reding err = tegra_sor_power_up(sor, 250); 2418459cc2c6SThierry Reding if (err < 0) 2419459cc2c6SThierry Reding dev_err(sor->dev, "failed to power up SOR: %d\n", err); 2420459cc2c6SThierry Reding 24212bd1dd39SThierry Reding /* configure dynamic range of output */ 2422880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->head_state0 + dc->pipe); 2423459cc2c6SThierry Reding value &= ~SOR_HEAD_STATE_RANGECOMPRESS_MASK; 2424459cc2c6SThierry Reding value &= ~SOR_HEAD_STATE_DYNRANGE_MASK; 2425880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->head_state0 + dc->pipe); 2426459cc2c6SThierry Reding 24272bd1dd39SThierry Reding /* configure colorspace */ 2428880cee0bSThierry Reding value = tegra_sor_readl(sor, sor->soc->regs->head_state0 + dc->pipe); 2429459cc2c6SThierry Reding value &= ~SOR_HEAD_STATE_COLORSPACE_MASK; 2430459cc2c6SThierry Reding value |= SOR_HEAD_STATE_COLORSPACE_RGB; 2431880cee0bSThierry Reding tegra_sor_writel(sor, value, sor->soc->regs->head_state0 + dc->pipe); 2432459cc2c6SThierry Reding 2433c31efa7aSThierry Reding tegra_sor_mode_set(sor, mode, state); 2434459cc2c6SThierry Reding 2435459cc2c6SThierry Reding tegra_sor_update(sor); 2436459cc2c6SThierry Reding 2437*c57997bcSThierry Reding /* program preamble timing in SOR (XXX) */ 2438*c57997bcSThierry Reding value = tegra_sor_readl(sor, SOR_DP_SPARE0); 2439*c57997bcSThierry Reding value &= ~SOR_DP_SPARE_DISP_VIDEO_PREAMBLE; 2440*c57997bcSThierry Reding tegra_sor_writel(sor, value, SOR_DP_SPARE0); 2441*c57997bcSThierry Reding 2442459cc2c6SThierry Reding err = tegra_sor_attach(sor); 2443459cc2c6SThierry Reding if (err < 0) 2444459cc2c6SThierry Reding dev_err(sor->dev, "failed to attach SOR: %d\n", err); 2445459cc2c6SThierry Reding 2446459cc2c6SThierry Reding /* enable display to SOR clock and generate HDMI preamble */ 2447459cc2c6SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 2448*c57997bcSThierry Reding 2449*c57997bcSThierry Reding if (!sor->soc->has_nvdisplay) 2450*c57997bcSThierry Reding value |= SOR_ENABLE(1) | SOR1_TIMING_CYA; 2451*c57997bcSThierry Reding else 2452*c57997bcSThierry Reding value |= SOR_ENABLE(sor->index); 2453*c57997bcSThierry Reding 2454459cc2c6SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 2455459cc2c6SThierry Reding 2456*c57997bcSThierry Reding if (dc->soc->has_nvdisplay) { 2457*c57997bcSThierry Reding value = tegra_dc_readl(dc, DC_DISP_CORE_SOR_SET_CONTROL(sor->index)); 2458*c57997bcSThierry Reding value &= ~PROTOCOL_MASK; 2459*c57997bcSThierry Reding value |= PROTOCOL_SINGLE_TMDS_A; 2460*c57997bcSThierry Reding tegra_dc_writel(dc, value, DC_DISP_CORE_SOR_SET_CONTROL(sor->index)); 2461*c57997bcSThierry Reding } 2462*c57997bcSThierry Reding 2463459cc2c6SThierry Reding tegra_dc_commit(dc); 2464459cc2c6SThierry Reding 2465459cc2c6SThierry Reding err = tegra_sor_wakeup(sor); 2466459cc2c6SThierry Reding if (err < 0) 2467459cc2c6SThierry Reding dev_err(sor->dev, "failed to wakeup SOR: %d\n", err); 2468459cc2c6SThierry Reding } 2469459cc2c6SThierry Reding 2470459cc2c6SThierry Reding static const struct drm_encoder_helper_funcs tegra_sor_hdmi_helpers = { 2471459cc2c6SThierry Reding .disable = tegra_sor_hdmi_disable, 2472459cc2c6SThierry Reding .enable = tegra_sor_hdmi_enable, 2473459cc2c6SThierry Reding .atomic_check = tegra_sor_encoder_atomic_check, 2474459cc2c6SThierry Reding }; 2475459cc2c6SThierry Reding 24766b6b6042SThierry Reding static int tegra_sor_init(struct host1x_client *client) 24776b6b6042SThierry Reding { 24789910f5c4SThierry Reding struct drm_device *drm = dev_get_drvdata(client->parent); 2479459cc2c6SThierry Reding const struct drm_encoder_helper_funcs *helpers = NULL; 24806b6b6042SThierry Reding struct tegra_sor *sor = host1x_client_to_sor(client); 2481459cc2c6SThierry Reding int connector = DRM_MODE_CONNECTOR_Unknown; 2482459cc2c6SThierry Reding int encoder = DRM_MODE_ENCODER_NONE; 24836b6b6042SThierry Reding int err; 24846b6b6042SThierry Reding 24859542c237SThierry Reding if (!sor->aux) { 2486459cc2c6SThierry Reding if (sor->soc->supports_hdmi) { 2487459cc2c6SThierry Reding connector = DRM_MODE_CONNECTOR_HDMIA; 2488459cc2c6SThierry Reding encoder = DRM_MODE_ENCODER_TMDS; 2489459cc2c6SThierry Reding helpers = &tegra_sor_hdmi_helpers; 2490459cc2c6SThierry Reding } else if (sor->soc->supports_lvds) { 2491459cc2c6SThierry Reding connector = DRM_MODE_CONNECTOR_LVDS; 2492459cc2c6SThierry Reding encoder = DRM_MODE_ENCODER_LVDS; 2493459cc2c6SThierry Reding } 2494459cc2c6SThierry Reding } else { 2495459cc2c6SThierry Reding if (sor->soc->supports_edp) { 2496459cc2c6SThierry Reding connector = DRM_MODE_CONNECTOR_eDP; 2497459cc2c6SThierry Reding encoder = DRM_MODE_ENCODER_TMDS; 2498459cc2c6SThierry Reding helpers = &tegra_sor_edp_helpers; 2499459cc2c6SThierry Reding } else if (sor->soc->supports_dp) { 2500459cc2c6SThierry Reding connector = DRM_MODE_CONNECTOR_DisplayPort; 2501459cc2c6SThierry Reding encoder = DRM_MODE_ENCODER_TMDS; 2502459cc2c6SThierry Reding } 2503459cc2c6SThierry Reding } 25046b6b6042SThierry Reding 25056b6b6042SThierry Reding sor->output.dev = sor->dev; 25066b6b6042SThierry Reding 25076fad8f66SThierry Reding drm_connector_init(drm, &sor->output.connector, 25086fad8f66SThierry Reding &tegra_sor_connector_funcs, 2509459cc2c6SThierry Reding connector); 25106fad8f66SThierry Reding drm_connector_helper_add(&sor->output.connector, 25116fad8f66SThierry Reding &tegra_sor_connector_helper_funcs); 25126fad8f66SThierry Reding sor->output.connector.dpms = DRM_MODE_DPMS_OFF; 25136fad8f66SThierry Reding 25146fad8f66SThierry Reding drm_encoder_init(drm, &sor->output.encoder, &tegra_sor_encoder_funcs, 251513a3d91fSVille Syrjälä encoder, NULL); 2516459cc2c6SThierry Reding drm_encoder_helper_add(&sor->output.encoder, helpers); 25176fad8f66SThierry Reding 25186fad8f66SThierry Reding drm_mode_connector_attach_encoder(&sor->output.connector, 25196fad8f66SThierry Reding &sor->output.encoder); 25206fad8f66SThierry Reding drm_connector_register(&sor->output.connector); 25216fad8f66SThierry Reding 2522ea130b24SThierry Reding err = tegra_output_init(drm, &sor->output); 2523ea130b24SThierry Reding if (err < 0) { 2524ea130b24SThierry Reding dev_err(client->dev, "failed to initialize output: %d\n", err); 2525ea130b24SThierry Reding return err; 2526ea130b24SThierry Reding } 25276fad8f66SThierry Reding 2528*c57997bcSThierry Reding tegra_output_find_possible_crtcs(&sor->output, drm); 25296b6b6042SThierry Reding 25309542c237SThierry Reding if (sor->aux) { 25319542c237SThierry Reding err = drm_dp_aux_attach(sor->aux, &sor->output); 25326b6b6042SThierry Reding if (err < 0) { 25336b6b6042SThierry Reding dev_err(sor->dev, "failed to attach DP: %d\n", err); 25346b6b6042SThierry Reding return err; 25356b6b6042SThierry Reding } 25366b6b6042SThierry Reding } 25376b6b6042SThierry Reding 2538535a65dbSTomeu Vizoso /* 2539535a65dbSTomeu Vizoso * XXX: Remove this reset once proper hand-over from firmware to 2540535a65dbSTomeu Vizoso * kernel is possible. 2541535a65dbSTomeu Vizoso */ 2542f8c79120SJon Hunter if (sor->rst) { 2543535a65dbSTomeu Vizoso err = reset_control_assert(sor->rst); 2544535a65dbSTomeu Vizoso if (err < 0) { 2545f8c79120SJon Hunter dev_err(sor->dev, "failed to assert SOR reset: %d\n", 2546f8c79120SJon Hunter err); 2547535a65dbSTomeu Vizoso return err; 2548535a65dbSTomeu Vizoso } 2549f8c79120SJon Hunter } 2550535a65dbSTomeu Vizoso 25516fad8f66SThierry Reding err = clk_prepare_enable(sor->clk); 25526fad8f66SThierry Reding if (err < 0) { 25536fad8f66SThierry Reding dev_err(sor->dev, "failed to enable clock: %d\n", err); 25546fad8f66SThierry Reding return err; 25556fad8f66SThierry Reding } 25566fad8f66SThierry Reding 2557535a65dbSTomeu Vizoso usleep_range(1000, 3000); 2558535a65dbSTomeu Vizoso 2559f8c79120SJon Hunter if (sor->rst) { 2560535a65dbSTomeu Vizoso err = reset_control_deassert(sor->rst); 2561535a65dbSTomeu Vizoso if (err < 0) { 2562f8c79120SJon Hunter dev_err(sor->dev, "failed to deassert SOR reset: %d\n", 2563f8c79120SJon Hunter err); 2564535a65dbSTomeu Vizoso return err; 2565535a65dbSTomeu Vizoso } 2566f8c79120SJon Hunter } 2567535a65dbSTomeu Vizoso 25686fad8f66SThierry Reding err = clk_prepare_enable(sor->clk_safe); 25696fad8f66SThierry Reding if (err < 0) 25706fad8f66SThierry Reding return err; 25716fad8f66SThierry Reding 25726fad8f66SThierry Reding err = clk_prepare_enable(sor->clk_dp); 25736fad8f66SThierry Reding if (err < 0) 25746fad8f66SThierry Reding return err; 25756fad8f66SThierry Reding 25766b6b6042SThierry Reding return 0; 25776b6b6042SThierry Reding } 25786b6b6042SThierry Reding 25796b6b6042SThierry Reding static int tegra_sor_exit(struct host1x_client *client) 25806b6b6042SThierry Reding { 25816b6b6042SThierry Reding struct tegra_sor *sor = host1x_client_to_sor(client); 25826b6b6042SThierry Reding int err; 25836b6b6042SThierry Reding 2584328ec69eSThierry Reding tegra_output_exit(&sor->output); 2585328ec69eSThierry Reding 25869542c237SThierry Reding if (sor->aux) { 25879542c237SThierry Reding err = drm_dp_aux_detach(sor->aux); 25886b6b6042SThierry Reding if (err < 0) { 25896b6b6042SThierry Reding dev_err(sor->dev, "failed to detach DP: %d\n", err); 25906b6b6042SThierry Reding return err; 25916b6b6042SThierry Reding } 25926b6b6042SThierry Reding } 25936b6b6042SThierry Reding 25946fad8f66SThierry Reding clk_disable_unprepare(sor->clk_safe); 25956fad8f66SThierry Reding clk_disable_unprepare(sor->clk_dp); 25966fad8f66SThierry Reding clk_disable_unprepare(sor->clk); 25976fad8f66SThierry Reding 25986b6b6042SThierry Reding return 0; 25996b6b6042SThierry Reding } 26006b6b6042SThierry Reding 26016b6b6042SThierry Reding static const struct host1x_client_ops sor_client_ops = { 26026b6b6042SThierry Reding .init = tegra_sor_init, 26036b6b6042SThierry Reding .exit = tegra_sor_exit, 26046b6b6042SThierry Reding }; 26056b6b6042SThierry Reding 2606459cc2c6SThierry Reding static const struct tegra_sor_ops tegra_sor_edp_ops = { 2607459cc2c6SThierry Reding .name = "eDP", 2608459cc2c6SThierry Reding }; 2609459cc2c6SThierry Reding 2610459cc2c6SThierry Reding static int tegra_sor_hdmi_probe(struct tegra_sor *sor) 2611459cc2c6SThierry Reding { 2612459cc2c6SThierry Reding int err; 2613459cc2c6SThierry Reding 2614459cc2c6SThierry Reding sor->avdd_io_supply = devm_regulator_get(sor->dev, "avdd-io"); 2615459cc2c6SThierry Reding if (IS_ERR(sor->avdd_io_supply)) { 2616459cc2c6SThierry Reding dev_err(sor->dev, "cannot get AVDD I/O supply: %ld\n", 2617459cc2c6SThierry Reding PTR_ERR(sor->avdd_io_supply)); 2618459cc2c6SThierry Reding return PTR_ERR(sor->avdd_io_supply); 2619459cc2c6SThierry Reding } 2620459cc2c6SThierry Reding 2621459cc2c6SThierry Reding err = regulator_enable(sor->avdd_io_supply); 2622459cc2c6SThierry Reding if (err < 0) { 2623459cc2c6SThierry Reding dev_err(sor->dev, "failed to enable AVDD I/O supply: %d\n", 2624459cc2c6SThierry Reding err); 2625459cc2c6SThierry Reding return err; 2626459cc2c6SThierry Reding } 2627459cc2c6SThierry Reding 2628459cc2c6SThierry Reding sor->vdd_pll_supply = devm_regulator_get(sor->dev, "vdd-pll"); 2629459cc2c6SThierry Reding if (IS_ERR(sor->vdd_pll_supply)) { 2630459cc2c6SThierry Reding dev_err(sor->dev, "cannot get VDD PLL supply: %ld\n", 2631459cc2c6SThierry Reding PTR_ERR(sor->vdd_pll_supply)); 2632459cc2c6SThierry Reding return PTR_ERR(sor->vdd_pll_supply); 2633459cc2c6SThierry Reding } 2634459cc2c6SThierry Reding 2635459cc2c6SThierry Reding err = regulator_enable(sor->vdd_pll_supply); 2636459cc2c6SThierry Reding if (err < 0) { 2637459cc2c6SThierry Reding dev_err(sor->dev, "failed to enable VDD PLL supply: %d\n", 2638459cc2c6SThierry Reding err); 2639459cc2c6SThierry Reding return err; 2640459cc2c6SThierry Reding } 2641459cc2c6SThierry Reding 2642459cc2c6SThierry Reding sor->hdmi_supply = devm_regulator_get(sor->dev, "hdmi"); 2643459cc2c6SThierry Reding if (IS_ERR(sor->hdmi_supply)) { 2644459cc2c6SThierry Reding dev_err(sor->dev, "cannot get HDMI supply: %ld\n", 2645459cc2c6SThierry Reding PTR_ERR(sor->hdmi_supply)); 2646459cc2c6SThierry Reding return PTR_ERR(sor->hdmi_supply); 2647459cc2c6SThierry Reding } 2648459cc2c6SThierry Reding 2649459cc2c6SThierry Reding err = regulator_enable(sor->hdmi_supply); 2650459cc2c6SThierry Reding if (err < 0) { 2651459cc2c6SThierry Reding dev_err(sor->dev, "failed to enable HDMI supply: %d\n", err); 2652459cc2c6SThierry Reding return err; 2653459cc2c6SThierry Reding } 2654459cc2c6SThierry Reding 2655459cc2c6SThierry Reding return 0; 2656459cc2c6SThierry Reding } 2657459cc2c6SThierry Reding 2658459cc2c6SThierry Reding static int tegra_sor_hdmi_remove(struct tegra_sor *sor) 2659459cc2c6SThierry Reding { 2660459cc2c6SThierry Reding regulator_disable(sor->hdmi_supply); 2661459cc2c6SThierry Reding regulator_disable(sor->vdd_pll_supply); 2662459cc2c6SThierry Reding regulator_disable(sor->avdd_io_supply); 2663459cc2c6SThierry Reding 2664459cc2c6SThierry Reding return 0; 2665459cc2c6SThierry Reding } 2666459cc2c6SThierry Reding 2667459cc2c6SThierry Reding static const struct tegra_sor_ops tegra_sor_hdmi_ops = { 2668459cc2c6SThierry Reding .name = "HDMI", 2669459cc2c6SThierry Reding .probe = tegra_sor_hdmi_probe, 2670459cc2c6SThierry Reding .remove = tegra_sor_hdmi_remove, 2671459cc2c6SThierry Reding }; 2672459cc2c6SThierry Reding 267330b49435SThierry Reding static const u8 tegra124_sor_xbar_cfg[5] = { 267430b49435SThierry Reding 0, 1, 2, 3, 4 267530b49435SThierry Reding }; 267630b49435SThierry Reding 2677880cee0bSThierry Reding static const struct tegra_sor_regs tegra124_sor_regs = { 2678880cee0bSThierry Reding .head_state0 = 0x05, 2679880cee0bSThierry Reding .head_state1 = 0x07, 2680880cee0bSThierry Reding .head_state2 = 0x09, 2681880cee0bSThierry Reding .head_state3 = 0x0b, 2682880cee0bSThierry Reding .head_state4 = 0x0d, 2683880cee0bSThierry Reding .head_state5 = 0x0f, 2684880cee0bSThierry Reding .pll0 = 0x17, 2685880cee0bSThierry Reding .pll1 = 0x18, 2686880cee0bSThierry Reding .pll2 = 0x19, 2687880cee0bSThierry Reding .pll3 = 0x1a, 2688880cee0bSThierry Reding .dp_padctl0 = 0x5c, 2689880cee0bSThierry Reding .dp_padctl2 = 0x73, 2690880cee0bSThierry Reding }; 2691880cee0bSThierry Reding 2692459cc2c6SThierry Reding static const struct tegra_sor_soc tegra124_sor = { 2693459cc2c6SThierry Reding .supports_edp = true, 2694459cc2c6SThierry Reding .supports_lvds = true, 2695459cc2c6SThierry Reding .supports_hdmi = false, 2696459cc2c6SThierry Reding .supports_dp = false, 2697880cee0bSThierry Reding .regs = &tegra124_sor_regs, 2698*c57997bcSThierry Reding .has_nvdisplay = false, 269930b49435SThierry Reding .xbar_cfg = tegra124_sor_xbar_cfg, 2700459cc2c6SThierry Reding }; 2701459cc2c6SThierry Reding 2702880cee0bSThierry Reding static const struct tegra_sor_regs tegra210_sor_regs = { 2703880cee0bSThierry Reding .head_state0 = 0x05, 2704880cee0bSThierry Reding .head_state1 = 0x07, 2705880cee0bSThierry Reding .head_state2 = 0x09, 2706880cee0bSThierry Reding .head_state3 = 0x0b, 2707880cee0bSThierry Reding .head_state4 = 0x0d, 2708880cee0bSThierry Reding .head_state5 = 0x0f, 2709880cee0bSThierry Reding .pll0 = 0x17, 2710880cee0bSThierry Reding .pll1 = 0x18, 2711880cee0bSThierry Reding .pll2 = 0x19, 2712880cee0bSThierry Reding .pll3 = 0x1a, 2713880cee0bSThierry Reding .dp_padctl0 = 0x5c, 2714880cee0bSThierry Reding .dp_padctl2 = 0x73, 2715880cee0bSThierry Reding }; 2716880cee0bSThierry Reding 2717459cc2c6SThierry Reding static const struct tegra_sor_soc tegra210_sor = { 2718459cc2c6SThierry Reding .supports_edp = true, 2719459cc2c6SThierry Reding .supports_lvds = false, 2720459cc2c6SThierry Reding .supports_hdmi = false, 2721459cc2c6SThierry Reding .supports_dp = false, 2722880cee0bSThierry Reding .regs = &tegra210_sor_regs, 2723*c57997bcSThierry Reding .has_nvdisplay = false, 272430b49435SThierry Reding .xbar_cfg = tegra124_sor_xbar_cfg, 272530b49435SThierry Reding }; 272630b49435SThierry Reding 272730b49435SThierry Reding static const u8 tegra210_sor_xbar_cfg[5] = { 272830b49435SThierry Reding 2, 1, 0, 3, 4 2729459cc2c6SThierry Reding }; 2730459cc2c6SThierry Reding 2731459cc2c6SThierry Reding static const struct tegra_sor_soc tegra210_sor1 = { 2732459cc2c6SThierry Reding .supports_edp = false, 2733459cc2c6SThierry Reding .supports_lvds = false, 2734459cc2c6SThierry Reding .supports_hdmi = true, 2735459cc2c6SThierry Reding .supports_dp = true, 2736459cc2c6SThierry Reding 2737880cee0bSThierry Reding .regs = &tegra210_sor_regs, 2738*c57997bcSThierry Reding .has_nvdisplay = false, 2739880cee0bSThierry Reding 2740459cc2c6SThierry Reding .num_settings = ARRAY_SIZE(tegra210_sor_hdmi_defaults), 2741459cc2c6SThierry Reding .settings = tegra210_sor_hdmi_defaults, 274230b49435SThierry Reding 274330b49435SThierry Reding .xbar_cfg = tegra210_sor_xbar_cfg, 2744459cc2c6SThierry Reding }; 2745459cc2c6SThierry Reding 2746*c57997bcSThierry Reding static const struct tegra_sor_regs tegra186_sor_regs = { 2747*c57997bcSThierry Reding .head_state0 = 0x151, 2748*c57997bcSThierry Reding .head_state1 = 0x154, 2749*c57997bcSThierry Reding .head_state2 = 0x157, 2750*c57997bcSThierry Reding .head_state3 = 0x15a, 2751*c57997bcSThierry Reding .head_state4 = 0x15d, 2752*c57997bcSThierry Reding .head_state5 = 0x160, 2753*c57997bcSThierry Reding .pll0 = 0x163, 2754*c57997bcSThierry Reding .pll1 = 0x164, 2755*c57997bcSThierry Reding .pll2 = 0x165, 2756*c57997bcSThierry Reding .pll3 = 0x166, 2757*c57997bcSThierry Reding .dp_padctl0 = 0x168, 2758*c57997bcSThierry Reding .dp_padctl2 = 0x16a, 2759*c57997bcSThierry Reding }; 2760*c57997bcSThierry Reding 2761*c57997bcSThierry Reding static const struct tegra_sor_soc tegra186_sor = { 2762*c57997bcSThierry Reding .supports_edp = false, 2763*c57997bcSThierry Reding .supports_lvds = false, 2764*c57997bcSThierry Reding .supports_hdmi = false, 2765*c57997bcSThierry Reding .supports_dp = true, 2766*c57997bcSThierry Reding 2767*c57997bcSThierry Reding .regs = &tegra186_sor_regs, 2768*c57997bcSThierry Reding .has_nvdisplay = true, 2769*c57997bcSThierry Reding 2770*c57997bcSThierry Reding .xbar_cfg = tegra124_sor_xbar_cfg, 2771*c57997bcSThierry Reding }; 2772*c57997bcSThierry Reding 2773*c57997bcSThierry Reding static const struct tegra_sor_soc tegra186_sor1 = { 2774*c57997bcSThierry Reding .supports_edp = false, 2775*c57997bcSThierry Reding .supports_lvds = false, 2776*c57997bcSThierry Reding .supports_hdmi = true, 2777*c57997bcSThierry Reding .supports_dp = true, 2778*c57997bcSThierry Reding 2779*c57997bcSThierry Reding .regs = &tegra186_sor_regs, 2780*c57997bcSThierry Reding .has_nvdisplay = true, 2781*c57997bcSThierry Reding 2782*c57997bcSThierry Reding .num_settings = ARRAY_SIZE(tegra186_sor_hdmi_defaults), 2783*c57997bcSThierry Reding .settings = tegra186_sor_hdmi_defaults, 2784*c57997bcSThierry Reding 2785*c57997bcSThierry Reding .xbar_cfg = tegra124_sor_xbar_cfg, 2786*c57997bcSThierry Reding }; 2787*c57997bcSThierry Reding 2788459cc2c6SThierry Reding static const struct of_device_id tegra_sor_of_match[] = { 2789*c57997bcSThierry Reding { .compatible = "nvidia,tegra186-sor1", .data = &tegra186_sor1 }, 2790*c57997bcSThierry Reding { .compatible = "nvidia,tegra186-sor", .data = &tegra186_sor }, 2791459cc2c6SThierry Reding { .compatible = "nvidia,tegra210-sor1", .data = &tegra210_sor1 }, 2792459cc2c6SThierry Reding { .compatible = "nvidia,tegra210-sor", .data = &tegra210_sor }, 2793459cc2c6SThierry Reding { .compatible = "nvidia,tegra124-sor", .data = &tegra124_sor }, 2794459cc2c6SThierry Reding { }, 2795459cc2c6SThierry Reding }; 2796459cc2c6SThierry Reding MODULE_DEVICE_TABLE(of, tegra_sor_of_match); 2797459cc2c6SThierry Reding 2798*c57997bcSThierry Reding static int tegra_sor_parse_dt(struct tegra_sor *sor) 2799*c57997bcSThierry Reding { 2800*c57997bcSThierry Reding struct device_node *np = sor->dev->of_node; 2801*c57997bcSThierry Reding u32 value; 2802*c57997bcSThierry Reding int err; 2803*c57997bcSThierry Reding 2804*c57997bcSThierry Reding if (sor->soc->has_nvdisplay) { 2805*c57997bcSThierry Reding err = of_property_read_u32(np, "nvidia,interface", &value); 2806*c57997bcSThierry Reding if (err < 0) 2807*c57997bcSThierry Reding return err; 2808*c57997bcSThierry Reding 2809*c57997bcSThierry Reding sor->index = value; 2810*c57997bcSThierry Reding 2811*c57997bcSThierry Reding /* 2812*c57997bcSThierry Reding * override the default that we already set for Tegra210 and 2813*c57997bcSThierry Reding * earlier 2814*c57997bcSThierry Reding */ 2815*c57997bcSThierry Reding sor->pad = TEGRA_IO_PAD_HDMI_DP0 + sor->index; 2816*c57997bcSThierry Reding } 2817*c57997bcSThierry Reding 2818*c57997bcSThierry Reding return 0; 2819*c57997bcSThierry Reding } 2820*c57997bcSThierry Reding 28216b6b6042SThierry Reding static int tegra_sor_probe(struct platform_device *pdev) 28226b6b6042SThierry Reding { 28236b6b6042SThierry Reding struct device_node *np; 28246b6b6042SThierry Reding struct tegra_sor *sor; 28256b6b6042SThierry Reding struct resource *regs; 28266b6b6042SThierry Reding int err; 28276b6b6042SThierry Reding 28286b6b6042SThierry Reding sor = devm_kzalloc(&pdev->dev, sizeof(*sor), GFP_KERNEL); 28296b6b6042SThierry Reding if (!sor) 28306b6b6042SThierry Reding return -ENOMEM; 28316b6b6042SThierry Reding 28325faea3d0SThierry Reding sor->soc = of_device_get_match_data(&pdev->dev); 28336b6b6042SThierry Reding sor->output.dev = sor->dev = &pdev->dev; 2834459cc2c6SThierry Reding 2835459cc2c6SThierry Reding sor->settings = devm_kmemdup(&pdev->dev, sor->soc->settings, 2836459cc2c6SThierry Reding sor->soc->num_settings * 2837459cc2c6SThierry Reding sizeof(*sor->settings), 2838459cc2c6SThierry Reding GFP_KERNEL); 2839459cc2c6SThierry Reding if (!sor->settings) 2840459cc2c6SThierry Reding return -ENOMEM; 2841459cc2c6SThierry Reding 2842459cc2c6SThierry Reding sor->num_settings = sor->soc->num_settings; 28436b6b6042SThierry Reding 28446b6b6042SThierry Reding np = of_parse_phandle(pdev->dev.of_node, "nvidia,dpaux", 0); 28456b6b6042SThierry Reding if (np) { 28469542c237SThierry Reding sor->aux = drm_dp_aux_find_by_of_node(np); 28476b6b6042SThierry Reding of_node_put(np); 28486b6b6042SThierry Reding 28499542c237SThierry Reding if (!sor->aux) 28506b6b6042SThierry Reding return -EPROBE_DEFER; 28516b6b6042SThierry Reding } 28526b6b6042SThierry Reding 28539542c237SThierry Reding if (!sor->aux) { 2854459cc2c6SThierry Reding if (sor->soc->supports_hdmi) { 2855459cc2c6SThierry Reding sor->ops = &tegra_sor_hdmi_ops; 2856*c57997bcSThierry Reding sor->pad = TEGRA_IO_PAD_HDMI; 2857459cc2c6SThierry Reding } else if (sor->soc->supports_lvds) { 2858459cc2c6SThierry Reding dev_err(&pdev->dev, "LVDS not supported yet\n"); 2859459cc2c6SThierry Reding return -ENODEV; 2860459cc2c6SThierry Reding } else { 2861459cc2c6SThierry Reding dev_err(&pdev->dev, "unknown (non-DP) support\n"); 2862459cc2c6SThierry Reding return -ENODEV; 2863459cc2c6SThierry Reding } 2864459cc2c6SThierry Reding } else { 2865459cc2c6SThierry Reding if (sor->soc->supports_edp) { 2866459cc2c6SThierry Reding sor->ops = &tegra_sor_edp_ops; 2867*c57997bcSThierry Reding sor->pad = TEGRA_IO_PAD_LVDS; 2868459cc2c6SThierry Reding } else if (sor->soc->supports_dp) { 2869459cc2c6SThierry Reding dev_err(&pdev->dev, "DisplayPort not supported yet\n"); 2870459cc2c6SThierry Reding return -ENODEV; 2871459cc2c6SThierry Reding } else { 2872459cc2c6SThierry Reding dev_err(&pdev->dev, "unknown (DP) support\n"); 2873459cc2c6SThierry Reding return -ENODEV; 2874459cc2c6SThierry Reding } 2875459cc2c6SThierry Reding } 2876459cc2c6SThierry Reding 2877*c57997bcSThierry Reding err = tegra_sor_parse_dt(sor); 2878*c57997bcSThierry Reding if (err < 0) 2879*c57997bcSThierry Reding return err; 2880*c57997bcSThierry Reding 28816b6b6042SThierry Reding err = tegra_output_probe(&sor->output); 28824dbdc740SThierry Reding if (err < 0) { 28834dbdc740SThierry Reding dev_err(&pdev->dev, "failed to probe output: %d\n", err); 28846b6b6042SThierry Reding return err; 28854dbdc740SThierry Reding } 28866b6b6042SThierry Reding 2887459cc2c6SThierry Reding if (sor->ops && sor->ops->probe) { 2888459cc2c6SThierry Reding err = sor->ops->probe(sor); 2889459cc2c6SThierry Reding if (err < 0) { 2890459cc2c6SThierry Reding dev_err(&pdev->dev, "failed to probe %s: %d\n", 2891459cc2c6SThierry Reding sor->ops->name, err); 2892459cc2c6SThierry Reding goto output; 2893459cc2c6SThierry Reding } 2894459cc2c6SThierry Reding } 2895459cc2c6SThierry Reding 28966b6b6042SThierry Reding regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 28976b6b6042SThierry Reding sor->regs = devm_ioremap_resource(&pdev->dev, regs); 2898459cc2c6SThierry Reding if (IS_ERR(sor->regs)) { 2899459cc2c6SThierry Reding err = PTR_ERR(sor->regs); 2900459cc2c6SThierry Reding goto remove; 2901459cc2c6SThierry Reding } 29026b6b6042SThierry Reding 2903f8c79120SJon Hunter if (!pdev->dev.pm_domain) { 29046b6b6042SThierry Reding sor->rst = devm_reset_control_get(&pdev->dev, "sor"); 29054dbdc740SThierry Reding if (IS_ERR(sor->rst)) { 2906459cc2c6SThierry Reding err = PTR_ERR(sor->rst); 2907f8c79120SJon Hunter dev_err(&pdev->dev, "failed to get reset control: %d\n", 2908f8c79120SJon Hunter err); 2909459cc2c6SThierry Reding goto remove; 29104dbdc740SThierry Reding } 2911f8c79120SJon Hunter } 29126b6b6042SThierry Reding 29136b6b6042SThierry Reding sor->clk = devm_clk_get(&pdev->dev, NULL); 29144dbdc740SThierry Reding if (IS_ERR(sor->clk)) { 2915459cc2c6SThierry Reding err = PTR_ERR(sor->clk); 2916459cc2c6SThierry Reding dev_err(&pdev->dev, "failed to get module clock: %d\n", err); 2917459cc2c6SThierry Reding goto remove; 29184dbdc740SThierry Reding } 29196b6b6042SThierry Reding 2920618dee39SThierry Reding if (sor->soc->supports_hdmi || sor->soc->supports_dp) { 2921e1335e2fSThierry Reding struct device_node *np = pdev->dev.of_node; 2922e1335e2fSThierry Reding const char *name; 2923e1335e2fSThierry Reding 2924e1335e2fSThierry Reding /* 2925e1335e2fSThierry Reding * For backwards compatibility with Tegra210 device trees, 2926e1335e2fSThierry Reding * fall back to the old clock name "source" if the new "out" 2927e1335e2fSThierry Reding * clock is not available. 2928e1335e2fSThierry Reding */ 2929e1335e2fSThierry Reding if (of_property_match_string(np, "clock-names", "out") < 0) 2930e1335e2fSThierry Reding name = "source"; 2931e1335e2fSThierry Reding else 2932e1335e2fSThierry Reding name = "out"; 2933e1335e2fSThierry Reding 2934e1335e2fSThierry Reding sor->clk_out = devm_clk_get(&pdev->dev, name); 2935e1335e2fSThierry Reding if (IS_ERR(sor->clk_out)) { 2936e1335e2fSThierry Reding err = PTR_ERR(sor->clk_out); 2937e1335e2fSThierry Reding dev_err(sor->dev, "failed to get %s clock: %d\n", 2938e1335e2fSThierry Reding name, err); 2939618dee39SThierry Reding goto remove; 2940618dee39SThierry Reding } 2941618dee39SThierry Reding } 2942618dee39SThierry Reding 29436b6b6042SThierry Reding sor->clk_parent = devm_clk_get(&pdev->dev, "parent"); 29444dbdc740SThierry Reding if (IS_ERR(sor->clk_parent)) { 2945459cc2c6SThierry Reding err = PTR_ERR(sor->clk_parent); 2946459cc2c6SThierry Reding dev_err(&pdev->dev, "failed to get parent clock: %d\n", err); 2947459cc2c6SThierry Reding goto remove; 29484dbdc740SThierry Reding } 29496b6b6042SThierry Reding 29506b6b6042SThierry Reding sor->clk_safe = devm_clk_get(&pdev->dev, "safe"); 29514dbdc740SThierry Reding if (IS_ERR(sor->clk_safe)) { 2952459cc2c6SThierry Reding err = PTR_ERR(sor->clk_safe); 2953459cc2c6SThierry Reding dev_err(&pdev->dev, "failed to get safe clock: %d\n", err); 2954459cc2c6SThierry Reding goto remove; 29554dbdc740SThierry Reding } 29566b6b6042SThierry Reding 29576b6b6042SThierry Reding sor->clk_dp = devm_clk_get(&pdev->dev, "dp"); 29584dbdc740SThierry Reding if (IS_ERR(sor->clk_dp)) { 2959459cc2c6SThierry Reding err = PTR_ERR(sor->clk_dp); 2960459cc2c6SThierry Reding dev_err(&pdev->dev, "failed to get DP clock: %d\n", err); 2961459cc2c6SThierry Reding goto remove; 29624dbdc740SThierry Reding } 29636b6b6042SThierry Reding 2964e1335e2fSThierry Reding /* 2965e1335e2fSThierry Reding * Starting with Tegra186, the BPMP provides an implementation for 2966e1335e2fSThierry Reding * the pad output clock, so we have to look it up from device tree. 2967e1335e2fSThierry Reding */ 2968e1335e2fSThierry Reding sor->clk_pad = devm_clk_get(&pdev->dev, "pad"); 2969e1335e2fSThierry Reding if (IS_ERR(sor->clk_pad)) { 2970e1335e2fSThierry Reding if (sor->clk_pad != ERR_PTR(-ENOENT)) { 2971e1335e2fSThierry Reding err = PTR_ERR(sor->clk_pad); 2972e1335e2fSThierry Reding goto remove; 2973e1335e2fSThierry Reding } 2974e1335e2fSThierry Reding 2975e1335e2fSThierry Reding /* 2976e1335e2fSThierry Reding * If the pad output clock is not available, then we assume 2977e1335e2fSThierry Reding * we're on Tegra210 or earlier and have to provide our own 2978e1335e2fSThierry Reding * implementation. 2979e1335e2fSThierry Reding */ 2980e1335e2fSThierry Reding sor->clk_pad = NULL; 2981e1335e2fSThierry Reding } 2982e1335e2fSThierry Reding 2983e1335e2fSThierry Reding /* 2984e1335e2fSThierry Reding * The bootloader may have set up the SOR such that it's module clock 2985e1335e2fSThierry Reding * is sourced by one of the display PLLs. However, that doesn't work 2986e1335e2fSThierry Reding * without properly having set up other bits of the SOR. 2987e1335e2fSThierry Reding */ 2988e1335e2fSThierry Reding err = clk_set_parent(sor->clk_out, sor->clk_safe); 2989e1335e2fSThierry Reding if (err < 0) { 2990e1335e2fSThierry Reding dev_err(&pdev->dev, "failed to use safe clock: %d\n", err); 2991e1335e2fSThierry Reding goto remove; 2992e1335e2fSThierry Reding } 2993e1335e2fSThierry Reding 2994aaff8bd2SThierry Reding platform_set_drvdata(pdev, sor); 2995aaff8bd2SThierry Reding pm_runtime_enable(&pdev->dev); 2996aaff8bd2SThierry Reding 2997e1335e2fSThierry Reding /* 2998e1335e2fSThierry Reding * On Tegra210 and earlier, provide our own implementation for the 2999e1335e2fSThierry Reding * pad output clock. 3000e1335e2fSThierry Reding */ 3001e1335e2fSThierry Reding if (!sor->clk_pad) { 3002e1335e2fSThierry Reding err = pm_runtime_get_sync(&pdev->dev); 3003e1335e2fSThierry Reding if (err < 0) { 3004e1335e2fSThierry Reding dev_err(&pdev->dev, "failed to get runtime PM: %d\n", 3005e1335e2fSThierry Reding err); 3006e1335e2fSThierry Reding goto remove; 3007e1335e2fSThierry Reding } 3008b299221cSThierry Reding 3009e1335e2fSThierry Reding sor->clk_pad = tegra_clk_sor_pad_register(sor, 3010e1335e2fSThierry Reding "sor1_pad_clkout"); 3011e1335e2fSThierry Reding pm_runtime_put(&pdev->dev); 3012e1335e2fSThierry Reding } 3013e1335e2fSThierry Reding 3014e1335e2fSThierry Reding if (IS_ERR(sor->clk_pad)) { 3015e1335e2fSThierry Reding err = PTR_ERR(sor->clk_pad); 3016e1335e2fSThierry Reding dev_err(&pdev->dev, "failed to register SOR pad clock: %d\n", 3017e1335e2fSThierry Reding err); 3018b299221cSThierry Reding goto remove; 3019b299221cSThierry Reding } 3020b299221cSThierry Reding 30216b6b6042SThierry Reding INIT_LIST_HEAD(&sor->client.list); 30226b6b6042SThierry Reding sor->client.ops = &sor_client_ops; 30236b6b6042SThierry Reding sor->client.dev = &pdev->dev; 30246b6b6042SThierry Reding 30256b6b6042SThierry Reding err = host1x_client_register(&sor->client); 30266b6b6042SThierry Reding if (err < 0) { 30276b6b6042SThierry Reding dev_err(&pdev->dev, "failed to register host1x client: %d\n", 30286b6b6042SThierry Reding err); 3029459cc2c6SThierry Reding goto remove; 30306b6b6042SThierry Reding } 30316b6b6042SThierry Reding 30326b6b6042SThierry Reding return 0; 3033459cc2c6SThierry Reding 3034459cc2c6SThierry Reding remove: 3035459cc2c6SThierry Reding if (sor->ops && sor->ops->remove) 3036459cc2c6SThierry Reding sor->ops->remove(sor); 3037459cc2c6SThierry Reding output: 3038459cc2c6SThierry Reding tegra_output_remove(&sor->output); 3039459cc2c6SThierry Reding return err; 30406b6b6042SThierry Reding } 30416b6b6042SThierry Reding 30426b6b6042SThierry Reding static int tegra_sor_remove(struct platform_device *pdev) 30436b6b6042SThierry Reding { 30446b6b6042SThierry Reding struct tegra_sor *sor = platform_get_drvdata(pdev); 30456b6b6042SThierry Reding int err; 30466b6b6042SThierry Reding 3047aaff8bd2SThierry Reding pm_runtime_disable(&pdev->dev); 3048aaff8bd2SThierry Reding 30496b6b6042SThierry Reding err = host1x_client_unregister(&sor->client); 30506b6b6042SThierry Reding if (err < 0) { 30516b6b6042SThierry Reding dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 30526b6b6042SThierry Reding err); 30536b6b6042SThierry Reding return err; 30546b6b6042SThierry Reding } 30556b6b6042SThierry Reding 3056459cc2c6SThierry Reding if (sor->ops && sor->ops->remove) { 3057459cc2c6SThierry Reding err = sor->ops->remove(sor); 3058459cc2c6SThierry Reding if (err < 0) 3059459cc2c6SThierry Reding dev_err(&pdev->dev, "failed to remove SOR: %d\n", err); 3060459cc2c6SThierry Reding } 3061459cc2c6SThierry Reding 3062328ec69eSThierry Reding tegra_output_remove(&sor->output); 30636b6b6042SThierry Reding 30646b6b6042SThierry Reding return 0; 30656b6b6042SThierry Reding } 30666b6b6042SThierry Reding 3067aaff8bd2SThierry Reding #ifdef CONFIG_PM 3068aaff8bd2SThierry Reding static int tegra_sor_suspend(struct device *dev) 3069aaff8bd2SThierry Reding { 3070aaff8bd2SThierry Reding struct tegra_sor *sor = dev_get_drvdata(dev); 3071aaff8bd2SThierry Reding int err; 3072aaff8bd2SThierry Reding 3073f8c79120SJon Hunter if (sor->rst) { 3074aaff8bd2SThierry Reding err = reset_control_assert(sor->rst); 3075aaff8bd2SThierry Reding if (err < 0) { 3076aaff8bd2SThierry Reding dev_err(dev, "failed to assert reset: %d\n", err); 3077aaff8bd2SThierry Reding return err; 3078aaff8bd2SThierry Reding } 3079f8c79120SJon Hunter } 3080aaff8bd2SThierry Reding 3081aaff8bd2SThierry Reding usleep_range(1000, 2000); 3082aaff8bd2SThierry Reding 3083aaff8bd2SThierry Reding clk_disable_unprepare(sor->clk); 3084aaff8bd2SThierry Reding 3085aaff8bd2SThierry Reding return 0; 3086aaff8bd2SThierry Reding } 3087aaff8bd2SThierry Reding 3088aaff8bd2SThierry Reding static int tegra_sor_resume(struct device *dev) 3089aaff8bd2SThierry Reding { 3090aaff8bd2SThierry Reding struct tegra_sor *sor = dev_get_drvdata(dev); 3091aaff8bd2SThierry Reding int err; 3092aaff8bd2SThierry Reding 3093aaff8bd2SThierry Reding err = clk_prepare_enable(sor->clk); 3094aaff8bd2SThierry Reding if (err < 0) { 3095aaff8bd2SThierry Reding dev_err(dev, "failed to enable clock: %d\n", err); 3096aaff8bd2SThierry Reding return err; 3097aaff8bd2SThierry Reding } 3098aaff8bd2SThierry Reding 3099aaff8bd2SThierry Reding usleep_range(1000, 2000); 3100aaff8bd2SThierry Reding 3101f8c79120SJon Hunter if (sor->rst) { 3102aaff8bd2SThierry Reding err = reset_control_deassert(sor->rst); 3103aaff8bd2SThierry Reding if (err < 0) { 3104aaff8bd2SThierry Reding dev_err(dev, "failed to deassert reset: %d\n", err); 3105aaff8bd2SThierry Reding clk_disable_unprepare(sor->clk); 3106aaff8bd2SThierry Reding return err; 3107aaff8bd2SThierry Reding } 3108f8c79120SJon Hunter } 3109aaff8bd2SThierry Reding 3110aaff8bd2SThierry Reding return 0; 3111aaff8bd2SThierry Reding } 3112aaff8bd2SThierry Reding #endif 3113aaff8bd2SThierry Reding 3114aaff8bd2SThierry Reding static const struct dev_pm_ops tegra_sor_pm_ops = { 3115aaff8bd2SThierry Reding SET_RUNTIME_PM_OPS(tegra_sor_suspend, tegra_sor_resume, NULL) 3116aaff8bd2SThierry Reding }; 3117aaff8bd2SThierry Reding 31186b6b6042SThierry Reding struct platform_driver tegra_sor_driver = { 31196b6b6042SThierry Reding .driver = { 31206b6b6042SThierry Reding .name = "tegra-sor", 31216b6b6042SThierry Reding .of_match_table = tegra_sor_of_match, 3122aaff8bd2SThierry Reding .pm = &tegra_sor_pm_ops, 31236b6b6042SThierry Reding }, 31246b6b6042SThierry Reding .probe = tegra_sor_probe, 31256b6b6042SThierry Reding .remove = tegra_sor_remove, 31266b6b6042SThierry Reding }; 3127