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 31459cc2c6SThierry Reding #define SOR_REKEY 0x38 32459cc2c6SThierry Reding 33459cc2c6SThierry Reding struct tegra_sor_hdmi_settings { 34459cc2c6SThierry Reding unsigned long frequency; 35459cc2c6SThierry Reding 36459cc2c6SThierry Reding u8 vcocap; 37459cc2c6SThierry Reding u8 ichpmp; 38459cc2c6SThierry Reding u8 loadadj; 39459cc2c6SThierry Reding u8 termadj; 40459cc2c6SThierry Reding u8 tx_pu; 41459cc2c6SThierry Reding u8 bg_vref; 42459cc2c6SThierry Reding 43459cc2c6SThierry Reding u8 drive_current[4]; 44459cc2c6SThierry Reding u8 preemphasis[4]; 45459cc2c6SThierry Reding }; 46459cc2c6SThierry Reding 47459cc2c6SThierry Reding #if 1 48459cc2c6SThierry Reding static const struct tegra_sor_hdmi_settings tegra210_sor_hdmi_defaults[] = { 49459cc2c6SThierry Reding { 50459cc2c6SThierry Reding .frequency = 54000000, 51459cc2c6SThierry Reding .vcocap = 0x0, 52459cc2c6SThierry Reding .ichpmp = 0x1, 53459cc2c6SThierry Reding .loadadj = 0x3, 54459cc2c6SThierry Reding .termadj = 0x9, 55459cc2c6SThierry Reding .tx_pu = 0x10, 56459cc2c6SThierry Reding .bg_vref = 0x8, 57459cc2c6SThierry Reding .drive_current = { 0x33, 0x3a, 0x3a, 0x3a }, 58459cc2c6SThierry Reding .preemphasis = { 0x00, 0x00, 0x00, 0x00 }, 59459cc2c6SThierry Reding }, { 60459cc2c6SThierry Reding .frequency = 75000000, 61459cc2c6SThierry Reding .vcocap = 0x3, 62459cc2c6SThierry Reding .ichpmp = 0x1, 63459cc2c6SThierry Reding .loadadj = 0x3, 64459cc2c6SThierry Reding .termadj = 0x9, 65459cc2c6SThierry Reding .tx_pu = 0x40, 66459cc2c6SThierry Reding .bg_vref = 0x8, 67459cc2c6SThierry Reding .drive_current = { 0x33, 0x3a, 0x3a, 0x3a }, 68459cc2c6SThierry Reding .preemphasis = { 0x00, 0x00, 0x00, 0x00 }, 69459cc2c6SThierry Reding }, { 70459cc2c6SThierry Reding .frequency = 150000000, 71459cc2c6SThierry Reding .vcocap = 0x3, 72459cc2c6SThierry Reding .ichpmp = 0x1, 73459cc2c6SThierry Reding .loadadj = 0x3, 74459cc2c6SThierry Reding .termadj = 0x9, 75459cc2c6SThierry Reding .tx_pu = 0x66, 76459cc2c6SThierry Reding .bg_vref = 0x8, 77459cc2c6SThierry Reding .drive_current = { 0x33, 0x3a, 0x3a, 0x3a }, 78459cc2c6SThierry Reding .preemphasis = { 0x00, 0x00, 0x00, 0x00 }, 79459cc2c6SThierry Reding }, { 80459cc2c6SThierry Reding .frequency = 300000000, 81459cc2c6SThierry Reding .vcocap = 0x3, 82459cc2c6SThierry Reding .ichpmp = 0x1, 83459cc2c6SThierry Reding .loadadj = 0x3, 84459cc2c6SThierry Reding .termadj = 0x9, 85459cc2c6SThierry Reding .tx_pu = 0x66, 86459cc2c6SThierry Reding .bg_vref = 0xa, 87459cc2c6SThierry Reding .drive_current = { 0x33, 0x3f, 0x3f, 0x3f }, 88459cc2c6SThierry Reding .preemphasis = { 0x00, 0x17, 0x17, 0x17 }, 89459cc2c6SThierry Reding }, { 90459cc2c6SThierry Reding .frequency = 600000000, 91459cc2c6SThierry Reding .vcocap = 0x3, 92459cc2c6SThierry Reding .ichpmp = 0x1, 93459cc2c6SThierry Reding .loadadj = 0x3, 94459cc2c6SThierry Reding .termadj = 0x9, 95459cc2c6SThierry Reding .tx_pu = 0x66, 96459cc2c6SThierry Reding .bg_vref = 0x8, 97459cc2c6SThierry Reding .drive_current = { 0x33, 0x3f, 0x3f, 0x3f }, 98459cc2c6SThierry Reding .preemphasis = { 0x00, 0x00, 0x00, 0x00 }, 99459cc2c6SThierry Reding }, 100459cc2c6SThierry Reding }; 101459cc2c6SThierry Reding #else 102459cc2c6SThierry Reding static const struct tegra_sor_hdmi_settings tegra210_sor_hdmi_defaults[] = { 103459cc2c6SThierry Reding { 104459cc2c6SThierry Reding .frequency = 75000000, 105459cc2c6SThierry Reding .vcocap = 0x3, 106459cc2c6SThierry Reding .ichpmp = 0x1, 107459cc2c6SThierry Reding .loadadj = 0x3, 108459cc2c6SThierry Reding .termadj = 0x9, 109459cc2c6SThierry Reding .tx_pu = 0x40, 110459cc2c6SThierry Reding .bg_vref = 0x8, 111459cc2c6SThierry Reding .drive_current = { 0x29, 0x29, 0x29, 0x29 }, 112459cc2c6SThierry Reding .preemphasis = { 0x00, 0x00, 0x00, 0x00 }, 113459cc2c6SThierry Reding }, { 114459cc2c6SThierry Reding .frequency = 150000000, 115459cc2c6SThierry Reding .vcocap = 0x3, 116459cc2c6SThierry Reding .ichpmp = 0x1, 117459cc2c6SThierry Reding .loadadj = 0x3, 118459cc2c6SThierry Reding .termadj = 0x9, 119459cc2c6SThierry Reding .tx_pu = 0x66, 120459cc2c6SThierry Reding .bg_vref = 0x8, 121459cc2c6SThierry Reding .drive_current = { 0x30, 0x37, 0x37, 0x37 }, 122459cc2c6SThierry Reding .preemphasis = { 0x01, 0x02, 0x02, 0x02 }, 123459cc2c6SThierry Reding }, { 124459cc2c6SThierry Reding .frequency = 300000000, 125459cc2c6SThierry Reding .vcocap = 0x3, 126459cc2c6SThierry Reding .ichpmp = 0x6, 127459cc2c6SThierry Reding .loadadj = 0x3, 128459cc2c6SThierry Reding .termadj = 0x9, 129459cc2c6SThierry Reding .tx_pu = 0x66, 130459cc2c6SThierry Reding .bg_vref = 0xf, 131459cc2c6SThierry Reding .drive_current = { 0x30, 0x37, 0x37, 0x37 }, 132459cc2c6SThierry Reding .preemphasis = { 0x10, 0x3e, 0x3e, 0x3e }, 133459cc2c6SThierry Reding }, { 134459cc2c6SThierry Reding .frequency = 600000000, 135459cc2c6SThierry Reding .vcocap = 0x3, 136459cc2c6SThierry Reding .ichpmp = 0xa, 137459cc2c6SThierry Reding .loadadj = 0x3, 138459cc2c6SThierry Reding .termadj = 0xb, 139459cc2c6SThierry Reding .tx_pu = 0x66, 140459cc2c6SThierry Reding .bg_vref = 0xe, 141459cc2c6SThierry Reding .drive_current = { 0x35, 0x3e, 0x3e, 0x3e }, 142459cc2c6SThierry Reding .preemphasis = { 0x02, 0x3f, 0x3f, 0x3f }, 143459cc2c6SThierry Reding }, 144459cc2c6SThierry Reding }; 145459cc2c6SThierry Reding #endif 146459cc2c6SThierry Reding 147459cc2c6SThierry Reding struct tegra_sor_soc { 148459cc2c6SThierry Reding bool supports_edp; 149459cc2c6SThierry Reding bool supports_lvds; 150459cc2c6SThierry Reding bool supports_hdmi; 151459cc2c6SThierry Reding bool supports_dp; 152459cc2c6SThierry Reding 153459cc2c6SThierry Reding const struct tegra_sor_hdmi_settings *settings; 154459cc2c6SThierry Reding unsigned int num_settings; 15530b49435SThierry Reding 15630b49435SThierry Reding const u8 *xbar_cfg; 157459cc2c6SThierry Reding }; 158459cc2c6SThierry Reding 159459cc2c6SThierry Reding struct tegra_sor; 160459cc2c6SThierry Reding 161459cc2c6SThierry Reding struct tegra_sor_ops { 162459cc2c6SThierry Reding const char *name; 163459cc2c6SThierry Reding int (*probe)(struct tegra_sor *sor); 164459cc2c6SThierry Reding int (*remove)(struct tegra_sor *sor); 165459cc2c6SThierry Reding }; 166459cc2c6SThierry Reding 1676b6b6042SThierry Reding struct tegra_sor { 1686b6b6042SThierry Reding struct host1x_client client; 1696b6b6042SThierry Reding struct tegra_output output; 1706b6b6042SThierry Reding struct device *dev; 1716b6b6042SThierry Reding 172459cc2c6SThierry Reding const struct tegra_sor_soc *soc; 1736b6b6042SThierry Reding void __iomem *regs; 1746b6b6042SThierry Reding 1756b6b6042SThierry Reding struct reset_control *rst; 1766b6b6042SThierry Reding struct clk *clk_parent; 1776b6b6042SThierry Reding struct clk *clk_safe; 178e1335e2fSThierry Reding struct clk *clk_out; 179e1335e2fSThierry Reding struct clk *clk_pad; 1806b6b6042SThierry Reding struct clk *clk_dp; 1816b6b6042SThierry Reding struct clk *clk; 1826b6b6042SThierry Reding 1839542c237SThierry Reding struct drm_dp_aux *aux; 1846b6b6042SThierry Reding 185dab16336SThierry Reding struct drm_info_list *debugfs_files; 186dab16336SThierry Reding struct drm_minor *minor; 187459cc2c6SThierry Reding 188459cc2c6SThierry Reding const struct tegra_sor_ops *ops; 189459cc2c6SThierry Reding 190459cc2c6SThierry Reding /* for HDMI 2.0 */ 191459cc2c6SThierry Reding struct tegra_sor_hdmi_settings *settings; 192459cc2c6SThierry Reding unsigned int num_settings; 193459cc2c6SThierry Reding 194459cc2c6SThierry Reding struct regulator *avdd_io_supply; 195459cc2c6SThierry Reding struct regulator *vdd_pll_supply; 196459cc2c6SThierry Reding struct regulator *hdmi_supply; 1976b6b6042SThierry Reding }; 1986b6b6042SThierry Reding 199c31efa7aSThierry Reding struct tegra_sor_state { 200c31efa7aSThierry Reding struct drm_connector_state base; 201c31efa7aSThierry Reding 202c31efa7aSThierry Reding unsigned int bpc; 203c31efa7aSThierry Reding }; 204c31efa7aSThierry Reding 205c31efa7aSThierry Reding static inline struct tegra_sor_state * 206c31efa7aSThierry Reding to_sor_state(struct drm_connector_state *state) 207c31efa7aSThierry Reding { 208c31efa7aSThierry Reding return container_of(state, struct tegra_sor_state, base); 209c31efa7aSThierry Reding } 210c31efa7aSThierry Reding 21134fa183bSThierry Reding struct tegra_sor_config { 21234fa183bSThierry Reding u32 bits_per_pixel; 21334fa183bSThierry Reding 21434fa183bSThierry Reding u32 active_polarity; 21534fa183bSThierry Reding u32 active_count; 21634fa183bSThierry Reding u32 tu_size; 21734fa183bSThierry Reding u32 active_frac; 21834fa183bSThierry Reding u32 watermark; 2197890b576SThierry Reding 2207890b576SThierry Reding u32 hblank_symbols; 2217890b576SThierry Reding u32 vblank_symbols; 22234fa183bSThierry Reding }; 22334fa183bSThierry Reding 2246b6b6042SThierry Reding static inline struct tegra_sor * 2256b6b6042SThierry Reding host1x_client_to_sor(struct host1x_client *client) 2266b6b6042SThierry Reding { 2276b6b6042SThierry Reding return container_of(client, struct tegra_sor, client); 2286b6b6042SThierry Reding } 2296b6b6042SThierry Reding 2306b6b6042SThierry Reding static inline struct tegra_sor *to_sor(struct tegra_output *output) 2316b6b6042SThierry Reding { 2326b6b6042SThierry Reding return container_of(output, struct tegra_sor, output); 2336b6b6042SThierry Reding } 2346b6b6042SThierry Reding 2355c5f1301SThierry Reding static inline u32 tegra_sor_readl(struct tegra_sor *sor, unsigned int offset) 2366b6b6042SThierry Reding { 237932f6529SThierry Reding u32 value = readl(sor->regs + (offset << 2)); 238932f6529SThierry Reding 239932f6529SThierry Reding trace_sor_readl(sor->dev, offset, value); 240932f6529SThierry Reding 241932f6529SThierry Reding return value; 2426b6b6042SThierry Reding } 2436b6b6042SThierry Reding 24428fe2076SThierry Reding static inline void tegra_sor_writel(struct tegra_sor *sor, u32 value, 2455c5f1301SThierry Reding unsigned int offset) 2466b6b6042SThierry Reding { 247932f6529SThierry Reding trace_sor_writel(sor->dev, offset, value); 2486b6b6042SThierry Reding writel(value, sor->regs + (offset << 2)); 2496b6b6042SThierry Reding } 2506b6b6042SThierry Reding 25125bb2cecSThierry Reding static int tegra_sor_set_parent_clock(struct tegra_sor *sor, struct clk *parent) 25225bb2cecSThierry Reding { 25325bb2cecSThierry Reding int err; 25425bb2cecSThierry Reding 25525bb2cecSThierry Reding clk_disable_unprepare(sor->clk); 25625bb2cecSThierry Reding 257e1335e2fSThierry Reding err = clk_set_parent(sor->clk_out, parent); 25825bb2cecSThierry Reding if (err < 0) 25925bb2cecSThierry Reding return err; 26025bb2cecSThierry Reding 26125bb2cecSThierry Reding err = clk_prepare_enable(sor->clk); 26225bb2cecSThierry Reding if (err < 0) 26325bb2cecSThierry Reding return err; 26425bb2cecSThierry Reding 26525bb2cecSThierry Reding return 0; 26625bb2cecSThierry Reding } 26725bb2cecSThierry Reding 268e1335e2fSThierry Reding struct tegra_clk_sor_pad { 269b299221cSThierry Reding struct clk_hw hw; 270b299221cSThierry Reding struct tegra_sor *sor; 271b299221cSThierry Reding }; 272b299221cSThierry Reding 273e1335e2fSThierry Reding static inline struct tegra_clk_sor_pad *to_pad(struct clk_hw *hw) 274b299221cSThierry Reding { 275e1335e2fSThierry Reding return container_of(hw, struct tegra_clk_sor_pad, hw); 276b299221cSThierry Reding } 277b299221cSThierry Reding 278e1335e2fSThierry Reding static const char * const tegra_clk_sor_pad_parents[] = { 279b299221cSThierry Reding "pll_d2_out0", "pll_dp" 280b299221cSThierry Reding }; 281b299221cSThierry Reding 282e1335e2fSThierry Reding static int tegra_clk_sor_pad_set_parent(struct clk_hw *hw, u8 index) 283b299221cSThierry Reding { 284e1335e2fSThierry Reding struct tegra_clk_sor_pad *pad = to_pad(hw); 285e1335e2fSThierry Reding struct tegra_sor *sor = pad->sor; 286b299221cSThierry Reding u32 value; 287b299221cSThierry Reding 288b299221cSThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 289b299221cSThierry Reding value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; 290b299221cSThierry Reding 291b299221cSThierry Reding switch (index) { 292b299221cSThierry Reding case 0: 293b299221cSThierry Reding value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK; 294b299221cSThierry Reding break; 295b299221cSThierry Reding 296b299221cSThierry Reding case 1: 297b299221cSThierry Reding value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK; 298b299221cSThierry Reding break; 299b299221cSThierry Reding } 300b299221cSThierry Reding 301b299221cSThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 302b299221cSThierry Reding 303b299221cSThierry Reding return 0; 304b299221cSThierry Reding } 305b299221cSThierry Reding 306e1335e2fSThierry Reding static u8 tegra_clk_sor_pad_get_parent(struct clk_hw *hw) 307b299221cSThierry Reding { 308e1335e2fSThierry Reding struct tegra_clk_sor_pad *pad = to_pad(hw); 309e1335e2fSThierry Reding struct tegra_sor *sor = pad->sor; 310b299221cSThierry Reding u8 parent = U8_MAX; 311b299221cSThierry Reding u32 value; 312b299221cSThierry Reding 313b299221cSThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 314b299221cSThierry Reding 315b299221cSThierry Reding switch (value & SOR_CLK_CNTRL_DP_CLK_SEL_MASK) { 316b299221cSThierry Reding case SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK: 317b299221cSThierry Reding case SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_PCLK: 318b299221cSThierry Reding parent = 0; 319b299221cSThierry Reding break; 320b299221cSThierry Reding 321b299221cSThierry Reding case SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK: 322b299221cSThierry Reding case SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_DPCLK: 323b299221cSThierry Reding parent = 1; 324b299221cSThierry Reding break; 325b299221cSThierry Reding } 326b299221cSThierry Reding 327b299221cSThierry Reding return parent; 328b299221cSThierry Reding } 329b299221cSThierry Reding 330e1335e2fSThierry Reding static const struct clk_ops tegra_clk_sor_pad_ops = { 331e1335e2fSThierry Reding .set_parent = tegra_clk_sor_pad_set_parent, 332e1335e2fSThierry Reding .get_parent = tegra_clk_sor_pad_get_parent, 333b299221cSThierry Reding }; 334b299221cSThierry Reding 335e1335e2fSThierry Reding static struct clk *tegra_clk_sor_pad_register(struct tegra_sor *sor, 336b299221cSThierry Reding const char *name) 337b299221cSThierry Reding { 338e1335e2fSThierry Reding struct tegra_clk_sor_pad *pad; 339b299221cSThierry Reding struct clk_init_data init; 340b299221cSThierry Reding struct clk *clk; 341b299221cSThierry Reding 342e1335e2fSThierry Reding pad = devm_kzalloc(sor->dev, sizeof(*pad), GFP_KERNEL); 343e1335e2fSThierry Reding if (!pad) 344b299221cSThierry Reding return ERR_PTR(-ENOMEM); 345b299221cSThierry Reding 346e1335e2fSThierry Reding pad->sor = sor; 347b299221cSThierry Reding 348b299221cSThierry Reding init.name = name; 349b299221cSThierry Reding init.flags = 0; 350e1335e2fSThierry Reding init.parent_names = tegra_clk_sor_pad_parents; 351e1335e2fSThierry Reding init.num_parents = ARRAY_SIZE(tegra_clk_sor_pad_parents); 352e1335e2fSThierry Reding init.ops = &tegra_clk_sor_pad_ops; 353b299221cSThierry Reding 354e1335e2fSThierry Reding pad->hw.init = &init; 355b299221cSThierry Reding 356e1335e2fSThierry Reding clk = devm_clk_register(sor->dev, &pad->hw); 357b299221cSThierry Reding 358b299221cSThierry Reding return clk; 359b299221cSThierry Reding } 360b299221cSThierry Reding 3616b6b6042SThierry Reding static int tegra_sor_dp_train_fast(struct tegra_sor *sor, 3626b6b6042SThierry Reding struct drm_dp_link *link) 3636b6b6042SThierry Reding { 3646b6b6042SThierry Reding unsigned int i; 3656b6b6042SThierry Reding u8 pattern; 36628fe2076SThierry Reding u32 value; 3676b6b6042SThierry Reding int err; 3686b6b6042SThierry Reding 3696b6b6042SThierry Reding /* setup lane parameters */ 3706b6b6042SThierry Reding value = SOR_LANE_DRIVE_CURRENT_LANE3(0x40) | 3716b6b6042SThierry Reding SOR_LANE_DRIVE_CURRENT_LANE2(0x40) | 3726b6b6042SThierry Reding SOR_LANE_DRIVE_CURRENT_LANE1(0x40) | 3736b6b6042SThierry Reding SOR_LANE_DRIVE_CURRENT_LANE0(0x40); 374a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_LANE_DRIVE_CURRENT0); 3756b6b6042SThierry Reding 3766b6b6042SThierry Reding value = SOR_LANE_PREEMPHASIS_LANE3(0x0f) | 3776b6b6042SThierry Reding SOR_LANE_PREEMPHASIS_LANE2(0x0f) | 3786b6b6042SThierry Reding SOR_LANE_PREEMPHASIS_LANE1(0x0f) | 3796b6b6042SThierry Reding SOR_LANE_PREEMPHASIS_LANE0(0x0f); 380a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_LANE_PREEMPHASIS0); 3816b6b6042SThierry Reding 382a9a9e4fdSThierry Reding value = SOR_LANE_POSTCURSOR_LANE3(0x00) | 383a9a9e4fdSThierry Reding SOR_LANE_POSTCURSOR_LANE2(0x00) | 384a9a9e4fdSThierry Reding SOR_LANE_POSTCURSOR_LANE1(0x00) | 385a9a9e4fdSThierry Reding SOR_LANE_POSTCURSOR_LANE0(0x00); 386a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_LANE_POSTCURSOR0); 3876b6b6042SThierry Reding 3886b6b6042SThierry Reding /* disable LVDS mode */ 3896b6b6042SThierry Reding tegra_sor_writel(sor, 0, SOR_LVDS); 3906b6b6042SThierry Reding 391a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 3926b6b6042SThierry Reding value |= SOR_DP_PADCTL_TX_PU_ENABLE; 3936b6b6042SThierry Reding value &= ~SOR_DP_PADCTL_TX_PU_MASK; 3946b6b6042SThierry Reding value |= SOR_DP_PADCTL_TX_PU(2); /* XXX: don't hardcode? */ 395a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 3966b6b6042SThierry Reding 397a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 3986b6b6042SThierry Reding value |= SOR_DP_PADCTL_CM_TXD_3 | SOR_DP_PADCTL_CM_TXD_2 | 3996b6b6042SThierry Reding SOR_DP_PADCTL_CM_TXD_1 | SOR_DP_PADCTL_CM_TXD_0; 400a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 4016b6b6042SThierry Reding 4026b6b6042SThierry Reding usleep_range(10, 100); 4036b6b6042SThierry Reding 404a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 4056b6b6042SThierry Reding value &= ~(SOR_DP_PADCTL_CM_TXD_3 | SOR_DP_PADCTL_CM_TXD_2 | 4066b6b6042SThierry Reding SOR_DP_PADCTL_CM_TXD_1 | SOR_DP_PADCTL_CM_TXD_0); 407a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 4086b6b6042SThierry Reding 4099542c237SThierry Reding err = drm_dp_aux_prepare(sor->aux, DP_SET_ANSI_8B10B); 4106b6b6042SThierry Reding if (err < 0) 4116b6b6042SThierry Reding return err; 4126b6b6042SThierry Reding 4136b6b6042SThierry Reding for (i = 0, value = 0; i < link->num_lanes; i++) { 4146b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 4156b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_NONE | 4166b6b6042SThierry Reding SOR_DP_TPG_PATTERN_TRAIN1; 4176b6b6042SThierry Reding value = (value << 8) | lane; 4186b6b6042SThierry Reding } 4196b6b6042SThierry Reding 4206b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 4216b6b6042SThierry Reding 4226b6b6042SThierry Reding pattern = DP_TRAINING_PATTERN_1; 4236b6b6042SThierry Reding 4249542c237SThierry Reding err = drm_dp_aux_train(sor->aux, link, pattern); 4256b6b6042SThierry Reding if (err < 0) 4266b6b6042SThierry Reding return err; 4276b6b6042SThierry Reding 428a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_SPARE0); 4296b6b6042SThierry Reding value |= SOR_DP_SPARE_SEQ_ENABLE; 4306b6b6042SThierry Reding value &= ~SOR_DP_SPARE_PANEL_INTERNAL; 4316b6b6042SThierry Reding value |= SOR_DP_SPARE_MACRO_SOR_CLK; 432a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_SPARE0); 4336b6b6042SThierry Reding 4346b6b6042SThierry Reding for (i = 0, value = 0; i < link->num_lanes; i++) { 4356b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 4366b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_NONE | 4376b6b6042SThierry Reding SOR_DP_TPG_PATTERN_TRAIN2; 4386b6b6042SThierry Reding value = (value << 8) | lane; 4396b6b6042SThierry Reding } 4406b6b6042SThierry Reding 4416b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 4426b6b6042SThierry Reding 4436b6b6042SThierry Reding pattern = DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_2; 4446b6b6042SThierry Reding 4459542c237SThierry Reding err = drm_dp_aux_train(sor->aux, link, pattern); 4466b6b6042SThierry Reding if (err < 0) 4476b6b6042SThierry Reding return err; 4486b6b6042SThierry Reding 4496b6b6042SThierry Reding for (i = 0, value = 0; i < link->num_lanes; i++) { 4506b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 4516b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_GALIOS | 4526b6b6042SThierry Reding SOR_DP_TPG_PATTERN_NONE; 4536b6b6042SThierry Reding value = (value << 8) | lane; 4546b6b6042SThierry Reding } 4556b6b6042SThierry Reding 4566b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 4576b6b6042SThierry Reding 4586b6b6042SThierry Reding pattern = DP_TRAINING_PATTERN_DISABLE; 4596b6b6042SThierry Reding 4609542c237SThierry Reding err = drm_dp_aux_train(sor->aux, link, pattern); 4616b6b6042SThierry Reding if (err < 0) 4626b6b6042SThierry Reding return err; 4636b6b6042SThierry Reding 4646b6b6042SThierry Reding return 0; 4656b6b6042SThierry Reding } 4666b6b6042SThierry Reding 467459cc2c6SThierry Reding static void tegra_sor_dp_term_calibrate(struct tegra_sor *sor) 468459cc2c6SThierry Reding { 469459cc2c6SThierry Reding u32 mask = 0x08, adj = 0, value; 470459cc2c6SThierry Reding 471459cc2c6SThierry Reding /* enable pad calibration logic */ 472459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 473459cc2c6SThierry Reding value &= ~SOR_DP_PADCTL_PAD_CAL_PD; 474459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 475459cc2c6SThierry Reding 476459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_PLL1); 477459cc2c6SThierry Reding value |= SOR_PLL1_TMDS_TERM; 478459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_PLL1); 479459cc2c6SThierry Reding 480459cc2c6SThierry Reding while (mask) { 481459cc2c6SThierry Reding adj |= mask; 482459cc2c6SThierry Reding 483459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_PLL1); 484459cc2c6SThierry Reding value &= ~SOR_PLL1_TMDS_TERMADJ_MASK; 485459cc2c6SThierry Reding value |= SOR_PLL1_TMDS_TERMADJ(adj); 486459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_PLL1); 487459cc2c6SThierry Reding 488459cc2c6SThierry Reding usleep_range(100, 200); 489459cc2c6SThierry Reding 490459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_PLL1); 491459cc2c6SThierry Reding if (value & SOR_PLL1_TERM_COMPOUT) 492459cc2c6SThierry Reding adj &= ~mask; 493459cc2c6SThierry Reding 494459cc2c6SThierry Reding mask >>= 1; 495459cc2c6SThierry Reding } 496459cc2c6SThierry Reding 497459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_PLL1); 498459cc2c6SThierry Reding value &= ~SOR_PLL1_TMDS_TERMADJ_MASK; 499459cc2c6SThierry Reding value |= SOR_PLL1_TMDS_TERMADJ(adj); 500459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_PLL1); 501459cc2c6SThierry Reding 502459cc2c6SThierry Reding /* disable pad calibration logic */ 503459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 504459cc2c6SThierry Reding value |= SOR_DP_PADCTL_PAD_CAL_PD; 505459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 506459cc2c6SThierry Reding } 507459cc2c6SThierry Reding 5086b6b6042SThierry Reding static void tegra_sor_super_update(struct tegra_sor *sor) 5096b6b6042SThierry Reding { 510a9a9e4fdSThierry Reding tegra_sor_writel(sor, 0, SOR_SUPER_STATE0); 511a9a9e4fdSThierry Reding tegra_sor_writel(sor, 1, SOR_SUPER_STATE0); 512a9a9e4fdSThierry Reding tegra_sor_writel(sor, 0, SOR_SUPER_STATE0); 5136b6b6042SThierry Reding } 5146b6b6042SThierry Reding 5156b6b6042SThierry Reding static void tegra_sor_update(struct tegra_sor *sor) 5166b6b6042SThierry Reding { 517a9a9e4fdSThierry Reding tegra_sor_writel(sor, 0, SOR_STATE0); 518a9a9e4fdSThierry Reding tegra_sor_writel(sor, 1, SOR_STATE0); 519a9a9e4fdSThierry Reding tegra_sor_writel(sor, 0, SOR_STATE0); 5206b6b6042SThierry Reding } 5216b6b6042SThierry Reding 5226b6b6042SThierry Reding static int tegra_sor_setup_pwm(struct tegra_sor *sor, unsigned long timeout) 5236b6b6042SThierry Reding { 52428fe2076SThierry Reding u32 value; 5256b6b6042SThierry Reding 5266b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWM_DIV); 5276b6b6042SThierry Reding value &= ~SOR_PWM_DIV_MASK; 5286b6b6042SThierry Reding value |= 0x400; /* period */ 5296b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PWM_DIV); 5306b6b6042SThierry Reding 5316b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWM_CTL); 5326b6b6042SThierry Reding value &= ~SOR_PWM_CTL_DUTY_CYCLE_MASK; 5336b6b6042SThierry Reding value |= 0x400; /* duty cycle */ 5346b6b6042SThierry Reding value &= ~SOR_PWM_CTL_CLK_SEL; /* clock source: PCLK */ 5356b6b6042SThierry Reding value |= SOR_PWM_CTL_TRIGGER; 5366b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PWM_CTL); 5376b6b6042SThierry Reding 5386b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(timeout); 5396b6b6042SThierry Reding 5406b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 5416b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWM_CTL); 5426b6b6042SThierry Reding if ((value & SOR_PWM_CTL_TRIGGER) == 0) 5436b6b6042SThierry Reding return 0; 5446b6b6042SThierry Reding 5456b6b6042SThierry Reding usleep_range(25, 100); 5466b6b6042SThierry Reding } 5476b6b6042SThierry Reding 5486b6b6042SThierry Reding return -ETIMEDOUT; 5496b6b6042SThierry Reding } 5506b6b6042SThierry Reding 5516b6b6042SThierry Reding static int tegra_sor_attach(struct tegra_sor *sor) 5526b6b6042SThierry Reding { 5536b6b6042SThierry Reding unsigned long value, timeout; 5546b6b6042SThierry Reding 5556b6b6042SThierry Reding /* wake up in normal mode */ 556a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE1); 5576b6b6042SThierry Reding value |= SOR_SUPER_STATE_HEAD_MODE_AWAKE; 5586b6b6042SThierry Reding value |= SOR_SUPER_STATE_MODE_NORMAL; 559a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE1); 5606b6b6042SThierry Reding tegra_sor_super_update(sor); 5616b6b6042SThierry Reding 5626b6b6042SThierry Reding /* attach */ 563a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE1); 5646b6b6042SThierry Reding value |= SOR_SUPER_STATE_ATTACHED; 565a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE1); 5666b6b6042SThierry Reding tegra_sor_super_update(sor); 5676b6b6042SThierry Reding 5686b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 5696b6b6042SThierry Reding 5706b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 5716b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_TEST); 5726b6b6042SThierry Reding if ((value & SOR_TEST_ATTACHED) != 0) 5736b6b6042SThierry Reding return 0; 5746b6b6042SThierry Reding 5756b6b6042SThierry Reding usleep_range(25, 100); 5766b6b6042SThierry Reding } 5776b6b6042SThierry Reding 5786b6b6042SThierry Reding return -ETIMEDOUT; 5796b6b6042SThierry Reding } 5806b6b6042SThierry Reding 5816b6b6042SThierry Reding static int tegra_sor_wakeup(struct tegra_sor *sor) 5826b6b6042SThierry Reding { 5836b6b6042SThierry Reding unsigned long value, timeout; 5846b6b6042SThierry Reding 5856b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 5866b6b6042SThierry Reding 5876b6b6042SThierry Reding /* wait for head to wake up */ 5886b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 5896b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_TEST); 5906b6b6042SThierry Reding value &= SOR_TEST_HEAD_MODE_MASK; 5916b6b6042SThierry Reding 5926b6b6042SThierry Reding if (value == SOR_TEST_HEAD_MODE_AWAKE) 5936b6b6042SThierry Reding return 0; 5946b6b6042SThierry Reding 5956b6b6042SThierry Reding usleep_range(25, 100); 5966b6b6042SThierry Reding } 5976b6b6042SThierry Reding 5986b6b6042SThierry Reding return -ETIMEDOUT; 5996b6b6042SThierry Reding } 6006b6b6042SThierry Reding 6016b6b6042SThierry Reding static int tegra_sor_power_up(struct tegra_sor *sor, unsigned long timeout) 6026b6b6042SThierry Reding { 60328fe2076SThierry Reding u32 value; 6046b6b6042SThierry Reding 6056b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 6066b6b6042SThierry Reding value |= SOR_PWR_TRIGGER | SOR_PWR_NORMAL_STATE_PU; 6076b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PWR); 6086b6b6042SThierry Reding 6096b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(timeout); 6106b6b6042SThierry Reding 6116b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 6126b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 6136b6b6042SThierry Reding if ((value & SOR_PWR_TRIGGER) == 0) 6146b6b6042SThierry Reding return 0; 6156b6b6042SThierry Reding 6166b6b6042SThierry Reding usleep_range(25, 100); 6176b6b6042SThierry Reding } 6186b6b6042SThierry Reding 6196b6b6042SThierry Reding return -ETIMEDOUT; 6206b6b6042SThierry Reding } 6216b6b6042SThierry Reding 62234fa183bSThierry Reding struct tegra_sor_params { 62334fa183bSThierry Reding /* number of link clocks per line */ 62434fa183bSThierry Reding unsigned int num_clocks; 62534fa183bSThierry Reding /* ratio between input and output */ 62634fa183bSThierry Reding u64 ratio; 62734fa183bSThierry Reding /* precision factor */ 62834fa183bSThierry Reding u64 precision; 62934fa183bSThierry Reding 63034fa183bSThierry Reding unsigned int active_polarity; 63134fa183bSThierry Reding unsigned int active_count; 63234fa183bSThierry Reding unsigned int active_frac; 63334fa183bSThierry Reding unsigned int tu_size; 63434fa183bSThierry Reding unsigned int error; 63534fa183bSThierry Reding }; 63634fa183bSThierry Reding 63734fa183bSThierry Reding static int tegra_sor_compute_params(struct tegra_sor *sor, 63834fa183bSThierry Reding struct tegra_sor_params *params, 63934fa183bSThierry Reding unsigned int tu_size) 64034fa183bSThierry Reding { 64134fa183bSThierry Reding u64 active_sym, active_count, frac, approx; 64234fa183bSThierry Reding u32 active_polarity, active_frac = 0; 64334fa183bSThierry Reding const u64 f = params->precision; 64434fa183bSThierry Reding s64 error; 64534fa183bSThierry Reding 64634fa183bSThierry Reding active_sym = params->ratio * tu_size; 64734fa183bSThierry Reding active_count = div_u64(active_sym, f) * f; 64834fa183bSThierry Reding frac = active_sym - active_count; 64934fa183bSThierry Reding 65034fa183bSThierry Reding /* fraction < 0.5 */ 65134fa183bSThierry Reding if (frac >= (f / 2)) { 65234fa183bSThierry Reding active_polarity = 1; 65334fa183bSThierry Reding frac = f - frac; 65434fa183bSThierry Reding } else { 65534fa183bSThierry Reding active_polarity = 0; 65634fa183bSThierry Reding } 65734fa183bSThierry Reding 65834fa183bSThierry Reding if (frac != 0) { 65934fa183bSThierry Reding frac = div_u64(f * f, frac); /* 1/fraction */ 66034fa183bSThierry Reding if (frac <= (15 * f)) { 66134fa183bSThierry Reding active_frac = div_u64(frac, f); 66234fa183bSThierry Reding 66334fa183bSThierry Reding /* round up */ 66434fa183bSThierry Reding if (active_polarity) 66534fa183bSThierry Reding active_frac++; 66634fa183bSThierry Reding } else { 66734fa183bSThierry Reding active_frac = active_polarity ? 1 : 15; 66834fa183bSThierry Reding } 66934fa183bSThierry Reding } 67034fa183bSThierry Reding 67134fa183bSThierry Reding if (active_frac == 1) 67234fa183bSThierry Reding active_polarity = 0; 67334fa183bSThierry Reding 67434fa183bSThierry Reding if (active_polarity == 1) { 67534fa183bSThierry Reding if (active_frac) { 67634fa183bSThierry Reding approx = active_count + (active_frac * (f - 1)) * f; 67734fa183bSThierry Reding approx = div_u64(approx, active_frac * f); 67834fa183bSThierry Reding } else { 67934fa183bSThierry Reding approx = active_count + f; 68034fa183bSThierry Reding } 68134fa183bSThierry Reding } else { 68234fa183bSThierry Reding if (active_frac) 68334fa183bSThierry Reding approx = active_count + div_u64(f, active_frac); 68434fa183bSThierry Reding else 68534fa183bSThierry Reding approx = active_count; 68634fa183bSThierry Reding } 68734fa183bSThierry Reding 68834fa183bSThierry Reding error = div_s64(active_sym - approx, tu_size); 68934fa183bSThierry Reding error *= params->num_clocks; 69034fa183bSThierry Reding 69179211c8eSAndrew Morton if (error <= 0 && abs(error) < params->error) { 69234fa183bSThierry Reding params->active_count = div_u64(active_count, f); 69334fa183bSThierry Reding params->active_polarity = active_polarity; 69434fa183bSThierry Reding params->active_frac = active_frac; 69579211c8eSAndrew Morton params->error = abs(error); 69634fa183bSThierry Reding params->tu_size = tu_size; 69734fa183bSThierry Reding 69834fa183bSThierry Reding if (error == 0) 69934fa183bSThierry Reding return true; 70034fa183bSThierry Reding } 70134fa183bSThierry Reding 70234fa183bSThierry Reding return false; 70334fa183bSThierry Reding } 70434fa183bSThierry Reding 705a198359eSThierry Reding static int tegra_sor_compute_config(struct tegra_sor *sor, 70680444495SThierry Reding const struct drm_display_mode *mode, 70734fa183bSThierry Reding struct tegra_sor_config *config, 70834fa183bSThierry Reding struct drm_dp_link *link) 70934fa183bSThierry Reding { 71034fa183bSThierry Reding const u64 f = 100000, link_rate = link->rate * 1000; 71134fa183bSThierry Reding const u64 pclk = mode->clock * 1000; 7127890b576SThierry Reding u64 input, output, watermark, num; 71334fa183bSThierry Reding struct tegra_sor_params params; 71434fa183bSThierry Reding u32 num_syms_per_line; 71534fa183bSThierry Reding unsigned int i; 71634fa183bSThierry Reding 71734fa183bSThierry Reding if (!link_rate || !link->num_lanes || !pclk || !config->bits_per_pixel) 71834fa183bSThierry Reding return -EINVAL; 71934fa183bSThierry Reding 72034fa183bSThierry Reding output = link_rate * 8 * link->num_lanes; 72134fa183bSThierry Reding input = pclk * config->bits_per_pixel; 72234fa183bSThierry Reding 72334fa183bSThierry Reding if (input >= output) 72434fa183bSThierry Reding return -ERANGE; 72534fa183bSThierry Reding 72634fa183bSThierry Reding memset(¶ms, 0, sizeof(params)); 72734fa183bSThierry Reding params.ratio = div64_u64(input * f, output); 72834fa183bSThierry Reding params.num_clocks = div_u64(link_rate * mode->hdisplay, pclk); 72934fa183bSThierry Reding params.precision = f; 73034fa183bSThierry Reding params.error = 64 * f; 73134fa183bSThierry Reding params.tu_size = 64; 73234fa183bSThierry Reding 73334fa183bSThierry Reding for (i = params.tu_size; i >= 32; i--) 73434fa183bSThierry Reding if (tegra_sor_compute_params(sor, ¶ms, i)) 73534fa183bSThierry Reding break; 73634fa183bSThierry Reding 73734fa183bSThierry Reding if (params.active_frac == 0) { 73834fa183bSThierry Reding config->active_polarity = 0; 73934fa183bSThierry Reding config->active_count = params.active_count; 74034fa183bSThierry Reding 74134fa183bSThierry Reding if (!params.active_polarity) 74234fa183bSThierry Reding config->active_count--; 74334fa183bSThierry Reding 74434fa183bSThierry Reding config->tu_size = params.tu_size; 74534fa183bSThierry Reding config->active_frac = 1; 74634fa183bSThierry Reding } else { 74734fa183bSThierry Reding config->active_polarity = params.active_polarity; 74834fa183bSThierry Reding config->active_count = params.active_count; 74934fa183bSThierry Reding config->active_frac = params.active_frac; 75034fa183bSThierry Reding config->tu_size = params.tu_size; 75134fa183bSThierry Reding } 75234fa183bSThierry Reding 75334fa183bSThierry Reding dev_dbg(sor->dev, 75434fa183bSThierry Reding "polarity: %d active count: %d tu size: %d active frac: %d\n", 75534fa183bSThierry Reding config->active_polarity, config->active_count, 75634fa183bSThierry Reding config->tu_size, config->active_frac); 75734fa183bSThierry Reding 75834fa183bSThierry Reding watermark = params.ratio * config->tu_size * (f - params.ratio); 75934fa183bSThierry Reding watermark = div_u64(watermark, f); 76034fa183bSThierry Reding 76134fa183bSThierry Reding watermark = div_u64(watermark + params.error, f); 76234fa183bSThierry Reding config->watermark = watermark + (config->bits_per_pixel / 8) + 2; 76334fa183bSThierry Reding num_syms_per_line = (mode->hdisplay * config->bits_per_pixel) * 76434fa183bSThierry Reding (link->num_lanes * 8); 76534fa183bSThierry Reding 76634fa183bSThierry Reding if (config->watermark > 30) { 76734fa183bSThierry Reding config->watermark = 30; 76834fa183bSThierry Reding dev_err(sor->dev, 76934fa183bSThierry Reding "unable to compute TU size, forcing watermark to %u\n", 77034fa183bSThierry Reding config->watermark); 77134fa183bSThierry Reding } else if (config->watermark > num_syms_per_line) { 77234fa183bSThierry Reding config->watermark = num_syms_per_line; 77334fa183bSThierry Reding dev_err(sor->dev, "watermark too high, forcing to %u\n", 77434fa183bSThierry Reding config->watermark); 77534fa183bSThierry Reding } 77634fa183bSThierry Reding 7777890b576SThierry Reding /* compute the number of symbols per horizontal blanking interval */ 7787890b576SThierry Reding num = ((mode->htotal - mode->hdisplay) - 7) * link_rate; 7797890b576SThierry Reding config->hblank_symbols = div_u64(num, pclk); 7807890b576SThierry Reding 7817890b576SThierry Reding if (link->capabilities & DP_LINK_CAP_ENHANCED_FRAMING) 7827890b576SThierry Reding config->hblank_symbols -= 3; 7837890b576SThierry Reding 7847890b576SThierry Reding config->hblank_symbols -= 12 / link->num_lanes; 7857890b576SThierry Reding 7867890b576SThierry Reding /* compute the number of symbols per vertical blanking interval */ 7877890b576SThierry Reding num = (mode->hdisplay - 25) * link_rate; 7887890b576SThierry Reding config->vblank_symbols = div_u64(num, pclk); 7897890b576SThierry Reding config->vblank_symbols -= 36 / link->num_lanes + 4; 7907890b576SThierry Reding 7917890b576SThierry Reding dev_dbg(sor->dev, "blank symbols: H:%u V:%u\n", config->hblank_symbols, 7927890b576SThierry Reding config->vblank_symbols); 7937890b576SThierry Reding 79434fa183bSThierry Reding return 0; 79534fa183bSThierry Reding } 79634fa183bSThierry Reding 797402f6bcdSThierry Reding static void tegra_sor_apply_config(struct tegra_sor *sor, 798402f6bcdSThierry Reding const struct tegra_sor_config *config) 799402f6bcdSThierry Reding { 800402f6bcdSThierry Reding u32 value; 801402f6bcdSThierry Reding 802402f6bcdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_LINKCTL0); 803402f6bcdSThierry Reding value &= ~SOR_DP_LINKCTL_TU_SIZE_MASK; 804402f6bcdSThierry Reding value |= SOR_DP_LINKCTL_TU_SIZE(config->tu_size); 805402f6bcdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_LINKCTL0); 806402f6bcdSThierry Reding 807402f6bcdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_CONFIG0); 808402f6bcdSThierry Reding value &= ~SOR_DP_CONFIG_WATERMARK_MASK; 809402f6bcdSThierry Reding value |= SOR_DP_CONFIG_WATERMARK(config->watermark); 810402f6bcdSThierry Reding 811402f6bcdSThierry Reding value &= ~SOR_DP_CONFIG_ACTIVE_SYM_COUNT_MASK; 812402f6bcdSThierry Reding value |= SOR_DP_CONFIG_ACTIVE_SYM_COUNT(config->active_count); 813402f6bcdSThierry Reding 814402f6bcdSThierry Reding value &= ~SOR_DP_CONFIG_ACTIVE_SYM_FRAC_MASK; 815402f6bcdSThierry Reding value |= SOR_DP_CONFIG_ACTIVE_SYM_FRAC(config->active_frac); 816402f6bcdSThierry Reding 817402f6bcdSThierry Reding if (config->active_polarity) 818402f6bcdSThierry Reding value |= SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; 819402f6bcdSThierry Reding else 820402f6bcdSThierry Reding value &= ~SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; 821402f6bcdSThierry Reding 822402f6bcdSThierry Reding value |= SOR_DP_CONFIG_ACTIVE_SYM_ENABLE; 823402f6bcdSThierry Reding value |= SOR_DP_CONFIG_DISPARITY_NEGATIVE; 824402f6bcdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_CONFIG0); 825402f6bcdSThierry Reding 826402f6bcdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_AUDIO_HBLANK_SYMBOLS); 827402f6bcdSThierry Reding value &= ~SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK; 828402f6bcdSThierry Reding value |= config->hblank_symbols & 0xffff; 829402f6bcdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_AUDIO_HBLANK_SYMBOLS); 830402f6bcdSThierry Reding 831402f6bcdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_AUDIO_VBLANK_SYMBOLS); 832402f6bcdSThierry Reding value &= ~SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK; 833402f6bcdSThierry Reding value |= config->vblank_symbols & 0xffff; 834402f6bcdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_AUDIO_VBLANK_SYMBOLS); 835402f6bcdSThierry Reding } 836402f6bcdSThierry Reding 8372bd1dd39SThierry Reding static void tegra_sor_mode_set(struct tegra_sor *sor, 8382bd1dd39SThierry Reding const struct drm_display_mode *mode, 839c31efa7aSThierry Reding struct tegra_sor_state *state) 8402bd1dd39SThierry Reding { 8412bd1dd39SThierry Reding struct tegra_dc *dc = to_tegra_dc(sor->output.encoder.crtc); 8422bd1dd39SThierry Reding unsigned int vbe, vse, hbe, hse, vbs, hbs; 8432bd1dd39SThierry Reding u32 value; 8442bd1dd39SThierry Reding 8452bd1dd39SThierry Reding value = tegra_sor_readl(sor, SOR_STATE1); 8462bd1dd39SThierry Reding value &= ~SOR_STATE_ASY_PIXELDEPTH_MASK; 8472bd1dd39SThierry Reding value &= ~SOR_STATE_ASY_CRC_MODE_MASK; 8482bd1dd39SThierry Reding value &= ~SOR_STATE_ASY_OWNER_MASK; 8492bd1dd39SThierry Reding 8502bd1dd39SThierry Reding value |= SOR_STATE_ASY_CRC_MODE_COMPLETE | 8512bd1dd39SThierry Reding SOR_STATE_ASY_OWNER(dc->pipe + 1); 8522bd1dd39SThierry Reding 8532bd1dd39SThierry Reding if (mode->flags & DRM_MODE_FLAG_PHSYNC) 8542bd1dd39SThierry Reding value &= ~SOR_STATE_ASY_HSYNCPOL; 8552bd1dd39SThierry Reding 8562bd1dd39SThierry Reding if (mode->flags & DRM_MODE_FLAG_NHSYNC) 8572bd1dd39SThierry Reding value |= SOR_STATE_ASY_HSYNCPOL; 8582bd1dd39SThierry Reding 8592bd1dd39SThierry Reding if (mode->flags & DRM_MODE_FLAG_PVSYNC) 8602bd1dd39SThierry Reding value &= ~SOR_STATE_ASY_VSYNCPOL; 8612bd1dd39SThierry Reding 8622bd1dd39SThierry Reding if (mode->flags & DRM_MODE_FLAG_NVSYNC) 8632bd1dd39SThierry Reding value |= SOR_STATE_ASY_VSYNCPOL; 8642bd1dd39SThierry Reding 865c31efa7aSThierry Reding switch (state->bpc) { 866c31efa7aSThierry Reding case 16: 867c31efa7aSThierry Reding value |= SOR_STATE_ASY_PIXELDEPTH_BPP_48_444; 868c31efa7aSThierry Reding break; 869c31efa7aSThierry Reding 870c31efa7aSThierry Reding case 12: 871c31efa7aSThierry Reding value |= SOR_STATE_ASY_PIXELDEPTH_BPP_36_444; 872c31efa7aSThierry Reding break; 873c31efa7aSThierry Reding 874c31efa7aSThierry Reding case 10: 875c31efa7aSThierry Reding value |= SOR_STATE_ASY_PIXELDEPTH_BPP_30_444; 876c31efa7aSThierry Reding break; 877c31efa7aSThierry Reding 8782bd1dd39SThierry Reding case 8: 8792bd1dd39SThierry Reding value |= SOR_STATE_ASY_PIXELDEPTH_BPP_24_444; 8802bd1dd39SThierry Reding break; 8812bd1dd39SThierry Reding 8822bd1dd39SThierry Reding case 6: 8832bd1dd39SThierry Reding value |= SOR_STATE_ASY_PIXELDEPTH_BPP_18_444; 8842bd1dd39SThierry Reding break; 8852bd1dd39SThierry Reding 8862bd1dd39SThierry Reding default: 887c31efa7aSThierry Reding value |= SOR_STATE_ASY_PIXELDEPTH_BPP_24_444; 8882bd1dd39SThierry Reding break; 8892bd1dd39SThierry Reding } 8902bd1dd39SThierry Reding 8912bd1dd39SThierry Reding tegra_sor_writel(sor, value, SOR_STATE1); 8922bd1dd39SThierry Reding 8932bd1dd39SThierry Reding /* 8942bd1dd39SThierry Reding * TODO: The video timing programming below doesn't seem to match the 8952bd1dd39SThierry Reding * register definitions. 8962bd1dd39SThierry Reding */ 8972bd1dd39SThierry Reding 8982bd1dd39SThierry Reding value = ((mode->vtotal & 0x7fff) << 16) | (mode->htotal & 0x7fff); 8992bd1dd39SThierry Reding tegra_sor_writel(sor, value, SOR_HEAD_STATE1(dc->pipe)); 9002bd1dd39SThierry Reding 9012bd1dd39SThierry Reding /* sync end = sync width - 1 */ 9022bd1dd39SThierry Reding vse = mode->vsync_end - mode->vsync_start - 1; 9032bd1dd39SThierry Reding hse = mode->hsync_end - mode->hsync_start - 1; 9042bd1dd39SThierry Reding 9052bd1dd39SThierry Reding value = ((vse & 0x7fff) << 16) | (hse & 0x7fff); 9062bd1dd39SThierry Reding tegra_sor_writel(sor, value, SOR_HEAD_STATE2(dc->pipe)); 9072bd1dd39SThierry Reding 9082bd1dd39SThierry Reding /* blank end = sync end + back porch */ 9092bd1dd39SThierry Reding vbe = vse + (mode->vtotal - mode->vsync_end); 9102bd1dd39SThierry Reding hbe = hse + (mode->htotal - mode->hsync_end); 9112bd1dd39SThierry Reding 9122bd1dd39SThierry Reding value = ((vbe & 0x7fff) << 16) | (hbe & 0x7fff); 9132bd1dd39SThierry Reding tegra_sor_writel(sor, value, SOR_HEAD_STATE3(dc->pipe)); 9142bd1dd39SThierry Reding 9152bd1dd39SThierry Reding /* blank start = blank end + active */ 9162bd1dd39SThierry Reding vbs = vbe + mode->vdisplay; 9172bd1dd39SThierry Reding hbs = hbe + mode->hdisplay; 9182bd1dd39SThierry Reding 9192bd1dd39SThierry Reding value = ((vbs & 0x7fff) << 16) | (hbs & 0x7fff); 9202bd1dd39SThierry Reding tegra_sor_writel(sor, value, SOR_HEAD_STATE4(dc->pipe)); 9212bd1dd39SThierry Reding 9222bd1dd39SThierry Reding /* XXX interlacing support */ 9232bd1dd39SThierry Reding tegra_sor_writel(sor, 0x001, SOR_HEAD_STATE5(dc->pipe)); 9242bd1dd39SThierry Reding } 9252bd1dd39SThierry Reding 9266fad8f66SThierry Reding static int tegra_sor_detach(struct tegra_sor *sor) 9276b6b6042SThierry Reding { 9286fad8f66SThierry Reding unsigned long value, timeout; 9296fad8f66SThierry Reding 9306fad8f66SThierry Reding /* switch to safe mode */ 931a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE1); 9326fad8f66SThierry Reding value &= ~SOR_SUPER_STATE_MODE_NORMAL; 933a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE1); 9346fad8f66SThierry Reding tegra_sor_super_update(sor); 9356fad8f66SThierry Reding 9366fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 9376fad8f66SThierry Reding 9386fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 9396fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 9406fad8f66SThierry Reding if (value & SOR_PWR_MODE_SAFE) 9416fad8f66SThierry Reding break; 9426fad8f66SThierry Reding } 9436fad8f66SThierry Reding 9446fad8f66SThierry Reding if ((value & SOR_PWR_MODE_SAFE) == 0) 9456fad8f66SThierry Reding return -ETIMEDOUT; 9466fad8f66SThierry Reding 9476fad8f66SThierry Reding /* go to sleep */ 948a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE1); 9496fad8f66SThierry Reding value &= ~SOR_SUPER_STATE_HEAD_MODE_MASK; 950a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE1); 9516fad8f66SThierry Reding tegra_sor_super_update(sor); 9526fad8f66SThierry Reding 9536fad8f66SThierry Reding /* detach */ 954a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE1); 9556fad8f66SThierry Reding value &= ~SOR_SUPER_STATE_ATTACHED; 956a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE1); 9576fad8f66SThierry Reding tegra_sor_super_update(sor); 9586fad8f66SThierry Reding 9596fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 9606fad8f66SThierry Reding 9616fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 9626fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_TEST); 9636fad8f66SThierry Reding if ((value & SOR_TEST_ATTACHED) == 0) 9646fad8f66SThierry Reding break; 9656fad8f66SThierry Reding 9666fad8f66SThierry Reding usleep_range(25, 100); 9676fad8f66SThierry Reding } 9686fad8f66SThierry Reding 9696fad8f66SThierry Reding if ((value & SOR_TEST_ATTACHED) != 0) 9706fad8f66SThierry Reding return -ETIMEDOUT; 9716fad8f66SThierry Reding 9726fad8f66SThierry Reding return 0; 9736fad8f66SThierry Reding } 9746fad8f66SThierry Reding 9756fad8f66SThierry Reding static int tegra_sor_power_down(struct tegra_sor *sor) 9766fad8f66SThierry Reding { 9776fad8f66SThierry Reding unsigned long value, timeout; 9786fad8f66SThierry Reding int err; 9796fad8f66SThierry Reding 9806fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 9816fad8f66SThierry Reding value &= ~SOR_PWR_NORMAL_STATE_PU; 9826fad8f66SThierry Reding value |= SOR_PWR_TRIGGER; 9836fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_PWR); 9846fad8f66SThierry Reding 9856fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 9866fad8f66SThierry Reding 9876fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 9886fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 9896fad8f66SThierry Reding if ((value & SOR_PWR_TRIGGER) == 0) 9906fad8f66SThierry Reding return 0; 9916fad8f66SThierry Reding 9926fad8f66SThierry Reding usleep_range(25, 100); 9936fad8f66SThierry Reding } 9946fad8f66SThierry Reding 9956fad8f66SThierry Reding if ((value & SOR_PWR_TRIGGER) != 0) 9966fad8f66SThierry Reding return -ETIMEDOUT; 9976fad8f66SThierry Reding 99825bb2cecSThierry Reding /* switch to safe parent clock */ 99925bb2cecSThierry Reding err = tegra_sor_set_parent_clock(sor, sor->clk_safe); 1000e1335e2fSThierry Reding if (err < 0) { 10016fad8f66SThierry Reding dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); 1002e1335e2fSThierry Reding return err; 1003e1335e2fSThierry Reding } 10046fad8f66SThierry Reding 1005a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 10066fad8f66SThierry Reding value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 | 10076fad8f66SThierry Reding SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2); 1008a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 10096fad8f66SThierry Reding 10106fad8f66SThierry Reding /* stop lane sequencer */ 10116fad8f66SThierry Reding value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_UP | 10126fad8f66SThierry Reding SOR_LANE_SEQ_CTL_POWER_STATE_DOWN; 10136fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL); 10146fad8f66SThierry Reding 10156fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 10166fad8f66SThierry Reding 10176fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 10186fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL); 10196fad8f66SThierry Reding if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0) 10206fad8f66SThierry Reding break; 10216fad8f66SThierry Reding 10226fad8f66SThierry Reding usleep_range(25, 100); 10236fad8f66SThierry Reding } 10246fad8f66SThierry Reding 10256fad8f66SThierry Reding if ((value & SOR_LANE_SEQ_CTL_TRIGGER) != 0) 10266fad8f66SThierry Reding return -ETIMEDOUT; 10276fad8f66SThierry Reding 1028a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 1029a9a9e4fdSThierry Reding value |= SOR_PLL2_PORT_POWERDOWN; 1030a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 10316fad8f66SThierry Reding 10326fad8f66SThierry Reding usleep_range(20, 100); 10336fad8f66SThierry Reding 1034a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL0); 1035a9a9e4fdSThierry Reding value |= SOR_PLL0_VCOPD | SOR_PLL0_PWR; 1036a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL0); 10376fad8f66SThierry Reding 1038a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 1039a9a9e4fdSThierry Reding value |= SOR_PLL2_SEQ_PLLCAPPD; 1040a9a9e4fdSThierry Reding value |= SOR_PLL2_SEQ_PLLCAPPD_ENFORCE; 1041a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 10426fad8f66SThierry Reding 10436fad8f66SThierry Reding usleep_range(20, 100); 10446fad8f66SThierry Reding 10456fad8f66SThierry Reding return 0; 10466fad8f66SThierry Reding } 10476fad8f66SThierry Reding 10486fad8f66SThierry Reding static int tegra_sor_crc_wait(struct tegra_sor *sor, unsigned long timeout) 10496fad8f66SThierry Reding { 10506fad8f66SThierry Reding u32 value; 10516fad8f66SThierry Reding 10526fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(timeout); 10536fad8f66SThierry Reding 10546fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 1055a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_CRCA); 1056a9a9e4fdSThierry Reding if (value & SOR_CRCA_VALID) 10576fad8f66SThierry Reding return 0; 10586fad8f66SThierry Reding 10596fad8f66SThierry Reding usleep_range(100, 200); 10606fad8f66SThierry Reding } 10616fad8f66SThierry Reding 10626fad8f66SThierry Reding return -ETIMEDOUT; 10636fad8f66SThierry Reding } 10646fad8f66SThierry Reding 1065530239a8SThierry Reding static int tegra_sor_show_crc(struct seq_file *s, void *data) 10666fad8f66SThierry Reding { 1067530239a8SThierry Reding struct drm_info_node *node = s->private; 1068530239a8SThierry Reding struct tegra_sor *sor = node->info_ent->data; 1069850bab44SThierry Reding struct drm_crtc *crtc = sor->output.encoder.crtc; 1070850bab44SThierry Reding struct drm_device *drm = node->minor->dev; 1071530239a8SThierry Reding int err = 0; 10726fad8f66SThierry Reding u32 value; 10736fad8f66SThierry Reding 1074850bab44SThierry Reding drm_modeset_lock_all(drm); 10756fad8f66SThierry Reding 1076850bab44SThierry Reding if (!crtc || !crtc->state->active) { 1077850bab44SThierry Reding err = -EBUSY; 10786fad8f66SThierry Reding goto unlock; 10796fad8f66SThierry Reding } 10806fad8f66SThierry Reding 1081a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_STATE1); 10826fad8f66SThierry Reding value &= ~SOR_STATE_ASY_CRC_MODE_MASK; 1083a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_STATE1); 10846fad8f66SThierry Reding 10856fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_CRC_CNTRL); 10866fad8f66SThierry Reding value |= SOR_CRC_CNTRL_ENABLE; 10876fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_CRC_CNTRL); 10886fad8f66SThierry Reding 10896fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_TEST); 10906fad8f66SThierry Reding value &= ~SOR_TEST_CRC_POST_SERIALIZE; 10916fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_TEST); 10926fad8f66SThierry Reding 10936fad8f66SThierry Reding err = tegra_sor_crc_wait(sor, 100); 10946fad8f66SThierry Reding if (err < 0) 10956fad8f66SThierry Reding goto unlock; 10966fad8f66SThierry Reding 1097a9a9e4fdSThierry Reding tegra_sor_writel(sor, SOR_CRCA_RESET, SOR_CRCA); 1098a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_CRCB); 10996fad8f66SThierry Reding 1100530239a8SThierry Reding seq_printf(s, "%08x\n", value); 11016fad8f66SThierry Reding 11026fad8f66SThierry Reding unlock: 1103850bab44SThierry Reding drm_modeset_unlock_all(drm); 11046fad8f66SThierry Reding return err; 11056fad8f66SThierry Reding } 11066fad8f66SThierry Reding 1107062f5b2cSThierry Reding #define DEBUGFS_REG32(_name) { .name = #_name, .offset = _name } 1108062f5b2cSThierry Reding 1109062f5b2cSThierry Reding static const struct debugfs_reg32 tegra_sor_regs[] = { 1110062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CTXSW), 1111062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SUPER_STATE0), 1112062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SUPER_STATE1), 1113062f5b2cSThierry Reding DEBUGFS_REG32(SOR_STATE0), 1114062f5b2cSThierry Reding DEBUGFS_REG32(SOR_STATE1), 1115062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE0(0)), 1116062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE0(1)), 1117062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE1(0)), 1118062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE1(1)), 1119062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE2(0)), 1120062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE2(1)), 1121062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE3(0)), 1122062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE3(1)), 1123062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE4(0)), 1124062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE4(1)), 1125062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE5(0)), 1126062f5b2cSThierry Reding DEBUGFS_REG32(SOR_HEAD_STATE5(1)), 1127062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CRC_CNTRL), 1128062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_DEBUG_MVID), 1129062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CLK_CNTRL), 1130062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CAP), 1131062f5b2cSThierry Reding DEBUGFS_REG32(SOR_PWR), 1132062f5b2cSThierry Reding DEBUGFS_REG32(SOR_TEST), 1133062f5b2cSThierry Reding DEBUGFS_REG32(SOR_PLL0), 1134062f5b2cSThierry Reding DEBUGFS_REG32(SOR_PLL1), 1135062f5b2cSThierry Reding DEBUGFS_REG32(SOR_PLL2), 1136062f5b2cSThierry Reding DEBUGFS_REG32(SOR_PLL3), 1137062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CSTM), 1138062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LVDS), 1139062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CRCA), 1140062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CRCB), 1141062f5b2cSThierry Reding DEBUGFS_REG32(SOR_BLANK), 1142062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_CTL), 1143062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE_SEQ_CTL), 1144062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(0)), 1145062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(1)), 1146062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(2)), 1147062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(3)), 1148062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(4)), 1149062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(5)), 1150062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(6)), 1151062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(7)), 1152062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(8)), 1153062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(9)), 1154062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(10)), 1155062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(11)), 1156062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(12)), 1157062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(13)), 1158062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(14)), 1159062f5b2cSThierry Reding DEBUGFS_REG32(SOR_SEQ_INST(15)), 1160062f5b2cSThierry Reding DEBUGFS_REG32(SOR_PWM_DIV), 1161062f5b2cSThierry Reding DEBUGFS_REG32(SOR_PWM_CTL), 1162062f5b2cSThierry Reding DEBUGFS_REG32(SOR_VCRC_A0), 1163062f5b2cSThierry Reding DEBUGFS_REG32(SOR_VCRC_A1), 1164062f5b2cSThierry Reding DEBUGFS_REG32(SOR_VCRC_B0), 1165062f5b2cSThierry Reding DEBUGFS_REG32(SOR_VCRC_B1), 1166062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CCRC_A0), 1167062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CCRC_A1), 1168062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CCRC_B0), 1169062f5b2cSThierry Reding DEBUGFS_REG32(SOR_CCRC_B1), 1170062f5b2cSThierry Reding DEBUGFS_REG32(SOR_EDATA_A0), 1171062f5b2cSThierry Reding DEBUGFS_REG32(SOR_EDATA_A1), 1172062f5b2cSThierry Reding DEBUGFS_REG32(SOR_EDATA_B0), 1173062f5b2cSThierry Reding DEBUGFS_REG32(SOR_EDATA_B1), 1174062f5b2cSThierry Reding DEBUGFS_REG32(SOR_COUNT_A0), 1175062f5b2cSThierry Reding DEBUGFS_REG32(SOR_COUNT_A1), 1176062f5b2cSThierry Reding DEBUGFS_REG32(SOR_COUNT_B0), 1177062f5b2cSThierry Reding DEBUGFS_REG32(SOR_COUNT_B1), 1178062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DEBUG_A0), 1179062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DEBUG_A1), 1180062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DEBUG_B0), 1181062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DEBUG_B1), 1182062f5b2cSThierry Reding DEBUGFS_REG32(SOR_TRIG), 1183062f5b2cSThierry Reding DEBUGFS_REG32(SOR_MSCHECK), 1184062f5b2cSThierry Reding DEBUGFS_REG32(SOR_XBAR_CTRL), 1185062f5b2cSThierry Reding DEBUGFS_REG32(SOR_XBAR_POL), 1186062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_LINKCTL0), 1187062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_LINKCTL1), 1188062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE_DRIVE_CURRENT0), 1189062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE_DRIVE_CURRENT1), 1190062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE4_DRIVE_CURRENT0), 1191062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE4_DRIVE_CURRENT1), 1192062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE_PREEMPHASIS0), 1193062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE_PREEMPHASIS1), 1194062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE4_PREEMPHASIS0), 1195062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE4_PREEMPHASIS1), 1196062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE_POSTCURSOR0), 1197062f5b2cSThierry Reding DEBUGFS_REG32(SOR_LANE_POSTCURSOR1), 1198062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_CONFIG0), 1199062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_CONFIG1), 1200062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_MN0), 1201062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_MN1), 1202062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_PADCTL0), 1203062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_PADCTL1), 1204062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_DEBUG0), 1205062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_DEBUG1), 1206062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_SPARE0), 1207062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_SPARE1), 1208062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_AUDIO_CTRL), 1209062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_AUDIO_HBLANK_SYMBOLS), 1210062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_AUDIO_VBLANK_SYMBOLS), 1211062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_GENERIC_INFOFRAME_HEADER), 1212062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_GENERIC_INFOFRAME_SUBPACK0), 1213062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_GENERIC_INFOFRAME_SUBPACK1), 1214062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_GENERIC_INFOFRAME_SUBPACK2), 1215062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_GENERIC_INFOFRAME_SUBPACK3), 1216062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_GENERIC_INFOFRAME_SUBPACK4), 1217062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_GENERIC_INFOFRAME_SUBPACK5), 1218062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_GENERIC_INFOFRAME_SUBPACK6), 1219062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_TPG), 1220062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_TPG_CONFIG), 1221062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_LQ_CSTM0), 1222062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_LQ_CSTM1), 1223062f5b2cSThierry Reding DEBUGFS_REG32(SOR_DP_LQ_CSTM2), 1224062f5b2cSThierry Reding }; 1225062f5b2cSThierry Reding 1226dab16336SThierry Reding static int tegra_sor_show_regs(struct seq_file *s, void *data) 1227dab16336SThierry Reding { 1228dab16336SThierry Reding struct drm_info_node *node = s->private; 1229dab16336SThierry Reding struct tegra_sor *sor = node->info_ent->data; 1230850bab44SThierry Reding struct drm_crtc *crtc = sor->output.encoder.crtc; 1231850bab44SThierry Reding struct drm_device *drm = node->minor->dev; 1232062f5b2cSThierry Reding unsigned int i; 1233850bab44SThierry Reding int err = 0; 1234850bab44SThierry Reding 1235850bab44SThierry Reding drm_modeset_lock_all(drm); 1236850bab44SThierry Reding 1237850bab44SThierry Reding if (!crtc || !crtc->state->active) { 1238850bab44SThierry Reding err = -EBUSY; 1239850bab44SThierry Reding goto unlock; 1240850bab44SThierry Reding } 1241dab16336SThierry Reding 1242062f5b2cSThierry Reding for (i = 0; i < ARRAY_SIZE(tegra_sor_regs); i++) { 1243062f5b2cSThierry Reding unsigned int offset = tegra_sor_regs[i].offset; 1244dab16336SThierry Reding 1245062f5b2cSThierry Reding seq_printf(s, "%-38s %#05x %08x\n", tegra_sor_regs[i].name, 1246062f5b2cSThierry Reding offset, tegra_sor_readl(sor, offset)); 1247062f5b2cSThierry Reding } 1248dab16336SThierry Reding 1249850bab44SThierry Reding unlock: 1250850bab44SThierry Reding drm_modeset_unlock_all(drm); 1251850bab44SThierry Reding return err; 1252dab16336SThierry Reding } 1253dab16336SThierry Reding 1254dab16336SThierry Reding static const struct drm_info_list debugfs_files[] = { 1255530239a8SThierry Reding { "crc", tegra_sor_show_crc, 0, NULL }, 1256dab16336SThierry Reding { "regs", tegra_sor_show_regs, 0, NULL }, 1257dab16336SThierry Reding }; 1258dab16336SThierry Reding 12596fad8f66SThierry Reding static int tegra_sor_debugfs_init(struct tegra_sor *sor, 12606fad8f66SThierry Reding struct drm_minor *minor) 12616fad8f66SThierry Reding { 1262*d92e6009SThierry Reding struct dentry *root = sor->output.connector.debugfs_entry; 1263dab16336SThierry Reding unsigned int i; 1264530239a8SThierry Reding int err; 12656fad8f66SThierry Reding 1266dab16336SThierry Reding sor->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files), 1267dab16336SThierry Reding GFP_KERNEL); 1268dab16336SThierry Reding if (!sor->debugfs_files) { 12696fad8f66SThierry Reding err = -ENOMEM; 12706fad8f66SThierry Reding goto remove; 12716fad8f66SThierry Reding } 12726fad8f66SThierry Reding 1273dab16336SThierry Reding for (i = 0; i < ARRAY_SIZE(debugfs_files); i++) 1274dab16336SThierry Reding sor->debugfs_files[i].data = sor; 1275dab16336SThierry Reding 1276dab16336SThierry Reding err = drm_debugfs_create_files(sor->debugfs_files, 1277dab16336SThierry Reding ARRAY_SIZE(debugfs_files), 1278*d92e6009SThierry Reding root, minor); 1279dab16336SThierry Reding if (err < 0) 1280dab16336SThierry Reding goto free; 1281dab16336SThierry Reding 12823ff1f22cSThierry Reding sor->minor = minor; 12833ff1f22cSThierry Reding 1284530239a8SThierry Reding return 0; 12856fad8f66SThierry Reding 1286dab16336SThierry Reding free: 1287dab16336SThierry Reding kfree(sor->debugfs_files); 1288dab16336SThierry Reding sor->debugfs_files = NULL; 12896fad8f66SThierry Reding remove: 1290*d92e6009SThierry Reding debugfs_remove_recursive(root); 12916fad8f66SThierry Reding return err; 12926fad8f66SThierry Reding } 12936fad8f66SThierry Reding 12944009c224SThierry Reding static void tegra_sor_debugfs_exit(struct tegra_sor *sor) 12956fad8f66SThierry Reding { 1296*d92e6009SThierry Reding struct dentry *root = sor->output.connector.debugfs_entry; 1297*d92e6009SThierry Reding 1298dab16336SThierry Reding drm_debugfs_remove_files(sor->debugfs_files, ARRAY_SIZE(debugfs_files), 1299dab16336SThierry Reding sor->minor); 1300dab16336SThierry Reding sor->minor = NULL; 1301dab16336SThierry Reding 1302dab16336SThierry Reding kfree(sor->debugfs_files); 1303066d30f8SThierry Reding sor->debugfs_files = NULL; 1304dab16336SThierry Reding 1305*d92e6009SThierry Reding debugfs_remove_recursive(root); 13066fad8f66SThierry Reding } 13076fad8f66SThierry Reding 1308c31efa7aSThierry Reding static void tegra_sor_connector_reset(struct drm_connector *connector) 1309c31efa7aSThierry Reding { 1310c31efa7aSThierry Reding struct tegra_sor_state *state; 1311c31efa7aSThierry Reding 1312c31efa7aSThierry Reding state = kzalloc(sizeof(*state), GFP_KERNEL); 1313c31efa7aSThierry Reding if (!state) 1314c31efa7aSThierry Reding return; 1315c31efa7aSThierry Reding 1316c31efa7aSThierry Reding if (connector->state) { 1317c31efa7aSThierry Reding __drm_atomic_helper_connector_destroy_state(connector->state); 1318c31efa7aSThierry Reding kfree(connector->state); 1319c31efa7aSThierry Reding } 1320c31efa7aSThierry Reding 1321c31efa7aSThierry Reding __drm_atomic_helper_connector_reset(connector, &state->base); 1322c31efa7aSThierry Reding } 1323c31efa7aSThierry Reding 13246fad8f66SThierry Reding static enum drm_connector_status 13256fad8f66SThierry Reding tegra_sor_connector_detect(struct drm_connector *connector, bool force) 13266fad8f66SThierry Reding { 13276fad8f66SThierry Reding struct tegra_output *output = connector_to_output(connector); 13286fad8f66SThierry Reding struct tegra_sor *sor = to_sor(output); 13296fad8f66SThierry Reding 13309542c237SThierry Reding if (sor->aux) 13319542c237SThierry Reding return drm_dp_aux_detect(sor->aux); 13326fad8f66SThierry Reding 1333459cc2c6SThierry Reding return tegra_output_connector_detect(connector, force); 13346fad8f66SThierry Reding } 13356fad8f66SThierry Reding 1336c31efa7aSThierry Reding static struct drm_connector_state * 1337c31efa7aSThierry Reding tegra_sor_connector_duplicate_state(struct drm_connector *connector) 1338c31efa7aSThierry Reding { 1339c31efa7aSThierry Reding struct tegra_sor_state *state = to_sor_state(connector->state); 1340c31efa7aSThierry Reding struct tegra_sor_state *copy; 1341c31efa7aSThierry Reding 1342c31efa7aSThierry Reding copy = kmemdup(state, sizeof(*state), GFP_KERNEL); 1343c31efa7aSThierry Reding if (!copy) 1344c31efa7aSThierry Reding return NULL; 1345c31efa7aSThierry Reding 1346c31efa7aSThierry Reding __drm_atomic_helper_connector_duplicate_state(connector, ©->base); 1347c31efa7aSThierry Reding 1348c31efa7aSThierry Reding return ©->base; 1349c31efa7aSThierry Reding } 1350c31efa7aSThierry Reding 13516fad8f66SThierry Reding static const struct drm_connector_funcs tegra_sor_connector_funcs = { 1352c31efa7aSThierry Reding .reset = tegra_sor_connector_reset, 13536fad8f66SThierry Reding .detect = tegra_sor_connector_detect, 13546fad8f66SThierry Reding .fill_modes = drm_helper_probe_single_connector_modes, 13556fad8f66SThierry Reding .destroy = tegra_output_connector_destroy, 1356c31efa7aSThierry Reding .atomic_duplicate_state = tegra_sor_connector_duplicate_state, 13574aa3df71SThierry Reding .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 13586fad8f66SThierry Reding }; 13596fad8f66SThierry Reding 13606fad8f66SThierry Reding static int tegra_sor_connector_get_modes(struct drm_connector *connector) 13616fad8f66SThierry Reding { 13626fad8f66SThierry Reding struct tegra_output *output = connector_to_output(connector); 13636fad8f66SThierry Reding struct tegra_sor *sor = to_sor(output); 13646fad8f66SThierry Reding int err; 13656fad8f66SThierry Reding 13669542c237SThierry Reding if (sor->aux) 13679542c237SThierry Reding drm_dp_aux_enable(sor->aux); 13686fad8f66SThierry Reding 13696fad8f66SThierry Reding err = tegra_output_connector_get_modes(connector); 13706fad8f66SThierry Reding 13719542c237SThierry Reding if (sor->aux) 13729542c237SThierry Reding drm_dp_aux_disable(sor->aux); 13736fad8f66SThierry Reding 13746fad8f66SThierry Reding return err; 13756fad8f66SThierry Reding } 13766fad8f66SThierry Reding 13776fad8f66SThierry Reding static enum drm_mode_status 13786fad8f66SThierry Reding tegra_sor_connector_mode_valid(struct drm_connector *connector, 13796fad8f66SThierry Reding struct drm_display_mode *mode) 13806fad8f66SThierry Reding { 138164ea25c3SThierry Reding /* HDMI 2.0 modes are not yet supported */ 138264ea25c3SThierry Reding if (mode->clock > 340000) 138364ea25c3SThierry Reding return MODE_NOCLOCK; 138464ea25c3SThierry Reding 13856fad8f66SThierry Reding return MODE_OK; 13866fad8f66SThierry Reding } 13876fad8f66SThierry Reding 13886fad8f66SThierry Reding static const struct drm_connector_helper_funcs tegra_sor_connector_helper_funcs = { 13896fad8f66SThierry Reding .get_modes = tegra_sor_connector_get_modes, 13906fad8f66SThierry Reding .mode_valid = tegra_sor_connector_mode_valid, 13916fad8f66SThierry Reding }; 13926fad8f66SThierry Reding 13936fad8f66SThierry Reding static const struct drm_encoder_funcs tegra_sor_encoder_funcs = { 13946fad8f66SThierry Reding .destroy = tegra_output_encoder_destroy, 13956fad8f66SThierry Reding }; 13966fad8f66SThierry Reding 1397850bab44SThierry Reding static void tegra_sor_edp_disable(struct drm_encoder *encoder) 13986fad8f66SThierry Reding { 1399850bab44SThierry Reding struct tegra_output *output = encoder_to_output(encoder); 1400850bab44SThierry Reding struct tegra_dc *dc = to_tegra_dc(encoder->crtc); 1401850bab44SThierry Reding struct tegra_sor *sor = to_sor(output); 1402850bab44SThierry Reding u32 value; 1403850bab44SThierry Reding int err; 1404850bab44SThierry Reding 1405850bab44SThierry Reding if (output->panel) 1406850bab44SThierry Reding drm_panel_disable(output->panel); 1407850bab44SThierry Reding 1408850bab44SThierry Reding err = tegra_sor_detach(sor); 1409850bab44SThierry Reding if (err < 0) 1410850bab44SThierry Reding dev_err(sor->dev, "failed to detach SOR: %d\n", err); 1411850bab44SThierry Reding 1412850bab44SThierry Reding tegra_sor_writel(sor, 0, SOR_STATE1); 1413850bab44SThierry Reding tegra_sor_update(sor); 1414850bab44SThierry Reding 1415850bab44SThierry Reding /* 1416850bab44SThierry Reding * The following accesses registers of the display controller, so make 1417850bab44SThierry Reding * sure it's only executed when the output is attached to one. 1418850bab44SThierry Reding */ 1419850bab44SThierry Reding if (dc) { 1420850bab44SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 1421850bab44SThierry Reding value &= ~SOR_ENABLE; 1422850bab44SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 1423850bab44SThierry Reding 1424850bab44SThierry Reding tegra_dc_commit(dc); 14256fad8f66SThierry Reding } 14266fad8f66SThierry Reding 1427850bab44SThierry Reding err = tegra_sor_power_down(sor); 1428850bab44SThierry Reding if (err < 0) 1429850bab44SThierry Reding dev_err(sor->dev, "failed to power down SOR: %d\n", err); 1430850bab44SThierry Reding 14319542c237SThierry Reding if (sor->aux) { 14329542c237SThierry Reding err = drm_dp_aux_disable(sor->aux); 1433850bab44SThierry Reding if (err < 0) 1434850bab44SThierry Reding dev_err(sor->dev, "failed to disable DP: %d\n", err); 14356fad8f66SThierry Reding } 14366fad8f66SThierry Reding 1437850bab44SThierry Reding err = tegra_io_rail_power_off(TEGRA_IO_RAIL_LVDS); 1438850bab44SThierry Reding if (err < 0) 1439850bab44SThierry Reding dev_err(sor->dev, "failed to power off I/O rail: %d\n", err); 1440850bab44SThierry Reding 1441850bab44SThierry Reding if (output->panel) 1442850bab44SThierry Reding drm_panel_unprepare(output->panel); 1443850bab44SThierry Reding 1444aaff8bd2SThierry Reding pm_runtime_put(sor->dev); 14456fad8f66SThierry Reding } 14466fad8f66SThierry Reding 1447459cc2c6SThierry Reding #if 0 1448459cc2c6SThierry Reding static int calc_h_ref_to_sync(const struct drm_display_mode *mode, 1449459cc2c6SThierry Reding unsigned int *value) 1450459cc2c6SThierry Reding { 1451459cc2c6SThierry Reding unsigned int hfp, hsw, hbp, a = 0, b; 1452459cc2c6SThierry Reding 1453459cc2c6SThierry Reding hfp = mode->hsync_start - mode->hdisplay; 1454459cc2c6SThierry Reding hsw = mode->hsync_end - mode->hsync_start; 1455459cc2c6SThierry Reding hbp = mode->htotal - mode->hsync_end; 1456459cc2c6SThierry Reding 1457459cc2c6SThierry Reding pr_info("hfp: %u, hsw: %u, hbp: %u\n", hfp, hsw, hbp); 1458459cc2c6SThierry Reding 1459459cc2c6SThierry Reding b = hfp - 1; 1460459cc2c6SThierry Reding 1461459cc2c6SThierry Reding pr_info("a: %u, b: %u\n", a, b); 1462459cc2c6SThierry Reding pr_info("a + hsw + hbp = %u\n", a + hsw + hbp); 1463459cc2c6SThierry Reding 1464459cc2c6SThierry Reding if (a + hsw + hbp <= 11) { 1465459cc2c6SThierry Reding a = 1 + 11 - hsw - hbp; 1466459cc2c6SThierry Reding pr_info("a: %u\n", a); 1467459cc2c6SThierry Reding } 1468459cc2c6SThierry Reding 1469459cc2c6SThierry Reding if (a > b) 1470459cc2c6SThierry Reding return -EINVAL; 1471459cc2c6SThierry Reding 1472459cc2c6SThierry Reding if (hsw < 1) 1473459cc2c6SThierry Reding return -EINVAL; 1474459cc2c6SThierry Reding 1475459cc2c6SThierry Reding if (mode->hdisplay < 16) 1476459cc2c6SThierry Reding return -EINVAL; 1477459cc2c6SThierry Reding 1478459cc2c6SThierry Reding if (value) { 1479459cc2c6SThierry Reding if (b > a && a % 2) 1480459cc2c6SThierry Reding *value = a + 1; 1481459cc2c6SThierry Reding else 1482459cc2c6SThierry Reding *value = a; 1483459cc2c6SThierry Reding } 1484459cc2c6SThierry Reding 1485459cc2c6SThierry Reding return 0; 1486459cc2c6SThierry Reding } 1487459cc2c6SThierry Reding #endif 1488459cc2c6SThierry Reding 1489850bab44SThierry Reding static void tegra_sor_edp_enable(struct drm_encoder *encoder) 14906fad8f66SThierry Reding { 1491850bab44SThierry Reding struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; 14926fad8f66SThierry Reding struct tegra_output *output = encoder_to_output(encoder); 14936fad8f66SThierry Reding struct tegra_dc *dc = to_tegra_dc(encoder->crtc); 14946b6b6042SThierry Reding struct tegra_sor *sor = to_sor(output); 149534fa183bSThierry Reding struct tegra_sor_config config; 1496c31efa7aSThierry Reding struct tegra_sor_state *state; 149734fa183bSThierry Reding struct drm_dp_link link; 149801b9bea0SThierry Reding u8 rate, lanes; 14992bd1dd39SThierry Reding unsigned int i; 150086f5c52dSThierry Reding int err = 0; 150128fe2076SThierry Reding u32 value; 150286f5c52dSThierry Reding 1503c31efa7aSThierry Reding state = to_sor_state(output->connector.state); 15046b6b6042SThierry Reding 1505aaff8bd2SThierry Reding pm_runtime_get_sync(sor->dev); 15066b6b6042SThierry Reding 15076fad8f66SThierry Reding if (output->panel) 15086fad8f66SThierry Reding drm_panel_prepare(output->panel); 15096fad8f66SThierry Reding 15109542c237SThierry Reding err = drm_dp_aux_enable(sor->aux); 15116b6b6042SThierry Reding if (err < 0) 15126b6b6042SThierry Reding dev_err(sor->dev, "failed to enable DP: %d\n", err); 151334fa183bSThierry Reding 15149542c237SThierry Reding err = drm_dp_link_probe(sor->aux, &link); 151534fa183bSThierry Reding if (err < 0) { 151601b9bea0SThierry Reding dev_err(sor->dev, "failed to probe eDP link: %d\n", err); 1517850bab44SThierry Reding return; 151834fa183bSThierry Reding } 15196b6b6042SThierry Reding 152025bb2cecSThierry Reding /* switch to safe parent clock */ 152125bb2cecSThierry Reding err = tegra_sor_set_parent_clock(sor, sor->clk_safe); 15226b6b6042SThierry Reding if (err < 0) 15236b6b6042SThierry Reding dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); 15246b6b6042SThierry Reding 152534fa183bSThierry Reding memset(&config, 0, sizeof(config)); 1526c31efa7aSThierry Reding config.bits_per_pixel = state->bpc * 3; 152734fa183bSThierry Reding 1528a198359eSThierry Reding err = tegra_sor_compute_config(sor, mode, &config, &link); 152934fa183bSThierry Reding if (err < 0) 1530a198359eSThierry Reding dev_err(sor->dev, "failed to compute configuration: %d\n", err); 153134fa183bSThierry Reding 15326b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 15336b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; 15346b6b6042SThierry Reding value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK; 15356b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 15366b6b6042SThierry Reding 1537a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 1538a9a9e4fdSThierry Reding value &= ~SOR_PLL2_BANDGAP_POWERDOWN; 1539a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 15406b6b6042SThierry Reding usleep_range(20, 100); 15416b6b6042SThierry Reding 1542a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL3); 1543a9a9e4fdSThierry Reding value |= SOR_PLL3_PLL_VDD_MODE_3V3; 1544a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL3); 15456b6b6042SThierry Reding 1546a9a9e4fdSThierry Reding value = SOR_PLL0_ICHPMP(0xf) | SOR_PLL0_VCOCAP_RST | 1547a9a9e4fdSThierry Reding SOR_PLL0_PLLREG_LEVEL_V45 | SOR_PLL0_RESISTOR_EXT; 1548a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL0); 15496b6b6042SThierry Reding 1550a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 1551a9a9e4fdSThierry Reding value |= SOR_PLL2_SEQ_PLLCAPPD; 1552a9a9e4fdSThierry Reding value &= ~SOR_PLL2_SEQ_PLLCAPPD_ENFORCE; 1553a9a9e4fdSThierry Reding value |= SOR_PLL2_LVDS_ENABLE; 1554a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 15556b6b6042SThierry Reding 1556a9a9e4fdSThierry Reding value = SOR_PLL1_TERM_COMPOUT | SOR_PLL1_TMDS_TERM; 1557a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL1); 15586b6b6042SThierry Reding 15596b6b6042SThierry Reding while (true) { 1560a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 1561a9a9e4fdSThierry Reding if ((value & SOR_PLL2_SEQ_PLLCAPPD_ENFORCE) == 0) 15626b6b6042SThierry Reding break; 15636b6b6042SThierry Reding 15646b6b6042SThierry Reding usleep_range(250, 1000); 15656b6b6042SThierry Reding } 15666b6b6042SThierry Reding 1567a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 1568a9a9e4fdSThierry Reding value &= ~SOR_PLL2_POWERDOWN_OVERRIDE; 1569a9a9e4fdSThierry Reding value &= ~SOR_PLL2_PORT_POWERDOWN; 1570a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 15716b6b6042SThierry Reding 15726b6b6042SThierry Reding /* 15736b6b6042SThierry Reding * power up 15746b6b6042SThierry Reding */ 15756b6b6042SThierry Reding 15766b6b6042SThierry Reding /* set safe link bandwidth (1.62 Gbps) */ 15776b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 15786b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; 15796b6b6042SThierry Reding value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G1_62; 15806b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 15816b6b6042SThierry Reding 15826b6b6042SThierry Reding /* step 1 */ 1583a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 1584a9a9e4fdSThierry Reding value |= SOR_PLL2_SEQ_PLLCAPPD_ENFORCE | SOR_PLL2_PORT_POWERDOWN | 1585a9a9e4fdSThierry Reding SOR_PLL2_BANDGAP_POWERDOWN; 1586a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 15876b6b6042SThierry Reding 1588a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL0); 1589a9a9e4fdSThierry Reding value |= SOR_PLL0_VCOPD | SOR_PLL0_PWR; 1590a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL0); 15916b6b6042SThierry Reding 1592a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 15936b6b6042SThierry Reding value &= ~SOR_DP_PADCTL_PAD_CAL_PD; 1594a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 15956b6b6042SThierry Reding 15966b6b6042SThierry Reding /* step 2 */ 15976b6b6042SThierry Reding err = tegra_io_rail_power_on(TEGRA_IO_RAIL_LVDS); 1598850bab44SThierry Reding if (err < 0) 15996b6b6042SThierry Reding dev_err(sor->dev, "failed to power on I/O rail: %d\n", err); 16006b6b6042SThierry Reding 16016b6b6042SThierry Reding usleep_range(5, 100); 16026b6b6042SThierry Reding 16036b6b6042SThierry Reding /* step 3 */ 1604a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 1605a9a9e4fdSThierry Reding value &= ~SOR_PLL2_BANDGAP_POWERDOWN; 1606a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 16076b6b6042SThierry Reding 16086b6b6042SThierry Reding usleep_range(20, 100); 16096b6b6042SThierry Reding 16106b6b6042SThierry Reding /* step 4 */ 1611a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL0); 1612a9a9e4fdSThierry Reding value &= ~SOR_PLL0_VCOPD; 1613a9a9e4fdSThierry Reding value &= ~SOR_PLL0_PWR; 1614a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL0); 16156b6b6042SThierry Reding 1616a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 1617a9a9e4fdSThierry Reding value &= ~SOR_PLL2_SEQ_PLLCAPPD_ENFORCE; 1618a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 16196b6b6042SThierry Reding 16206b6b6042SThierry Reding usleep_range(200, 1000); 16216b6b6042SThierry Reding 16226b6b6042SThierry Reding /* step 5 */ 1623a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 1624a9a9e4fdSThierry Reding value &= ~SOR_PLL2_PORT_POWERDOWN; 1625a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 16266b6b6042SThierry Reding 162730b49435SThierry Reding /* XXX not in TRM */ 162830b49435SThierry Reding for (value = 0, i = 0; i < 5; i++) 162930b49435SThierry Reding value |= SOR_XBAR_CTRL_LINK0_XSEL(i, sor->soc->xbar_cfg[i]) | 163030b49435SThierry Reding SOR_XBAR_CTRL_LINK1_XSEL(i, i); 163130b49435SThierry Reding 163230b49435SThierry Reding tegra_sor_writel(sor, 0x00000000, SOR_XBAR_POL); 163330b49435SThierry Reding tegra_sor_writel(sor, value, SOR_XBAR_CTRL); 163430b49435SThierry Reding 163525bb2cecSThierry Reding /* switch to DP parent clock */ 163625bb2cecSThierry Reding err = tegra_sor_set_parent_clock(sor, sor->clk_dp); 16376b6b6042SThierry Reding if (err < 0) 163825bb2cecSThierry Reding dev_err(sor->dev, "failed to set parent clock: %d\n", err); 16396b6b6042SThierry Reding 1640899451b7SThierry Reding /* power DP lanes */ 1641a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 1642899451b7SThierry Reding 1643899451b7SThierry Reding if (link.num_lanes <= 2) 1644899451b7SThierry Reding value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_2); 1645899451b7SThierry Reding else 1646899451b7SThierry Reding value |= SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_2; 1647899451b7SThierry Reding 1648899451b7SThierry Reding if (link.num_lanes <= 1) 1649899451b7SThierry Reding value &= ~SOR_DP_PADCTL_PD_TXD_1; 1650899451b7SThierry Reding else 1651899451b7SThierry Reding value |= SOR_DP_PADCTL_PD_TXD_1; 1652899451b7SThierry Reding 1653899451b7SThierry Reding if (link.num_lanes == 0) 1654899451b7SThierry Reding value &= ~SOR_DP_PADCTL_PD_TXD_0; 1655899451b7SThierry Reding else 1656899451b7SThierry Reding value |= SOR_DP_PADCTL_PD_TXD_0; 1657899451b7SThierry Reding 1658a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 16596b6b6042SThierry Reding 1660a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_LINKCTL0); 16616b6b6042SThierry Reding value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK; 16620c90a184SThierry Reding value |= SOR_DP_LINKCTL_LANE_COUNT(link.num_lanes); 1663a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_LINKCTL0); 16646b6b6042SThierry Reding 16656b6b6042SThierry Reding /* start lane sequencer */ 16666b6b6042SThierry Reding value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_DOWN | 16676b6b6042SThierry Reding SOR_LANE_SEQ_CTL_POWER_STATE_UP; 16686b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL); 16696b6b6042SThierry Reding 16706b6b6042SThierry Reding while (true) { 16716b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL); 16726b6b6042SThierry Reding if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0) 16736b6b6042SThierry Reding break; 16746b6b6042SThierry Reding 16756b6b6042SThierry Reding usleep_range(250, 1000); 16766b6b6042SThierry Reding } 16776b6b6042SThierry Reding 1678a4263fedSThierry Reding /* set link bandwidth */ 16796b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 16806b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; 1681a4263fedSThierry Reding value |= drm_dp_link_rate_to_bw_code(link.rate) << 2; 16826b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 16836b6b6042SThierry Reding 1684402f6bcdSThierry Reding tegra_sor_apply_config(sor, &config); 1685402f6bcdSThierry Reding 1686402f6bcdSThierry Reding /* enable link */ 1687a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_LINKCTL0); 16886b6b6042SThierry Reding value |= SOR_DP_LINKCTL_ENABLE; 16896b6b6042SThierry Reding value |= SOR_DP_LINKCTL_ENHANCED_FRAME; 1690a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_LINKCTL0); 16916b6b6042SThierry Reding 16926b6b6042SThierry Reding for (i = 0, value = 0; i < 4; i++) { 16936b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 16946b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_GALIOS | 16956b6b6042SThierry Reding SOR_DP_TPG_PATTERN_NONE; 16966b6b6042SThierry Reding value = (value << 8) | lane; 16976b6b6042SThierry Reding } 16986b6b6042SThierry Reding 16996b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 17006b6b6042SThierry Reding 17016b6b6042SThierry Reding /* enable pad calibration logic */ 1702a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 17036b6b6042SThierry Reding value |= SOR_DP_PADCTL_PAD_CAL_PD; 1704a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 17056b6b6042SThierry Reding 17069542c237SThierry Reding err = drm_dp_link_probe(sor->aux, &link); 1707850bab44SThierry Reding if (err < 0) 170801b9bea0SThierry Reding dev_err(sor->dev, "failed to probe eDP link: %d\n", err); 17096b6b6042SThierry Reding 17109542c237SThierry Reding err = drm_dp_link_power_up(sor->aux, &link); 1711850bab44SThierry Reding if (err < 0) 171201b9bea0SThierry Reding dev_err(sor->dev, "failed to power up eDP link: %d\n", err); 17136b6b6042SThierry Reding 17149542c237SThierry Reding err = drm_dp_link_configure(sor->aux, &link); 1715850bab44SThierry Reding if (err < 0) 171601b9bea0SThierry Reding dev_err(sor->dev, "failed to configure eDP link: %d\n", err); 17176b6b6042SThierry Reding 17186b6b6042SThierry Reding rate = drm_dp_link_rate_to_bw_code(link.rate); 17196b6b6042SThierry Reding lanes = link.num_lanes; 17206b6b6042SThierry Reding 17216b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 17226b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; 17236b6b6042SThierry Reding value |= SOR_CLK_CNTRL_DP_LINK_SPEED(rate); 17246b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 17256b6b6042SThierry Reding 1726a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_LINKCTL0); 17276b6b6042SThierry Reding value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK; 17286b6b6042SThierry Reding value |= SOR_DP_LINKCTL_LANE_COUNT(lanes); 17296b6b6042SThierry Reding 17306b6b6042SThierry Reding if (link.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) 17316b6b6042SThierry Reding value |= SOR_DP_LINKCTL_ENHANCED_FRAME; 17326b6b6042SThierry Reding 1733a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_LINKCTL0); 17346b6b6042SThierry Reding 17356b6b6042SThierry Reding /* disable training pattern generator */ 17366b6b6042SThierry Reding 17376b6b6042SThierry Reding for (i = 0; i < link.num_lanes; i++) { 17386b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 17396b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_GALIOS | 17406b6b6042SThierry Reding SOR_DP_TPG_PATTERN_NONE; 17416b6b6042SThierry Reding value = (value << 8) | lane; 17426b6b6042SThierry Reding } 17436b6b6042SThierry Reding 17446b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 17456b6b6042SThierry Reding 17466b6b6042SThierry Reding err = tegra_sor_dp_train_fast(sor, &link); 174701b9bea0SThierry Reding if (err < 0) 174801b9bea0SThierry Reding dev_err(sor->dev, "DP fast link training failed: %d\n", err); 17496b6b6042SThierry Reding 17506b6b6042SThierry Reding dev_dbg(sor->dev, "fast link training succeeded\n"); 17516b6b6042SThierry Reding 17526b6b6042SThierry Reding err = tegra_sor_power_up(sor, 250); 1753850bab44SThierry Reding if (err < 0) 17546b6b6042SThierry Reding dev_err(sor->dev, "failed to power up SOR: %d\n", err); 17556b6b6042SThierry Reding 17566b6b6042SThierry Reding /* CSTM (LVDS, link A/B, upper) */ 1757143b1df2SStéphane Marchesin value = SOR_CSTM_LVDS | SOR_CSTM_LINK_ACT_A | SOR_CSTM_LINK_ACT_B | 17586b6b6042SThierry Reding SOR_CSTM_UPPER; 17596b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CSTM); 17606b6b6042SThierry Reding 17612bd1dd39SThierry Reding /* use DP-A protocol */ 17622bd1dd39SThierry Reding value = tegra_sor_readl(sor, SOR_STATE1); 17632bd1dd39SThierry Reding value &= ~SOR_STATE_ASY_PROTOCOL_MASK; 17642bd1dd39SThierry Reding value |= SOR_STATE_ASY_PROTOCOL_DP_A; 17652bd1dd39SThierry Reding tegra_sor_writel(sor, value, SOR_STATE1); 17662bd1dd39SThierry Reding 1767c31efa7aSThierry Reding tegra_sor_mode_set(sor, mode, state); 17682bd1dd39SThierry Reding 17696b6b6042SThierry Reding /* PWM setup */ 17706b6b6042SThierry Reding err = tegra_sor_setup_pwm(sor, 250); 1771850bab44SThierry Reding if (err < 0) 17726b6b6042SThierry Reding dev_err(sor->dev, "failed to setup PWM: %d\n", err); 17736b6b6042SThierry Reding 1774666cb873SThierry Reding tegra_sor_update(sor); 1775666cb873SThierry Reding 17766b6b6042SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 17776b6b6042SThierry Reding value |= SOR_ENABLE; 17786b6b6042SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 17796b6b6042SThierry Reding 1780666cb873SThierry Reding tegra_dc_commit(dc); 17816b6b6042SThierry Reding 17826b6b6042SThierry Reding err = tegra_sor_attach(sor); 1783850bab44SThierry Reding if (err < 0) 17846b6b6042SThierry Reding dev_err(sor->dev, "failed to attach SOR: %d\n", err); 17856b6b6042SThierry Reding 17866b6b6042SThierry Reding err = tegra_sor_wakeup(sor); 1787850bab44SThierry Reding if (err < 0) 17886b6b6042SThierry Reding dev_err(sor->dev, "failed to enable DC: %d\n", err); 17896b6b6042SThierry Reding 17906fad8f66SThierry Reding if (output->panel) 17916fad8f66SThierry Reding drm_panel_enable(output->panel); 17926b6b6042SThierry Reding } 17936b6b6042SThierry Reding 179482f1511cSThierry Reding static int 179582f1511cSThierry Reding tegra_sor_encoder_atomic_check(struct drm_encoder *encoder, 179682f1511cSThierry Reding struct drm_crtc_state *crtc_state, 179782f1511cSThierry Reding struct drm_connector_state *conn_state) 179882f1511cSThierry Reding { 179982f1511cSThierry Reding struct tegra_output *output = encoder_to_output(encoder); 1800c31efa7aSThierry Reding struct tegra_sor_state *state = to_sor_state(conn_state); 180182f1511cSThierry Reding struct tegra_dc *dc = to_tegra_dc(conn_state->crtc); 180282f1511cSThierry Reding unsigned long pclk = crtc_state->mode.clock * 1000; 180382f1511cSThierry Reding struct tegra_sor *sor = to_sor(output); 1804c31efa7aSThierry Reding struct drm_display_info *info; 180582f1511cSThierry Reding int err; 180682f1511cSThierry Reding 1807c31efa7aSThierry Reding info = &output->connector.display_info; 1808c31efa7aSThierry Reding 180982f1511cSThierry Reding err = tegra_dc_state_setup_clock(dc, crtc_state, sor->clk_parent, 181082f1511cSThierry Reding pclk, 0); 181182f1511cSThierry Reding if (err < 0) { 181282f1511cSThierry Reding dev_err(output->dev, "failed to setup CRTC state: %d\n", err); 181382f1511cSThierry Reding return err; 181482f1511cSThierry Reding } 181582f1511cSThierry Reding 1816c31efa7aSThierry Reding switch (info->bpc) { 1817c31efa7aSThierry Reding case 8: 1818c31efa7aSThierry Reding case 6: 1819c31efa7aSThierry Reding state->bpc = info->bpc; 1820c31efa7aSThierry Reding break; 1821c31efa7aSThierry Reding 1822c31efa7aSThierry Reding default: 1823c31efa7aSThierry Reding DRM_DEBUG_KMS("%u bits-per-color not supported\n", info->bpc); 1824c31efa7aSThierry Reding state->bpc = 8; 1825c31efa7aSThierry Reding break; 1826c31efa7aSThierry Reding } 1827c31efa7aSThierry Reding 182882f1511cSThierry Reding return 0; 182982f1511cSThierry Reding } 183082f1511cSThierry Reding 1831459cc2c6SThierry Reding static const struct drm_encoder_helper_funcs tegra_sor_edp_helpers = { 1832850bab44SThierry Reding .disable = tegra_sor_edp_disable, 1833850bab44SThierry Reding .enable = tegra_sor_edp_enable, 183482f1511cSThierry Reding .atomic_check = tegra_sor_encoder_atomic_check, 18356b6b6042SThierry Reding }; 18366b6b6042SThierry Reding 1837459cc2c6SThierry Reding static inline u32 tegra_sor_hdmi_subpack(const u8 *ptr, size_t size) 1838459cc2c6SThierry Reding { 1839459cc2c6SThierry Reding u32 value = 0; 1840459cc2c6SThierry Reding size_t i; 1841459cc2c6SThierry Reding 1842459cc2c6SThierry Reding for (i = size; i > 0; i--) 1843459cc2c6SThierry Reding value = (value << 8) | ptr[i - 1]; 1844459cc2c6SThierry Reding 1845459cc2c6SThierry Reding return value; 1846459cc2c6SThierry Reding } 1847459cc2c6SThierry Reding 1848459cc2c6SThierry Reding static void tegra_sor_hdmi_write_infopack(struct tegra_sor *sor, 1849459cc2c6SThierry Reding const void *data, size_t size) 1850459cc2c6SThierry Reding { 1851459cc2c6SThierry Reding const u8 *ptr = data; 1852459cc2c6SThierry Reding unsigned long offset; 1853459cc2c6SThierry Reding size_t i, j; 1854459cc2c6SThierry Reding u32 value; 1855459cc2c6SThierry Reding 1856459cc2c6SThierry Reding switch (ptr[0]) { 1857459cc2c6SThierry Reding case HDMI_INFOFRAME_TYPE_AVI: 1858459cc2c6SThierry Reding offset = SOR_HDMI_AVI_INFOFRAME_HEADER; 1859459cc2c6SThierry Reding break; 1860459cc2c6SThierry Reding 1861459cc2c6SThierry Reding case HDMI_INFOFRAME_TYPE_AUDIO: 1862459cc2c6SThierry Reding offset = SOR_HDMI_AUDIO_INFOFRAME_HEADER; 1863459cc2c6SThierry Reding break; 1864459cc2c6SThierry Reding 1865459cc2c6SThierry Reding case HDMI_INFOFRAME_TYPE_VENDOR: 1866459cc2c6SThierry Reding offset = SOR_HDMI_VSI_INFOFRAME_HEADER; 1867459cc2c6SThierry Reding break; 1868459cc2c6SThierry Reding 1869459cc2c6SThierry Reding default: 1870459cc2c6SThierry Reding dev_err(sor->dev, "unsupported infoframe type: %02x\n", 1871459cc2c6SThierry Reding ptr[0]); 1872459cc2c6SThierry Reding return; 1873459cc2c6SThierry Reding } 1874459cc2c6SThierry Reding 1875459cc2c6SThierry Reding value = INFOFRAME_HEADER_TYPE(ptr[0]) | 1876459cc2c6SThierry Reding INFOFRAME_HEADER_VERSION(ptr[1]) | 1877459cc2c6SThierry Reding INFOFRAME_HEADER_LEN(ptr[2]); 1878459cc2c6SThierry Reding tegra_sor_writel(sor, value, offset); 1879459cc2c6SThierry Reding offset++; 1880459cc2c6SThierry Reding 1881459cc2c6SThierry Reding /* 1882459cc2c6SThierry Reding * Each subpack contains 7 bytes, divided into: 1883459cc2c6SThierry Reding * - subpack_low: bytes 0 - 3 1884459cc2c6SThierry Reding * - subpack_high: bytes 4 - 6 (with byte 7 padded to 0x00) 1885459cc2c6SThierry Reding */ 1886459cc2c6SThierry Reding for (i = 3, j = 0; i < size; i += 7, j += 8) { 1887459cc2c6SThierry Reding size_t rem = size - i, num = min_t(size_t, rem, 4); 1888459cc2c6SThierry Reding 1889459cc2c6SThierry Reding value = tegra_sor_hdmi_subpack(&ptr[i], num); 1890459cc2c6SThierry Reding tegra_sor_writel(sor, value, offset++); 1891459cc2c6SThierry Reding 1892459cc2c6SThierry Reding num = min_t(size_t, rem - num, 3); 1893459cc2c6SThierry Reding 1894459cc2c6SThierry Reding value = tegra_sor_hdmi_subpack(&ptr[i + 4], num); 1895459cc2c6SThierry Reding tegra_sor_writel(sor, value, offset++); 1896459cc2c6SThierry Reding } 1897459cc2c6SThierry Reding } 1898459cc2c6SThierry Reding 1899459cc2c6SThierry Reding static int 1900459cc2c6SThierry Reding tegra_sor_hdmi_setup_avi_infoframe(struct tegra_sor *sor, 1901459cc2c6SThierry Reding const struct drm_display_mode *mode) 1902459cc2c6SThierry Reding { 1903459cc2c6SThierry Reding u8 buffer[HDMI_INFOFRAME_SIZE(AVI)]; 1904459cc2c6SThierry Reding struct hdmi_avi_infoframe frame; 1905459cc2c6SThierry Reding u32 value; 1906459cc2c6SThierry Reding int err; 1907459cc2c6SThierry Reding 1908459cc2c6SThierry Reding /* disable AVI infoframe */ 1909459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_HDMI_AVI_INFOFRAME_CTRL); 1910459cc2c6SThierry Reding value &= ~INFOFRAME_CTRL_SINGLE; 1911459cc2c6SThierry Reding value &= ~INFOFRAME_CTRL_OTHER; 1912459cc2c6SThierry Reding value &= ~INFOFRAME_CTRL_ENABLE; 1913459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_HDMI_AVI_INFOFRAME_CTRL); 1914459cc2c6SThierry Reding 19150c1f528cSShashank Sharma err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); 1916459cc2c6SThierry Reding if (err < 0) { 1917459cc2c6SThierry Reding dev_err(sor->dev, "failed to setup AVI infoframe: %d\n", err); 1918459cc2c6SThierry Reding return err; 1919459cc2c6SThierry Reding } 1920459cc2c6SThierry Reding 1921459cc2c6SThierry Reding err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); 1922459cc2c6SThierry Reding if (err < 0) { 1923459cc2c6SThierry Reding dev_err(sor->dev, "failed to pack AVI infoframe: %d\n", err); 1924459cc2c6SThierry Reding return err; 1925459cc2c6SThierry Reding } 1926459cc2c6SThierry Reding 1927459cc2c6SThierry Reding tegra_sor_hdmi_write_infopack(sor, buffer, err); 1928459cc2c6SThierry Reding 1929459cc2c6SThierry Reding /* enable AVI infoframe */ 1930459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_HDMI_AVI_INFOFRAME_CTRL); 1931459cc2c6SThierry Reding value |= INFOFRAME_CTRL_CHECKSUM_ENABLE; 1932459cc2c6SThierry Reding value |= INFOFRAME_CTRL_ENABLE; 1933459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_HDMI_AVI_INFOFRAME_CTRL); 1934459cc2c6SThierry Reding 1935459cc2c6SThierry Reding return 0; 1936459cc2c6SThierry Reding } 1937459cc2c6SThierry Reding 1938459cc2c6SThierry Reding static void tegra_sor_hdmi_disable_audio_infoframe(struct tegra_sor *sor) 1939459cc2c6SThierry Reding { 1940459cc2c6SThierry Reding u32 value; 1941459cc2c6SThierry Reding 1942459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_HDMI_AUDIO_INFOFRAME_CTRL); 1943459cc2c6SThierry Reding value &= ~INFOFRAME_CTRL_ENABLE; 1944459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_HDMI_AUDIO_INFOFRAME_CTRL); 1945459cc2c6SThierry Reding } 1946459cc2c6SThierry Reding 1947459cc2c6SThierry Reding static struct tegra_sor_hdmi_settings * 1948459cc2c6SThierry Reding tegra_sor_hdmi_find_settings(struct tegra_sor *sor, unsigned long frequency) 1949459cc2c6SThierry Reding { 1950459cc2c6SThierry Reding unsigned int i; 1951459cc2c6SThierry Reding 1952459cc2c6SThierry Reding for (i = 0; i < sor->num_settings; i++) 1953459cc2c6SThierry Reding if (frequency <= sor->settings[i].frequency) 1954459cc2c6SThierry Reding return &sor->settings[i]; 1955459cc2c6SThierry Reding 1956459cc2c6SThierry Reding return NULL; 1957459cc2c6SThierry Reding } 1958459cc2c6SThierry Reding 1959459cc2c6SThierry Reding static void tegra_sor_hdmi_disable(struct drm_encoder *encoder) 1960459cc2c6SThierry Reding { 1961459cc2c6SThierry Reding struct tegra_output *output = encoder_to_output(encoder); 1962459cc2c6SThierry Reding struct tegra_dc *dc = to_tegra_dc(encoder->crtc); 1963459cc2c6SThierry Reding struct tegra_sor *sor = to_sor(output); 1964459cc2c6SThierry Reding u32 value; 1965459cc2c6SThierry Reding int err; 1966459cc2c6SThierry Reding 1967459cc2c6SThierry Reding err = tegra_sor_detach(sor); 1968459cc2c6SThierry Reding if (err < 0) 1969459cc2c6SThierry Reding dev_err(sor->dev, "failed to detach SOR: %d\n", err); 1970459cc2c6SThierry Reding 1971459cc2c6SThierry Reding tegra_sor_writel(sor, 0, SOR_STATE1); 1972459cc2c6SThierry Reding tegra_sor_update(sor); 1973459cc2c6SThierry Reding 1974459cc2c6SThierry Reding /* disable display to SOR clock */ 1975459cc2c6SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 1976459cc2c6SThierry Reding value &= ~SOR1_TIMING_CYA; 1977459cc2c6SThierry Reding value &= ~SOR1_ENABLE; 1978459cc2c6SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 1979459cc2c6SThierry Reding 1980459cc2c6SThierry Reding tegra_dc_commit(dc); 1981459cc2c6SThierry Reding 1982459cc2c6SThierry Reding err = tegra_sor_power_down(sor); 1983459cc2c6SThierry Reding if (err < 0) 1984459cc2c6SThierry Reding dev_err(sor->dev, "failed to power down SOR: %d\n", err); 1985459cc2c6SThierry Reding 1986459cc2c6SThierry Reding err = tegra_io_rail_power_off(TEGRA_IO_RAIL_HDMI); 1987459cc2c6SThierry Reding if (err < 0) 1988459cc2c6SThierry Reding dev_err(sor->dev, "failed to power off HDMI rail: %d\n", err); 1989459cc2c6SThierry Reding 1990aaff8bd2SThierry Reding pm_runtime_put(sor->dev); 1991459cc2c6SThierry Reding } 1992459cc2c6SThierry Reding 1993459cc2c6SThierry Reding static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) 1994459cc2c6SThierry Reding { 1995459cc2c6SThierry Reding struct tegra_output *output = encoder_to_output(encoder); 1996459cc2c6SThierry Reding unsigned int h_ref_to_sync = 1, pulse_start, max_ac; 1997459cc2c6SThierry Reding struct tegra_dc *dc = to_tegra_dc(encoder->crtc); 1998459cc2c6SThierry Reding struct tegra_sor_hdmi_settings *settings; 1999459cc2c6SThierry Reding struct tegra_sor *sor = to_sor(output); 2000c31efa7aSThierry Reding struct tegra_sor_state *state; 2001459cc2c6SThierry Reding struct drm_display_mode *mode; 200230b49435SThierry Reding unsigned int div, i; 2003459cc2c6SThierry Reding u32 value; 2004459cc2c6SThierry Reding int err; 2005459cc2c6SThierry Reding 2006c31efa7aSThierry Reding state = to_sor_state(output->connector.state); 2007459cc2c6SThierry Reding mode = &encoder->crtc->state->adjusted_mode; 2008459cc2c6SThierry Reding 2009aaff8bd2SThierry Reding pm_runtime_get_sync(sor->dev); 2010459cc2c6SThierry Reding 201125bb2cecSThierry Reding /* switch to safe parent clock */ 201225bb2cecSThierry Reding err = tegra_sor_set_parent_clock(sor, sor->clk_safe); 2013e1335e2fSThierry Reding if (err < 0) { 2014459cc2c6SThierry Reding dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); 2015e1335e2fSThierry Reding return; 2016e1335e2fSThierry Reding } 2017459cc2c6SThierry Reding 2018459cc2c6SThierry Reding div = clk_get_rate(sor->clk) / 1000000 * 4; 2019459cc2c6SThierry Reding 2020459cc2c6SThierry Reding err = tegra_io_rail_power_on(TEGRA_IO_RAIL_HDMI); 2021459cc2c6SThierry Reding if (err < 0) 2022459cc2c6SThierry Reding dev_err(sor->dev, "failed to power on HDMI rail: %d\n", err); 2023459cc2c6SThierry Reding 2024459cc2c6SThierry Reding usleep_range(20, 100); 2025459cc2c6SThierry Reding 2026459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 2027459cc2c6SThierry Reding value &= ~SOR_PLL2_BANDGAP_POWERDOWN; 2028459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 2029459cc2c6SThierry Reding 2030459cc2c6SThierry Reding usleep_range(20, 100); 2031459cc2c6SThierry Reding 2032459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_PLL3); 2033459cc2c6SThierry Reding value &= ~SOR_PLL3_PLL_VDD_MODE_3V3; 2034459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_PLL3); 2035459cc2c6SThierry Reding 2036459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_PLL0); 2037459cc2c6SThierry Reding value &= ~SOR_PLL0_VCOPD; 2038459cc2c6SThierry Reding value &= ~SOR_PLL0_PWR; 2039459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_PLL0); 2040459cc2c6SThierry Reding 2041459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 2042459cc2c6SThierry Reding value &= ~SOR_PLL2_SEQ_PLLCAPPD_ENFORCE; 2043459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 2044459cc2c6SThierry Reding 2045459cc2c6SThierry Reding usleep_range(200, 400); 2046459cc2c6SThierry Reding 2047459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 2048459cc2c6SThierry Reding value &= ~SOR_PLL2_POWERDOWN_OVERRIDE; 2049459cc2c6SThierry Reding value &= ~SOR_PLL2_PORT_POWERDOWN; 2050459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 2051459cc2c6SThierry Reding 2052459cc2c6SThierry Reding usleep_range(20, 100); 2053459cc2c6SThierry Reding 2054459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 2055459cc2c6SThierry Reding value |= SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 | 2056459cc2c6SThierry Reding SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2; 2057459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 2058459cc2c6SThierry Reding 2059459cc2c6SThierry Reding while (true) { 2060459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL); 2061459cc2c6SThierry Reding if ((value & SOR_LANE_SEQ_CTL_STATE_BUSY) == 0) 2062459cc2c6SThierry Reding break; 2063459cc2c6SThierry Reding 2064459cc2c6SThierry Reding usleep_range(250, 1000); 2065459cc2c6SThierry Reding } 2066459cc2c6SThierry Reding 2067459cc2c6SThierry Reding value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_DOWN | 2068459cc2c6SThierry Reding SOR_LANE_SEQ_CTL_POWER_STATE_UP | SOR_LANE_SEQ_CTL_DELAY(5); 2069459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL); 2070459cc2c6SThierry Reding 2071459cc2c6SThierry Reding while (true) { 2072459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL); 2073459cc2c6SThierry Reding if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0) 2074459cc2c6SThierry Reding break; 2075459cc2c6SThierry Reding 2076459cc2c6SThierry Reding usleep_range(250, 1000); 2077459cc2c6SThierry Reding } 2078459cc2c6SThierry Reding 2079459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 2080459cc2c6SThierry Reding value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; 2081459cc2c6SThierry Reding value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; 2082459cc2c6SThierry Reding 2083459cc2c6SThierry Reding if (mode->clock < 340000) 2084459cc2c6SThierry Reding value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G2_70; 2085459cc2c6SThierry Reding else 2086459cc2c6SThierry Reding value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G5_40; 2087459cc2c6SThierry Reding 2088459cc2c6SThierry Reding value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK; 2089459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 2090459cc2c6SThierry Reding 2091459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_DP_SPARE0); 2092459cc2c6SThierry Reding value |= SOR_DP_SPARE_DISP_VIDEO_PREAMBLE; 2093459cc2c6SThierry Reding value &= ~SOR_DP_SPARE_PANEL_INTERNAL; 2094459cc2c6SThierry Reding value |= SOR_DP_SPARE_SEQ_ENABLE; 2095459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_DP_SPARE0); 2096459cc2c6SThierry Reding 2097459cc2c6SThierry Reding value = SOR_SEQ_CTL_PU_PC(0) | SOR_SEQ_CTL_PU_PC_ALT(0) | 2098459cc2c6SThierry Reding SOR_SEQ_CTL_PD_PC(8) | SOR_SEQ_CTL_PD_PC_ALT(8); 2099459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_SEQ_CTL); 2100459cc2c6SThierry Reding 2101459cc2c6SThierry Reding value = SOR_SEQ_INST_DRIVE_PWM_OUT_LO | SOR_SEQ_INST_HALT | 2102459cc2c6SThierry Reding SOR_SEQ_INST_WAIT_VSYNC | SOR_SEQ_INST_WAIT(1); 2103459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_SEQ_INST(0)); 2104459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_SEQ_INST(8)); 2105459cc2c6SThierry Reding 2106459cc2c6SThierry Reding /* program the reference clock */ 2107459cc2c6SThierry Reding value = SOR_REFCLK_DIV_INT(div) | SOR_REFCLK_DIV_FRAC(div); 2108459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_REFCLK); 2109459cc2c6SThierry Reding 211030b49435SThierry Reding /* XXX not in TRM */ 211130b49435SThierry Reding for (value = 0, i = 0; i < 5; i++) 211230b49435SThierry Reding value |= SOR_XBAR_CTRL_LINK0_XSEL(i, sor->soc->xbar_cfg[i]) | 211330b49435SThierry Reding SOR_XBAR_CTRL_LINK1_XSEL(i, i); 2114459cc2c6SThierry Reding 2115459cc2c6SThierry Reding tegra_sor_writel(sor, 0x00000000, SOR_XBAR_POL); 211630b49435SThierry Reding tegra_sor_writel(sor, value, SOR_XBAR_CTRL); 2117459cc2c6SThierry Reding 211825bb2cecSThierry Reding /* switch to parent clock */ 2119e1335e2fSThierry Reding err = clk_set_parent(sor->clk, sor->clk_parent); 2120e1335e2fSThierry Reding if (err < 0) { 2121459cc2c6SThierry Reding dev_err(sor->dev, "failed to set parent clock: %d\n", err); 2122e1335e2fSThierry Reding return; 2123e1335e2fSThierry Reding } 2124e1335e2fSThierry Reding 2125e1335e2fSThierry Reding err = tegra_sor_set_parent_clock(sor, sor->clk_pad); 2126e1335e2fSThierry Reding if (err < 0) { 2127e1335e2fSThierry Reding dev_err(sor->dev, "failed to set pad clock: %d\n", err); 2128e1335e2fSThierry Reding return; 2129e1335e2fSThierry Reding } 2130459cc2c6SThierry Reding 2131459cc2c6SThierry Reding value = SOR_INPUT_CONTROL_HDMI_SRC_SELECT(dc->pipe); 2132459cc2c6SThierry Reding 2133459cc2c6SThierry Reding /* XXX is this the proper check? */ 2134459cc2c6SThierry Reding if (mode->clock < 75000) 2135459cc2c6SThierry Reding value |= SOR_INPUT_CONTROL_ARM_VIDEO_RANGE_LIMITED; 2136459cc2c6SThierry Reding 2137459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_INPUT_CONTROL); 2138459cc2c6SThierry Reding 2139459cc2c6SThierry Reding max_ac = ((mode->htotal - mode->hdisplay) - SOR_REKEY - 18) / 32; 2140459cc2c6SThierry Reding 2141459cc2c6SThierry Reding value = SOR_HDMI_CTRL_ENABLE | SOR_HDMI_CTRL_MAX_AC_PACKET(max_ac) | 2142459cc2c6SThierry Reding SOR_HDMI_CTRL_AUDIO_LAYOUT | SOR_HDMI_CTRL_REKEY(SOR_REKEY); 2143459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_HDMI_CTRL); 2144459cc2c6SThierry Reding 2145459cc2c6SThierry Reding /* H_PULSE2 setup */ 2146459cc2c6SThierry Reding pulse_start = h_ref_to_sync + (mode->hsync_end - mode->hsync_start) + 2147459cc2c6SThierry Reding (mode->htotal - mode->hsync_end) - 10; 2148459cc2c6SThierry Reding 2149459cc2c6SThierry Reding value = PULSE_LAST_END_A | PULSE_QUAL_VACTIVE | 2150459cc2c6SThierry Reding PULSE_POLARITY_HIGH | PULSE_MODE_NORMAL; 2151459cc2c6SThierry Reding tegra_dc_writel(dc, value, DC_DISP_H_PULSE2_CONTROL); 2152459cc2c6SThierry Reding 2153459cc2c6SThierry Reding value = PULSE_END(pulse_start + 8) | PULSE_START(pulse_start); 2154459cc2c6SThierry Reding tegra_dc_writel(dc, value, DC_DISP_H_PULSE2_POSITION_A); 2155459cc2c6SThierry Reding 2156459cc2c6SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_SIGNAL_OPTIONS0); 2157459cc2c6SThierry Reding value |= H_PULSE2_ENABLE; 2158459cc2c6SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_SIGNAL_OPTIONS0); 2159459cc2c6SThierry Reding 2160459cc2c6SThierry Reding /* infoframe setup */ 2161459cc2c6SThierry Reding err = tegra_sor_hdmi_setup_avi_infoframe(sor, mode); 2162459cc2c6SThierry Reding if (err < 0) 2163459cc2c6SThierry Reding dev_err(sor->dev, "failed to setup AVI infoframe: %d\n", err); 2164459cc2c6SThierry Reding 2165459cc2c6SThierry Reding /* XXX HDMI audio support not implemented yet */ 2166459cc2c6SThierry Reding tegra_sor_hdmi_disable_audio_infoframe(sor); 2167459cc2c6SThierry Reding 2168459cc2c6SThierry Reding /* use single TMDS protocol */ 2169459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_STATE1); 2170459cc2c6SThierry Reding value &= ~SOR_STATE_ASY_PROTOCOL_MASK; 2171459cc2c6SThierry Reding value |= SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A; 2172459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_STATE1); 2173459cc2c6SThierry Reding 2174459cc2c6SThierry Reding /* power up pad calibration */ 2175459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 2176459cc2c6SThierry Reding value &= ~SOR_DP_PADCTL_PAD_CAL_PD; 2177459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 2178459cc2c6SThierry Reding 2179459cc2c6SThierry Reding /* production settings */ 2180459cc2c6SThierry Reding settings = tegra_sor_hdmi_find_settings(sor, mode->clock * 1000); 2181db8b42fbSDan Carpenter if (!settings) { 2182db8b42fbSDan Carpenter dev_err(sor->dev, "no settings for pixel clock %d Hz\n", 2183db8b42fbSDan Carpenter mode->clock * 1000); 2184459cc2c6SThierry Reding return; 2185459cc2c6SThierry Reding } 2186459cc2c6SThierry Reding 2187459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_PLL0); 2188459cc2c6SThierry Reding value &= ~SOR_PLL0_ICHPMP_MASK; 2189459cc2c6SThierry Reding value &= ~SOR_PLL0_VCOCAP_MASK; 2190459cc2c6SThierry Reding value |= SOR_PLL0_ICHPMP(settings->ichpmp); 2191459cc2c6SThierry Reding value |= SOR_PLL0_VCOCAP(settings->vcocap); 2192459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_PLL0); 2193459cc2c6SThierry Reding 2194459cc2c6SThierry Reding tegra_sor_dp_term_calibrate(sor); 2195459cc2c6SThierry Reding 2196459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_PLL1); 2197459cc2c6SThierry Reding value &= ~SOR_PLL1_LOADADJ_MASK; 2198459cc2c6SThierry Reding value |= SOR_PLL1_LOADADJ(settings->loadadj); 2199459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_PLL1); 2200459cc2c6SThierry Reding 2201459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_PLL3); 2202459cc2c6SThierry Reding value &= ~SOR_PLL3_BG_VREF_LEVEL_MASK; 2203459cc2c6SThierry Reding value |= SOR_PLL3_BG_VREF_LEVEL(settings->bg_vref); 2204459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_PLL3); 2205459cc2c6SThierry Reding 2206459cc2c6SThierry Reding value = settings->drive_current[0] << 24 | 2207459cc2c6SThierry Reding settings->drive_current[1] << 16 | 2208459cc2c6SThierry Reding settings->drive_current[2] << 8 | 2209459cc2c6SThierry Reding settings->drive_current[3] << 0; 2210459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_DRIVE_CURRENT0); 2211459cc2c6SThierry Reding 2212459cc2c6SThierry Reding value = settings->preemphasis[0] << 24 | 2213459cc2c6SThierry Reding settings->preemphasis[1] << 16 | 2214459cc2c6SThierry Reding settings->preemphasis[2] << 8 | 2215459cc2c6SThierry Reding settings->preemphasis[3] << 0; 2216459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_PREEMPHASIS0); 2217459cc2c6SThierry Reding 2218459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 2219459cc2c6SThierry Reding value &= ~SOR_DP_PADCTL_TX_PU_MASK; 2220459cc2c6SThierry Reding value |= SOR_DP_PADCTL_TX_PU_ENABLE; 2221459cc2c6SThierry Reding value |= SOR_DP_PADCTL_TX_PU(settings->tx_pu); 2222459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 2223459cc2c6SThierry Reding 2224459cc2c6SThierry Reding /* power down pad calibration */ 2225459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 2226459cc2c6SThierry Reding value |= SOR_DP_PADCTL_PAD_CAL_PD; 2227459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 2228459cc2c6SThierry Reding 2229459cc2c6SThierry Reding /* miscellaneous display controller settings */ 2230459cc2c6SThierry Reding value = VSYNC_H_POSITION(1); 2231459cc2c6SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_TIMING_OPTIONS); 2232459cc2c6SThierry Reding 2233459cc2c6SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_COLOR_CONTROL); 2234459cc2c6SThierry Reding value &= ~DITHER_CONTROL_MASK; 2235459cc2c6SThierry Reding value &= ~BASE_COLOR_SIZE_MASK; 2236459cc2c6SThierry Reding 2237c31efa7aSThierry Reding switch (state->bpc) { 2238459cc2c6SThierry Reding case 6: 2239459cc2c6SThierry Reding value |= BASE_COLOR_SIZE_666; 2240459cc2c6SThierry Reding break; 2241459cc2c6SThierry Reding 2242459cc2c6SThierry Reding case 8: 2243459cc2c6SThierry Reding value |= BASE_COLOR_SIZE_888; 2244459cc2c6SThierry Reding break; 2245459cc2c6SThierry Reding 2246459cc2c6SThierry Reding default: 2247c31efa7aSThierry Reding WARN(1, "%u bits-per-color not supported\n", state->bpc); 2248c31efa7aSThierry Reding value |= BASE_COLOR_SIZE_888; 2249459cc2c6SThierry Reding break; 2250459cc2c6SThierry Reding } 2251459cc2c6SThierry Reding 2252459cc2c6SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_COLOR_CONTROL); 2253459cc2c6SThierry Reding 2254459cc2c6SThierry Reding err = tegra_sor_power_up(sor, 250); 2255459cc2c6SThierry Reding if (err < 0) 2256459cc2c6SThierry Reding dev_err(sor->dev, "failed to power up SOR: %d\n", err); 2257459cc2c6SThierry Reding 22582bd1dd39SThierry Reding /* configure dynamic range of output */ 2259459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_HEAD_STATE0(dc->pipe)); 2260459cc2c6SThierry Reding value &= ~SOR_HEAD_STATE_RANGECOMPRESS_MASK; 2261459cc2c6SThierry Reding value &= ~SOR_HEAD_STATE_DYNRANGE_MASK; 2262459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_HEAD_STATE0(dc->pipe)); 2263459cc2c6SThierry Reding 22642bd1dd39SThierry Reding /* configure colorspace */ 2265459cc2c6SThierry Reding value = tegra_sor_readl(sor, SOR_HEAD_STATE0(dc->pipe)); 2266459cc2c6SThierry Reding value &= ~SOR_HEAD_STATE_COLORSPACE_MASK; 2267459cc2c6SThierry Reding value |= SOR_HEAD_STATE_COLORSPACE_RGB; 2268459cc2c6SThierry Reding tegra_sor_writel(sor, value, SOR_HEAD_STATE0(dc->pipe)); 2269459cc2c6SThierry Reding 2270c31efa7aSThierry Reding tegra_sor_mode_set(sor, mode, state); 2271459cc2c6SThierry Reding 2272459cc2c6SThierry Reding tegra_sor_update(sor); 2273459cc2c6SThierry Reding 2274459cc2c6SThierry Reding err = tegra_sor_attach(sor); 2275459cc2c6SThierry Reding if (err < 0) 2276459cc2c6SThierry Reding dev_err(sor->dev, "failed to attach SOR: %d\n", err); 2277459cc2c6SThierry Reding 2278459cc2c6SThierry Reding /* enable display to SOR clock and generate HDMI preamble */ 2279459cc2c6SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 2280459cc2c6SThierry Reding value |= SOR1_ENABLE | SOR1_TIMING_CYA; 2281459cc2c6SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 2282459cc2c6SThierry Reding 2283459cc2c6SThierry Reding tegra_dc_commit(dc); 2284459cc2c6SThierry Reding 2285459cc2c6SThierry Reding err = tegra_sor_wakeup(sor); 2286459cc2c6SThierry Reding if (err < 0) 2287459cc2c6SThierry Reding dev_err(sor->dev, "failed to wakeup SOR: %d\n", err); 2288459cc2c6SThierry Reding } 2289459cc2c6SThierry Reding 2290459cc2c6SThierry Reding static const struct drm_encoder_helper_funcs tegra_sor_hdmi_helpers = { 2291459cc2c6SThierry Reding .disable = tegra_sor_hdmi_disable, 2292459cc2c6SThierry Reding .enable = tegra_sor_hdmi_enable, 2293459cc2c6SThierry Reding .atomic_check = tegra_sor_encoder_atomic_check, 2294459cc2c6SThierry Reding }; 2295459cc2c6SThierry Reding 22966b6b6042SThierry Reding static int tegra_sor_init(struct host1x_client *client) 22976b6b6042SThierry Reding { 22989910f5c4SThierry Reding struct drm_device *drm = dev_get_drvdata(client->parent); 2299459cc2c6SThierry Reding const struct drm_encoder_helper_funcs *helpers = NULL; 23006b6b6042SThierry Reding struct tegra_sor *sor = host1x_client_to_sor(client); 2301459cc2c6SThierry Reding int connector = DRM_MODE_CONNECTOR_Unknown; 2302459cc2c6SThierry Reding int encoder = DRM_MODE_ENCODER_NONE; 23036b6b6042SThierry Reding int err; 23046b6b6042SThierry Reding 23059542c237SThierry Reding if (!sor->aux) { 2306459cc2c6SThierry Reding if (sor->soc->supports_hdmi) { 2307459cc2c6SThierry Reding connector = DRM_MODE_CONNECTOR_HDMIA; 2308459cc2c6SThierry Reding encoder = DRM_MODE_ENCODER_TMDS; 2309459cc2c6SThierry Reding helpers = &tegra_sor_hdmi_helpers; 2310459cc2c6SThierry Reding } else if (sor->soc->supports_lvds) { 2311459cc2c6SThierry Reding connector = DRM_MODE_CONNECTOR_LVDS; 2312459cc2c6SThierry Reding encoder = DRM_MODE_ENCODER_LVDS; 2313459cc2c6SThierry Reding } 2314459cc2c6SThierry Reding } else { 2315459cc2c6SThierry Reding if (sor->soc->supports_edp) { 2316459cc2c6SThierry Reding connector = DRM_MODE_CONNECTOR_eDP; 2317459cc2c6SThierry Reding encoder = DRM_MODE_ENCODER_TMDS; 2318459cc2c6SThierry Reding helpers = &tegra_sor_edp_helpers; 2319459cc2c6SThierry Reding } else if (sor->soc->supports_dp) { 2320459cc2c6SThierry Reding connector = DRM_MODE_CONNECTOR_DisplayPort; 2321459cc2c6SThierry Reding encoder = DRM_MODE_ENCODER_TMDS; 2322459cc2c6SThierry Reding } 2323459cc2c6SThierry Reding } 23246b6b6042SThierry Reding 23256b6b6042SThierry Reding sor->output.dev = sor->dev; 23266b6b6042SThierry Reding 23276fad8f66SThierry Reding drm_connector_init(drm, &sor->output.connector, 23286fad8f66SThierry Reding &tegra_sor_connector_funcs, 2329459cc2c6SThierry Reding connector); 23306fad8f66SThierry Reding drm_connector_helper_add(&sor->output.connector, 23316fad8f66SThierry Reding &tegra_sor_connector_helper_funcs); 23326fad8f66SThierry Reding sor->output.connector.dpms = DRM_MODE_DPMS_OFF; 23336fad8f66SThierry Reding 23346fad8f66SThierry Reding drm_encoder_init(drm, &sor->output.encoder, &tegra_sor_encoder_funcs, 233513a3d91fSVille Syrjälä encoder, NULL); 2336459cc2c6SThierry Reding drm_encoder_helper_add(&sor->output.encoder, helpers); 23376fad8f66SThierry Reding 23386fad8f66SThierry Reding drm_mode_connector_attach_encoder(&sor->output.connector, 23396fad8f66SThierry Reding &sor->output.encoder); 23406fad8f66SThierry Reding drm_connector_register(&sor->output.connector); 23416fad8f66SThierry Reding 2342ea130b24SThierry Reding err = tegra_output_init(drm, &sor->output); 2343ea130b24SThierry Reding if (err < 0) { 2344ea130b24SThierry Reding dev_err(client->dev, "failed to initialize output: %d\n", err); 2345ea130b24SThierry Reding return err; 2346ea130b24SThierry Reding } 23476fad8f66SThierry Reding 2348ea130b24SThierry Reding sor->output.encoder.possible_crtcs = 0x3; 23496b6b6042SThierry Reding 2350a82752e1SThierry Reding if (IS_ENABLED(CONFIG_DEBUG_FS)) { 23511b0c7b48SThierry Reding err = tegra_sor_debugfs_init(sor, drm->primary); 2352a82752e1SThierry Reding if (err < 0) 2353a82752e1SThierry Reding dev_err(sor->dev, "debugfs setup failed: %d\n", err); 2354a82752e1SThierry Reding } 2355a82752e1SThierry Reding 23569542c237SThierry Reding if (sor->aux) { 23579542c237SThierry Reding err = drm_dp_aux_attach(sor->aux, &sor->output); 23586b6b6042SThierry Reding if (err < 0) { 23596b6b6042SThierry Reding dev_err(sor->dev, "failed to attach DP: %d\n", err); 23606b6b6042SThierry Reding return err; 23616b6b6042SThierry Reding } 23626b6b6042SThierry Reding } 23636b6b6042SThierry Reding 2364535a65dbSTomeu Vizoso /* 2365535a65dbSTomeu Vizoso * XXX: Remove this reset once proper hand-over from firmware to 2366535a65dbSTomeu Vizoso * kernel is possible. 2367535a65dbSTomeu Vizoso */ 2368f8c79120SJon Hunter if (sor->rst) { 2369535a65dbSTomeu Vizoso err = reset_control_assert(sor->rst); 2370535a65dbSTomeu Vizoso if (err < 0) { 2371f8c79120SJon Hunter dev_err(sor->dev, "failed to assert SOR reset: %d\n", 2372f8c79120SJon Hunter err); 2373535a65dbSTomeu Vizoso return err; 2374535a65dbSTomeu Vizoso } 2375f8c79120SJon Hunter } 2376535a65dbSTomeu Vizoso 23776fad8f66SThierry Reding err = clk_prepare_enable(sor->clk); 23786fad8f66SThierry Reding if (err < 0) { 23796fad8f66SThierry Reding dev_err(sor->dev, "failed to enable clock: %d\n", err); 23806fad8f66SThierry Reding return err; 23816fad8f66SThierry Reding } 23826fad8f66SThierry Reding 2383535a65dbSTomeu Vizoso usleep_range(1000, 3000); 2384535a65dbSTomeu Vizoso 2385f8c79120SJon Hunter if (sor->rst) { 2386535a65dbSTomeu Vizoso err = reset_control_deassert(sor->rst); 2387535a65dbSTomeu Vizoso if (err < 0) { 2388f8c79120SJon Hunter dev_err(sor->dev, "failed to deassert SOR reset: %d\n", 2389f8c79120SJon Hunter err); 2390535a65dbSTomeu Vizoso return err; 2391535a65dbSTomeu Vizoso } 2392f8c79120SJon Hunter } 2393535a65dbSTomeu Vizoso 23946fad8f66SThierry Reding err = clk_prepare_enable(sor->clk_safe); 23956fad8f66SThierry Reding if (err < 0) 23966fad8f66SThierry Reding return err; 23976fad8f66SThierry Reding 23986fad8f66SThierry Reding err = clk_prepare_enable(sor->clk_dp); 23996fad8f66SThierry Reding if (err < 0) 24006fad8f66SThierry Reding return err; 24016fad8f66SThierry Reding 24026b6b6042SThierry Reding return 0; 24036b6b6042SThierry Reding } 24046b6b6042SThierry Reding 24056b6b6042SThierry Reding static int tegra_sor_exit(struct host1x_client *client) 24066b6b6042SThierry Reding { 24076b6b6042SThierry Reding struct tegra_sor *sor = host1x_client_to_sor(client); 24086b6b6042SThierry Reding int err; 24096b6b6042SThierry Reding 2410328ec69eSThierry Reding tegra_output_exit(&sor->output); 2411328ec69eSThierry Reding 24129542c237SThierry Reding if (sor->aux) { 24139542c237SThierry Reding err = drm_dp_aux_detach(sor->aux); 24146b6b6042SThierry Reding if (err < 0) { 24156b6b6042SThierry Reding dev_err(sor->dev, "failed to detach DP: %d\n", err); 24166b6b6042SThierry Reding return err; 24176b6b6042SThierry Reding } 24186b6b6042SThierry Reding } 24196b6b6042SThierry Reding 24206fad8f66SThierry Reding clk_disable_unprepare(sor->clk_safe); 24216fad8f66SThierry Reding clk_disable_unprepare(sor->clk_dp); 24226fad8f66SThierry Reding clk_disable_unprepare(sor->clk); 24236fad8f66SThierry Reding 24244009c224SThierry Reding if (IS_ENABLED(CONFIG_DEBUG_FS)) 24254009c224SThierry Reding tegra_sor_debugfs_exit(sor); 2426a82752e1SThierry Reding 24276b6b6042SThierry Reding return 0; 24286b6b6042SThierry Reding } 24296b6b6042SThierry Reding 24306b6b6042SThierry Reding static const struct host1x_client_ops sor_client_ops = { 24316b6b6042SThierry Reding .init = tegra_sor_init, 24326b6b6042SThierry Reding .exit = tegra_sor_exit, 24336b6b6042SThierry Reding }; 24346b6b6042SThierry Reding 2435459cc2c6SThierry Reding static const struct tegra_sor_ops tegra_sor_edp_ops = { 2436459cc2c6SThierry Reding .name = "eDP", 2437459cc2c6SThierry Reding }; 2438459cc2c6SThierry Reding 2439459cc2c6SThierry Reding static int tegra_sor_hdmi_probe(struct tegra_sor *sor) 2440459cc2c6SThierry Reding { 2441459cc2c6SThierry Reding int err; 2442459cc2c6SThierry Reding 2443459cc2c6SThierry Reding sor->avdd_io_supply = devm_regulator_get(sor->dev, "avdd-io"); 2444459cc2c6SThierry Reding if (IS_ERR(sor->avdd_io_supply)) { 2445459cc2c6SThierry Reding dev_err(sor->dev, "cannot get AVDD I/O supply: %ld\n", 2446459cc2c6SThierry Reding PTR_ERR(sor->avdd_io_supply)); 2447459cc2c6SThierry Reding return PTR_ERR(sor->avdd_io_supply); 2448459cc2c6SThierry Reding } 2449459cc2c6SThierry Reding 2450459cc2c6SThierry Reding err = regulator_enable(sor->avdd_io_supply); 2451459cc2c6SThierry Reding if (err < 0) { 2452459cc2c6SThierry Reding dev_err(sor->dev, "failed to enable AVDD I/O supply: %d\n", 2453459cc2c6SThierry Reding err); 2454459cc2c6SThierry Reding return err; 2455459cc2c6SThierry Reding } 2456459cc2c6SThierry Reding 2457459cc2c6SThierry Reding sor->vdd_pll_supply = devm_regulator_get(sor->dev, "vdd-pll"); 2458459cc2c6SThierry Reding if (IS_ERR(sor->vdd_pll_supply)) { 2459459cc2c6SThierry Reding dev_err(sor->dev, "cannot get VDD PLL supply: %ld\n", 2460459cc2c6SThierry Reding PTR_ERR(sor->vdd_pll_supply)); 2461459cc2c6SThierry Reding return PTR_ERR(sor->vdd_pll_supply); 2462459cc2c6SThierry Reding } 2463459cc2c6SThierry Reding 2464459cc2c6SThierry Reding err = regulator_enable(sor->vdd_pll_supply); 2465459cc2c6SThierry Reding if (err < 0) { 2466459cc2c6SThierry Reding dev_err(sor->dev, "failed to enable VDD PLL supply: %d\n", 2467459cc2c6SThierry Reding err); 2468459cc2c6SThierry Reding return err; 2469459cc2c6SThierry Reding } 2470459cc2c6SThierry Reding 2471459cc2c6SThierry Reding sor->hdmi_supply = devm_regulator_get(sor->dev, "hdmi"); 2472459cc2c6SThierry Reding if (IS_ERR(sor->hdmi_supply)) { 2473459cc2c6SThierry Reding dev_err(sor->dev, "cannot get HDMI supply: %ld\n", 2474459cc2c6SThierry Reding PTR_ERR(sor->hdmi_supply)); 2475459cc2c6SThierry Reding return PTR_ERR(sor->hdmi_supply); 2476459cc2c6SThierry Reding } 2477459cc2c6SThierry Reding 2478459cc2c6SThierry Reding err = regulator_enable(sor->hdmi_supply); 2479459cc2c6SThierry Reding if (err < 0) { 2480459cc2c6SThierry Reding dev_err(sor->dev, "failed to enable HDMI supply: %d\n", err); 2481459cc2c6SThierry Reding return err; 2482459cc2c6SThierry Reding } 2483459cc2c6SThierry Reding 2484459cc2c6SThierry Reding return 0; 2485459cc2c6SThierry Reding } 2486459cc2c6SThierry Reding 2487459cc2c6SThierry Reding static int tegra_sor_hdmi_remove(struct tegra_sor *sor) 2488459cc2c6SThierry Reding { 2489459cc2c6SThierry Reding regulator_disable(sor->hdmi_supply); 2490459cc2c6SThierry Reding regulator_disable(sor->vdd_pll_supply); 2491459cc2c6SThierry Reding regulator_disable(sor->avdd_io_supply); 2492459cc2c6SThierry Reding 2493459cc2c6SThierry Reding return 0; 2494459cc2c6SThierry Reding } 2495459cc2c6SThierry Reding 2496459cc2c6SThierry Reding static const struct tegra_sor_ops tegra_sor_hdmi_ops = { 2497459cc2c6SThierry Reding .name = "HDMI", 2498459cc2c6SThierry Reding .probe = tegra_sor_hdmi_probe, 2499459cc2c6SThierry Reding .remove = tegra_sor_hdmi_remove, 2500459cc2c6SThierry Reding }; 2501459cc2c6SThierry Reding 250230b49435SThierry Reding static const u8 tegra124_sor_xbar_cfg[5] = { 250330b49435SThierry Reding 0, 1, 2, 3, 4 250430b49435SThierry Reding }; 250530b49435SThierry Reding 2506459cc2c6SThierry Reding static const struct tegra_sor_soc tegra124_sor = { 2507459cc2c6SThierry Reding .supports_edp = true, 2508459cc2c6SThierry Reding .supports_lvds = true, 2509459cc2c6SThierry Reding .supports_hdmi = false, 2510459cc2c6SThierry Reding .supports_dp = false, 251130b49435SThierry Reding .xbar_cfg = tegra124_sor_xbar_cfg, 2512459cc2c6SThierry Reding }; 2513459cc2c6SThierry Reding 2514459cc2c6SThierry Reding static const struct tegra_sor_soc tegra210_sor = { 2515459cc2c6SThierry Reding .supports_edp = true, 2516459cc2c6SThierry Reding .supports_lvds = false, 2517459cc2c6SThierry Reding .supports_hdmi = false, 2518459cc2c6SThierry Reding .supports_dp = false, 251930b49435SThierry Reding .xbar_cfg = tegra124_sor_xbar_cfg, 252030b49435SThierry Reding }; 252130b49435SThierry Reding 252230b49435SThierry Reding static const u8 tegra210_sor_xbar_cfg[5] = { 252330b49435SThierry Reding 2, 1, 0, 3, 4 2524459cc2c6SThierry Reding }; 2525459cc2c6SThierry Reding 2526459cc2c6SThierry Reding static const struct tegra_sor_soc tegra210_sor1 = { 2527459cc2c6SThierry Reding .supports_edp = false, 2528459cc2c6SThierry Reding .supports_lvds = false, 2529459cc2c6SThierry Reding .supports_hdmi = true, 2530459cc2c6SThierry Reding .supports_dp = true, 2531459cc2c6SThierry Reding 2532459cc2c6SThierry Reding .num_settings = ARRAY_SIZE(tegra210_sor_hdmi_defaults), 2533459cc2c6SThierry Reding .settings = tegra210_sor_hdmi_defaults, 253430b49435SThierry Reding 253530b49435SThierry Reding .xbar_cfg = tegra210_sor_xbar_cfg, 2536459cc2c6SThierry Reding }; 2537459cc2c6SThierry Reding 2538459cc2c6SThierry Reding static const struct of_device_id tegra_sor_of_match[] = { 2539459cc2c6SThierry Reding { .compatible = "nvidia,tegra210-sor1", .data = &tegra210_sor1 }, 2540459cc2c6SThierry Reding { .compatible = "nvidia,tegra210-sor", .data = &tegra210_sor }, 2541459cc2c6SThierry Reding { .compatible = "nvidia,tegra124-sor", .data = &tegra124_sor }, 2542459cc2c6SThierry Reding { }, 2543459cc2c6SThierry Reding }; 2544459cc2c6SThierry Reding MODULE_DEVICE_TABLE(of, tegra_sor_of_match); 2545459cc2c6SThierry Reding 25466b6b6042SThierry Reding static int tegra_sor_probe(struct platform_device *pdev) 25476b6b6042SThierry Reding { 25486b6b6042SThierry Reding struct device_node *np; 25496b6b6042SThierry Reding struct tegra_sor *sor; 25506b6b6042SThierry Reding struct resource *regs; 25516b6b6042SThierry Reding int err; 25526b6b6042SThierry Reding 25536b6b6042SThierry Reding sor = devm_kzalloc(&pdev->dev, sizeof(*sor), GFP_KERNEL); 25546b6b6042SThierry Reding if (!sor) 25556b6b6042SThierry Reding return -ENOMEM; 25566b6b6042SThierry Reding 25575faea3d0SThierry Reding sor->soc = of_device_get_match_data(&pdev->dev); 25586b6b6042SThierry Reding sor->output.dev = sor->dev = &pdev->dev; 2559459cc2c6SThierry Reding 2560459cc2c6SThierry Reding sor->settings = devm_kmemdup(&pdev->dev, sor->soc->settings, 2561459cc2c6SThierry Reding sor->soc->num_settings * 2562459cc2c6SThierry Reding sizeof(*sor->settings), 2563459cc2c6SThierry Reding GFP_KERNEL); 2564459cc2c6SThierry Reding if (!sor->settings) 2565459cc2c6SThierry Reding return -ENOMEM; 2566459cc2c6SThierry Reding 2567459cc2c6SThierry Reding sor->num_settings = sor->soc->num_settings; 25686b6b6042SThierry Reding 25696b6b6042SThierry Reding np = of_parse_phandle(pdev->dev.of_node, "nvidia,dpaux", 0); 25706b6b6042SThierry Reding if (np) { 25719542c237SThierry Reding sor->aux = drm_dp_aux_find_by_of_node(np); 25726b6b6042SThierry Reding of_node_put(np); 25736b6b6042SThierry Reding 25749542c237SThierry Reding if (!sor->aux) 25756b6b6042SThierry Reding return -EPROBE_DEFER; 25766b6b6042SThierry Reding } 25776b6b6042SThierry Reding 25789542c237SThierry Reding if (!sor->aux) { 2579459cc2c6SThierry Reding if (sor->soc->supports_hdmi) { 2580459cc2c6SThierry Reding sor->ops = &tegra_sor_hdmi_ops; 2581459cc2c6SThierry Reding } else if (sor->soc->supports_lvds) { 2582459cc2c6SThierry Reding dev_err(&pdev->dev, "LVDS not supported yet\n"); 2583459cc2c6SThierry Reding return -ENODEV; 2584459cc2c6SThierry Reding } else { 2585459cc2c6SThierry Reding dev_err(&pdev->dev, "unknown (non-DP) support\n"); 2586459cc2c6SThierry Reding return -ENODEV; 2587459cc2c6SThierry Reding } 2588459cc2c6SThierry Reding } else { 2589459cc2c6SThierry Reding if (sor->soc->supports_edp) { 2590459cc2c6SThierry Reding sor->ops = &tegra_sor_edp_ops; 2591459cc2c6SThierry Reding } else if (sor->soc->supports_dp) { 2592459cc2c6SThierry Reding dev_err(&pdev->dev, "DisplayPort not supported yet\n"); 2593459cc2c6SThierry Reding return -ENODEV; 2594459cc2c6SThierry Reding } else { 2595459cc2c6SThierry Reding dev_err(&pdev->dev, "unknown (DP) support\n"); 2596459cc2c6SThierry Reding return -ENODEV; 2597459cc2c6SThierry Reding } 2598459cc2c6SThierry Reding } 2599459cc2c6SThierry Reding 26006b6b6042SThierry Reding err = tegra_output_probe(&sor->output); 26014dbdc740SThierry Reding if (err < 0) { 26024dbdc740SThierry Reding dev_err(&pdev->dev, "failed to probe output: %d\n", err); 26036b6b6042SThierry Reding return err; 26044dbdc740SThierry Reding } 26056b6b6042SThierry Reding 2606459cc2c6SThierry Reding if (sor->ops && sor->ops->probe) { 2607459cc2c6SThierry Reding err = sor->ops->probe(sor); 2608459cc2c6SThierry Reding if (err < 0) { 2609459cc2c6SThierry Reding dev_err(&pdev->dev, "failed to probe %s: %d\n", 2610459cc2c6SThierry Reding sor->ops->name, err); 2611459cc2c6SThierry Reding goto output; 2612459cc2c6SThierry Reding } 2613459cc2c6SThierry Reding } 2614459cc2c6SThierry Reding 26156b6b6042SThierry Reding regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 26166b6b6042SThierry Reding sor->regs = devm_ioremap_resource(&pdev->dev, regs); 2617459cc2c6SThierry Reding if (IS_ERR(sor->regs)) { 2618459cc2c6SThierry Reding err = PTR_ERR(sor->regs); 2619459cc2c6SThierry Reding goto remove; 2620459cc2c6SThierry Reding } 26216b6b6042SThierry Reding 2622f8c79120SJon Hunter if (!pdev->dev.pm_domain) { 26236b6b6042SThierry Reding sor->rst = devm_reset_control_get(&pdev->dev, "sor"); 26244dbdc740SThierry Reding if (IS_ERR(sor->rst)) { 2625459cc2c6SThierry Reding err = PTR_ERR(sor->rst); 2626f8c79120SJon Hunter dev_err(&pdev->dev, "failed to get reset control: %d\n", 2627f8c79120SJon Hunter err); 2628459cc2c6SThierry Reding goto remove; 26294dbdc740SThierry Reding } 2630f8c79120SJon Hunter } 26316b6b6042SThierry Reding 26326b6b6042SThierry Reding sor->clk = devm_clk_get(&pdev->dev, NULL); 26334dbdc740SThierry Reding if (IS_ERR(sor->clk)) { 2634459cc2c6SThierry Reding err = PTR_ERR(sor->clk); 2635459cc2c6SThierry Reding dev_err(&pdev->dev, "failed to get module clock: %d\n", err); 2636459cc2c6SThierry Reding goto remove; 26374dbdc740SThierry Reding } 26386b6b6042SThierry Reding 2639618dee39SThierry Reding if (sor->soc->supports_hdmi || sor->soc->supports_dp) { 2640e1335e2fSThierry Reding struct device_node *np = pdev->dev.of_node; 2641e1335e2fSThierry Reding const char *name; 2642e1335e2fSThierry Reding 2643e1335e2fSThierry Reding /* 2644e1335e2fSThierry Reding * For backwards compatibility with Tegra210 device trees, 2645e1335e2fSThierry Reding * fall back to the old clock name "source" if the new "out" 2646e1335e2fSThierry Reding * clock is not available. 2647e1335e2fSThierry Reding */ 2648e1335e2fSThierry Reding if (of_property_match_string(np, "clock-names", "out") < 0) 2649e1335e2fSThierry Reding name = "source"; 2650e1335e2fSThierry Reding else 2651e1335e2fSThierry Reding name = "out"; 2652e1335e2fSThierry Reding 2653e1335e2fSThierry Reding sor->clk_out = devm_clk_get(&pdev->dev, name); 2654e1335e2fSThierry Reding if (IS_ERR(sor->clk_out)) { 2655e1335e2fSThierry Reding err = PTR_ERR(sor->clk_out); 2656e1335e2fSThierry Reding dev_err(sor->dev, "failed to get %s clock: %d\n", 2657e1335e2fSThierry Reding name, err); 2658618dee39SThierry Reding goto remove; 2659618dee39SThierry Reding } 2660618dee39SThierry Reding } 2661618dee39SThierry Reding 26626b6b6042SThierry Reding sor->clk_parent = devm_clk_get(&pdev->dev, "parent"); 26634dbdc740SThierry Reding if (IS_ERR(sor->clk_parent)) { 2664459cc2c6SThierry Reding err = PTR_ERR(sor->clk_parent); 2665459cc2c6SThierry Reding dev_err(&pdev->dev, "failed to get parent clock: %d\n", err); 2666459cc2c6SThierry Reding goto remove; 26674dbdc740SThierry Reding } 26686b6b6042SThierry Reding 26696b6b6042SThierry Reding sor->clk_safe = devm_clk_get(&pdev->dev, "safe"); 26704dbdc740SThierry Reding if (IS_ERR(sor->clk_safe)) { 2671459cc2c6SThierry Reding err = PTR_ERR(sor->clk_safe); 2672459cc2c6SThierry Reding dev_err(&pdev->dev, "failed to get safe clock: %d\n", err); 2673459cc2c6SThierry Reding goto remove; 26744dbdc740SThierry Reding } 26756b6b6042SThierry Reding 26766b6b6042SThierry Reding sor->clk_dp = devm_clk_get(&pdev->dev, "dp"); 26774dbdc740SThierry Reding if (IS_ERR(sor->clk_dp)) { 2678459cc2c6SThierry Reding err = PTR_ERR(sor->clk_dp); 2679459cc2c6SThierry Reding dev_err(&pdev->dev, "failed to get DP clock: %d\n", err); 2680459cc2c6SThierry Reding goto remove; 26814dbdc740SThierry Reding } 26826b6b6042SThierry Reding 2683e1335e2fSThierry Reding /* 2684e1335e2fSThierry Reding * Starting with Tegra186, the BPMP provides an implementation for 2685e1335e2fSThierry Reding * the pad output clock, so we have to look it up from device tree. 2686e1335e2fSThierry Reding */ 2687e1335e2fSThierry Reding sor->clk_pad = devm_clk_get(&pdev->dev, "pad"); 2688e1335e2fSThierry Reding if (IS_ERR(sor->clk_pad)) { 2689e1335e2fSThierry Reding if (sor->clk_pad != ERR_PTR(-ENOENT)) { 2690e1335e2fSThierry Reding err = PTR_ERR(sor->clk_pad); 2691e1335e2fSThierry Reding goto remove; 2692e1335e2fSThierry Reding } 2693e1335e2fSThierry Reding 2694e1335e2fSThierry Reding /* 2695e1335e2fSThierry Reding * If the pad output clock is not available, then we assume 2696e1335e2fSThierry Reding * we're on Tegra210 or earlier and have to provide our own 2697e1335e2fSThierry Reding * implementation. 2698e1335e2fSThierry Reding */ 2699e1335e2fSThierry Reding sor->clk_pad = NULL; 2700e1335e2fSThierry Reding } 2701e1335e2fSThierry Reding 2702e1335e2fSThierry Reding /* 2703e1335e2fSThierry Reding * The bootloader may have set up the SOR such that it's module clock 2704e1335e2fSThierry Reding * is sourced by one of the display PLLs. However, that doesn't work 2705e1335e2fSThierry Reding * without properly having set up other bits of the SOR. 2706e1335e2fSThierry Reding */ 2707e1335e2fSThierry Reding err = clk_set_parent(sor->clk_out, sor->clk_safe); 2708e1335e2fSThierry Reding if (err < 0) { 2709e1335e2fSThierry Reding dev_err(&pdev->dev, "failed to use safe clock: %d\n", err); 2710e1335e2fSThierry Reding goto remove; 2711e1335e2fSThierry Reding } 2712e1335e2fSThierry Reding 2713aaff8bd2SThierry Reding platform_set_drvdata(pdev, sor); 2714aaff8bd2SThierry Reding pm_runtime_enable(&pdev->dev); 2715aaff8bd2SThierry Reding 2716e1335e2fSThierry Reding /* 2717e1335e2fSThierry Reding * On Tegra210 and earlier, provide our own implementation for the 2718e1335e2fSThierry Reding * pad output clock. 2719e1335e2fSThierry Reding */ 2720e1335e2fSThierry Reding if (!sor->clk_pad) { 2721e1335e2fSThierry Reding err = pm_runtime_get_sync(&pdev->dev); 2722e1335e2fSThierry Reding if (err < 0) { 2723e1335e2fSThierry Reding dev_err(&pdev->dev, "failed to get runtime PM: %d\n", 2724e1335e2fSThierry Reding err); 2725e1335e2fSThierry Reding goto remove; 2726e1335e2fSThierry Reding } 2727b299221cSThierry Reding 2728e1335e2fSThierry Reding sor->clk_pad = tegra_clk_sor_pad_register(sor, 2729e1335e2fSThierry Reding "sor1_pad_clkout"); 2730e1335e2fSThierry Reding pm_runtime_put(&pdev->dev); 2731e1335e2fSThierry Reding } 2732e1335e2fSThierry Reding 2733e1335e2fSThierry Reding if (IS_ERR(sor->clk_pad)) { 2734e1335e2fSThierry Reding err = PTR_ERR(sor->clk_pad); 2735e1335e2fSThierry Reding dev_err(&pdev->dev, "failed to register SOR pad clock: %d\n", 2736e1335e2fSThierry Reding err); 2737b299221cSThierry Reding goto remove; 2738b299221cSThierry Reding } 2739b299221cSThierry Reding 27406b6b6042SThierry Reding INIT_LIST_HEAD(&sor->client.list); 27416b6b6042SThierry Reding sor->client.ops = &sor_client_ops; 27426b6b6042SThierry Reding sor->client.dev = &pdev->dev; 27436b6b6042SThierry Reding 27446b6b6042SThierry Reding err = host1x_client_register(&sor->client); 27456b6b6042SThierry Reding if (err < 0) { 27466b6b6042SThierry Reding dev_err(&pdev->dev, "failed to register host1x client: %d\n", 27476b6b6042SThierry Reding err); 2748459cc2c6SThierry Reding goto remove; 27496b6b6042SThierry Reding } 27506b6b6042SThierry Reding 27516b6b6042SThierry Reding return 0; 2752459cc2c6SThierry Reding 2753459cc2c6SThierry Reding remove: 2754459cc2c6SThierry Reding if (sor->ops && sor->ops->remove) 2755459cc2c6SThierry Reding sor->ops->remove(sor); 2756459cc2c6SThierry Reding output: 2757459cc2c6SThierry Reding tegra_output_remove(&sor->output); 2758459cc2c6SThierry Reding return err; 27596b6b6042SThierry Reding } 27606b6b6042SThierry Reding 27616b6b6042SThierry Reding static int tegra_sor_remove(struct platform_device *pdev) 27626b6b6042SThierry Reding { 27636b6b6042SThierry Reding struct tegra_sor *sor = platform_get_drvdata(pdev); 27646b6b6042SThierry Reding int err; 27656b6b6042SThierry Reding 2766aaff8bd2SThierry Reding pm_runtime_disable(&pdev->dev); 2767aaff8bd2SThierry Reding 27686b6b6042SThierry Reding err = host1x_client_unregister(&sor->client); 27696b6b6042SThierry Reding if (err < 0) { 27706b6b6042SThierry Reding dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 27716b6b6042SThierry Reding err); 27726b6b6042SThierry Reding return err; 27736b6b6042SThierry Reding } 27746b6b6042SThierry Reding 2775459cc2c6SThierry Reding if (sor->ops && sor->ops->remove) { 2776459cc2c6SThierry Reding err = sor->ops->remove(sor); 2777459cc2c6SThierry Reding if (err < 0) 2778459cc2c6SThierry Reding dev_err(&pdev->dev, "failed to remove SOR: %d\n", err); 2779459cc2c6SThierry Reding } 2780459cc2c6SThierry Reding 2781328ec69eSThierry Reding tegra_output_remove(&sor->output); 27826b6b6042SThierry Reding 27836b6b6042SThierry Reding return 0; 27846b6b6042SThierry Reding } 27856b6b6042SThierry Reding 2786aaff8bd2SThierry Reding #ifdef CONFIG_PM 2787aaff8bd2SThierry Reding static int tegra_sor_suspend(struct device *dev) 2788aaff8bd2SThierry Reding { 2789aaff8bd2SThierry Reding struct tegra_sor *sor = dev_get_drvdata(dev); 2790aaff8bd2SThierry Reding int err; 2791aaff8bd2SThierry Reding 2792f8c79120SJon Hunter if (sor->rst) { 2793aaff8bd2SThierry Reding err = reset_control_assert(sor->rst); 2794aaff8bd2SThierry Reding if (err < 0) { 2795aaff8bd2SThierry Reding dev_err(dev, "failed to assert reset: %d\n", err); 2796aaff8bd2SThierry Reding return err; 2797aaff8bd2SThierry Reding } 2798f8c79120SJon Hunter } 2799aaff8bd2SThierry Reding 2800aaff8bd2SThierry Reding usleep_range(1000, 2000); 2801aaff8bd2SThierry Reding 2802aaff8bd2SThierry Reding clk_disable_unprepare(sor->clk); 2803aaff8bd2SThierry Reding 2804aaff8bd2SThierry Reding return 0; 2805aaff8bd2SThierry Reding } 2806aaff8bd2SThierry Reding 2807aaff8bd2SThierry Reding static int tegra_sor_resume(struct device *dev) 2808aaff8bd2SThierry Reding { 2809aaff8bd2SThierry Reding struct tegra_sor *sor = dev_get_drvdata(dev); 2810aaff8bd2SThierry Reding int err; 2811aaff8bd2SThierry Reding 2812aaff8bd2SThierry Reding err = clk_prepare_enable(sor->clk); 2813aaff8bd2SThierry Reding if (err < 0) { 2814aaff8bd2SThierry Reding dev_err(dev, "failed to enable clock: %d\n", err); 2815aaff8bd2SThierry Reding return err; 2816aaff8bd2SThierry Reding } 2817aaff8bd2SThierry Reding 2818aaff8bd2SThierry Reding usleep_range(1000, 2000); 2819aaff8bd2SThierry Reding 2820f8c79120SJon Hunter if (sor->rst) { 2821aaff8bd2SThierry Reding err = reset_control_deassert(sor->rst); 2822aaff8bd2SThierry Reding if (err < 0) { 2823aaff8bd2SThierry Reding dev_err(dev, "failed to deassert reset: %d\n", err); 2824aaff8bd2SThierry Reding clk_disable_unprepare(sor->clk); 2825aaff8bd2SThierry Reding return err; 2826aaff8bd2SThierry Reding } 2827f8c79120SJon Hunter } 2828aaff8bd2SThierry Reding 2829aaff8bd2SThierry Reding return 0; 2830aaff8bd2SThierry Reding } 2831aaff8bd2SThierry Reding #endif 2832aaff8bd2SThierry Reding 2833aaff8bd2SThierry Reding static const struct dev_pm_ops tegra_sor_pm_ops = { 2834aaff8bd2SThierry Reding SET_RUNTIME_PM_OPS(tegra_sor_suspend, tegra_sor_resume, NULL) 2835aaff8bd2SThierry Reding }; 2836aaff8bd2SThierry Reding 28376b6b6042SThierry Reding struct platform_driver tegra_sor_driver = { 28386b6b6042SThierry Reding .driver = { 28396b6b6042SThierry Reding .name = "tegra-sor", 28406b6b6042SThierry Reding .of_match_table = tegra_sor_of_match, 2841aaff8bd2SThierry Reding .pm = &tegra_sor_pm_ops, 28426b6b6042SThierry Reding }, 28436b6b6042SThierry Reding .probe = tegra_sor_probe, 28446b6b6042SThierry Reding .remove = tegra_sor_remove, 28456b6b6042SThierry Reding }; 2846