1*6b6b6042SThierry Reding /* 2*6b6b6042SThierry Reding * Copyright (C) 2013 NVIDIA Corporation 3*6b6b6042SThierry Reding * 4*6b6b6042SThierry Reding * This program is free software; you can redistribute it and/or modify 5*6b6b6042SThierry Reding * it under the terms of the GNU General Public License version 2 as 6*6b6b6042SThierry Reding * published by the Free Software Foundation. 7*6b6b6042SThierry Reding */ 8*6b6b6042SThierry Reding 9*6b6b6042SThierry Reding #include <linux/clk.h> 10*6b6b6042SThierry Reding #include <linux/io.h> 11*6b6b6042SThierry Reding #include <linux/platform_device.h> 12*6b6b6042SThierry Reding #include <linux/reset.h> 13*6b6b6042SThierry Reding #include <linux/tegra-powergate.h> 14*6b6b6042SThierry Reding 15*6b6b6042SThierry Reding #include <drm/drm_dp_helper.h> 16*6b6b6042SThierry Reding 17*6b6b6042SThierry Reding #include "dc.h" 18*6b6b6042SThierry Reding #include "drm.h" 19*6b6b6042SThierry Reding #include "sor.h" 20*6b6b6042SThierry Reding 21*6b6b6042SThierry Reding struct tegra_sor { 22*6b6b6042SThierry Reding struct host1x_client client; 23*6b6b6042SThierry Reding struct tegra_output output; 24*6b6b6042SThierry Reding struct device *dev; 25*6b6b6042SThierry Reding 26*6b6b6042SThierry Reding void __iomem *regs; 27*6b6b6042SThierry Reding 28*6b6b6042SThierry Reding struct reset_control *rst; 29*6b6b6042SThierry Reding struct clk *clk_parent; 30*6b6b6042SThierry Reding struct clk *clk_safe; 31*6b6b6042SThierry Reding struct clk *clk_dp; 32*6b6b6042SThierry Reding struct clk *clk; 33*6b6b6042SThierry Reding 34*6b6b6042SThierry Reding struct tegra_dpaux *dpaux; 35*6b6b6042SThierry Reding 36*6b6b6042SThierry Reding bool enabled; 37*6b6b6042SThierry Reding }; 38*6b6b6042SThierry Reding 39*6b6b6042SThierry Reding static inline struct tegra_sor * 40*6b6b6042SThierry Reding host1x_client_to_sor(struct host1x_client *client) 41*6b6b6042SThierry Reding { 42*6b6b6042SThierry Reding return container_of(client, struct tegra_sor, client); 43*6b6b6042SThierry Reding } 44*6b6b6042SThierry Reding 45*6b6b6042SThierry Reding static inline struct tegra_sor *to_sor(struct tegra_output *output) 46*6b6b6042SThierry Reding { 47*6b6b6042SThierry Reding return container_of(output, struct tegra_sor, output); 48*6b6b6042SThierry Reding } 49*6b6b6042SThierry Reding 50*6b6b6042SThierry Reding static inline unsigned long tegra_sor_readl(struct tegra_sor *sor, 51*6b6b6042SThierry Reding unsigned long offset) 52*6b6b6042SThierry Reding { 53*6b6b6042SThierry Reding return readl(sor->regs + (offset << 2)); 54*6b6b6042SThierry Reding } 55*6b6b6042SThierry Reding 56*6b6b6042SThierry Reding static inline void tegra_sor_writel(struct tegra_sor *sor, unsigned long value, 57*6b6b6042SThierry Reding unsigned long offset) 58*6b6b6042SThierry Reding { 59*6b6b6042SThierry Reding writel(value, sor->regs + (offset << 2)); 60*6b6b6042SThierry Reding } 61*6b6b6042SThierry Reding 62*6b6b6042SThierry Reding static int tegra_sor_dp_train_fast(struct tegra_sor *sor, 63*6b6b6042SThierry Reding struct drm_dp_link *link) 64*6b6b6042SThierry Reding { 65*6b6b6042SThierry Reding unsigned long value; 66*6b6b6042SThierry Reding unsigned int i; 67*6b6b6042SThierry Reding u8 pattern; 68*6b6b6042SThierry Reding int err; 69*6b6b6042SThierry Reding 70*6b6b6042SThierry Reding /* setup lane parameters */ 71*6b6b6042SThierry Reding value = SOR_LANE_DRIVE_CURRENT_LANE3(0x40) | 72*6b6b6042SThierry Reding SOR_LANE_DRIVE_CURRENT_LANE2(0x40) | 73*6b6b6042SThierry Reding SOR_LANE_DRIVE_CURRENT_LANE1(0x40) | 74*6b6b6042SThierry Reding SOR_LANE_DRIVE_CURRENT_LANE0(0x40); 75*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_DRIVE_CURRENT_0); 76*6b6b6042SThierry Reding 77*6b6b6042SThierry Reding value = SOR_LANE_PREEMPHASIS_LANE3(0x0f) | 78*6b6b6042SThierry Reding SOR_LANE_PREEMPHASIS_LANE2(0x0f) | 79*6b6b6042SThierry Reding SOR_LANE_PREEMPHASIS_LANE1(0x0f) | 80*6b6b6042SThierry Reding SOR_LANE_PREEMPHASIS_LANE0(0x0f); 81*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_PREEMPHASIS_0); 82*6b6b6042SThierry Reding 83*6b6b6042SThierry Reding value = SOR_LANE_POST_CURSOR_LANE3(0x00) | 84*6b6b6042SThierry Reding SOR_LANE_POST_CURSOR_LANE2(0x00) | 85*6b6b6042SThierry Reding SOR_LANE_POST_CURSOR_LANE1(0x00) | 86*6b6b6042SThierry Reding SOR_LANE_POST_CURSOR_LANE0(0x00); 87*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_POST_CURSOR_0); 88*6b6b6042SThierry Reding 89*6b6b6042SThierry Reding /* disable LVDS mode */ 90*6b6b6042SThierry Reding tegra_sor_writel(sor, 0, SOR_LVDS); 91*6b6b6042SThierry Reding 92*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); 93*6b6b6042SThierry Reding value |= SOR_DP_PADCTL_TX_PU_ENABLE; 94*6b6b6042SThierry Reding value &= ~SOR_DP_PADCTL_TX_PU_MASK; 95*6b6b6042SThierry Reding value |= SOR_DP_PADCTL_TX_PU(2); /* XXX: don't hardcode? */ 96*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); 97*6b6b6042SThierry Reding 98*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); 99*6b6b6042SThierry Reding value |= SOR_DP_PADCTL_CM_TXD_3 | SOR_DP_PADCTL_CM_TXD_2 | 100*6b6b6042SThierry Reding SOR_DP_PADCTL_CM_TXD_1 | SOR_DP_PADCTL_CM_TXD_0; 101*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); 102*6b6b6042SThierry Reding 103*6b6b6042SThierry Reding usleep_range(10, 100); 104*6b6b6042SThierry Reding 105*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); 106*6b6b6042SThierry Reding value &= ~(SOR_DP_PADCTL_CM_TXD_3 | SOR_DP_PADCTL_CM_TXD_2 | 107*6b6b6042SThierry Reding SOR_DP_PADCTL_CM_TXD_1 | SOR_DP_PADCTL_CM_TXD_0); 108*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); 109*6b6b6042SThierry Reding 110*6b6b6042SThierry Reding err = tegra_dpaux_prepare(sor->dpaux, DP_SET_ANSI_8B10B); 111*6b6b6042SThierry Reding if (err < 0) 112*6b6b6042SThierry Reding return err; 113*6b6b6042SThierry Reding 114*6b6b6042SThierry Reding for (i = 0, value = 0; i < link->num_lanes; i++) { 115*6b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 116*6b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_NONE | 117*6b6b6042SThierry Reding SOR_DP_TPG_PATTERN_TRAIN1; 118*6b6b6042SThierry Reding value = (value << 8) | lane; 119*6b6b6042SThierry Reding } 120*6b6b6042SThierry Reding 121*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 122*6b6b6042SThierry Reding 123*6b6b6042SThierry Reding pattern = DP_TRAINING_PATTERN_1; 124*6b6b6042SThierry Reding 125*6b6b6042SThierry Reding err = tegra_dpaux_train(sor->dpaux, link, pattern); 126*6b6b6042SThierry Reding if (err < 0) 127*6b6b6042SThierry Reding return err; 128*6b6b6042SThierry Reding 129*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_SPARE_0); 130*6b6b6042SThierry Reding value |= SOR_DP_SPARE_SEQ_ENABLE; 131*6b6b6042SThierry Reding value &= ~SOR_DP_SPARE_PANEL_INTERNAL; 132*6b6b6042SThierry Reding value |= SOR_DP_SPARE_MACRO_SOR_CLK; 133*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_SPARE_0); 134*6b6b6042SThierry Reding 135*6b6b6042SThierry Reding for (i = 0, value = 0; i < link->num_lanes; i++) { 136*6b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 137*6b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_NONE | 138*6b6b6042SThierry Reding SOR_DP_TPG_PATTERN_TRAIN2; 139*6b6b6042SThierry Reding value = (value << 8) | lane; 140*6b6b6042SThierry Reding } 141*6b6b6042SThierry Reding 142*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 143*6b6b6042SThierry Reding 144*6b6b6042SThierry Reding pattern = DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_2; 145*6b6b6042SThierry Reding 146*6b6b6042SThierry Reding err = tegra_dpaux_train(sor->dpaux, link, pattern); 147*6b6b6042SThierry Reding if (err < 0) 148*6b6b6042SThierry Reding return err; 149*6b6b6042SThierry Reding 150*6b6b6042SThierry Reding for (i = 0, value = 0; i < link->num_lanes; i++) { 151*6b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 152*6b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_GALIOS | 153*6b6b6042SThierry Reding SOR_DP_TPG_PATTERN_NONE; 154*6b6b6042SThierry Reding value = (value << 8) | lane; 155*6b6b6042SThierry Reding } 156*6b6b6042SThierry Reding 157*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 158*6b6b6042SThierry Reding 159*6b6b6042SThierry Reding pattern = DP_TRAINING_PATTERN_DISABLE; 160*6b6b6042SThierry Reding 161*6b6b6042SThierry Reding err = tegra_dpaux_train(sor->dpaux, link, pattern); 162*6b6b6042SThierry Reding if (err < 0) 163*6b6b6042SThierry Reding return err; 164*6b6b6042SThierry Reding 165*6b6b6042SThierry Reding return 0; 166*6b6b6042SThierry Reding } 167*6b6b6042SThierry Reding 168*6b6b6042SThierry Reding static void tegra_sor_super_update(struct tegra_sor *sor) 169*6b6b6042SThierry Reding { 170*6b6b6042SThierry Reding tegra_sor_writel(sor, 0, SOR_SUPER_STATE_0); 171*6b6b6042SThierry Reding tegra_sor_writel(sor, 1, SOR_SUPER_STATE_0); 172*6b6b6042SThierry Reding tegra_sor_writel(sor, 0, SOR_SUPER_STATE_0); 173*6b6b6042SThierry Reding } 174*6b6b6042SThierry Reding 175*6b6b6042SThierry Reding static void tegra_sor_update(struct tegra_sor *sor) 176*6b6b6042SThierry Reding { 177*6b6b6042SThierry Reding tegra_sor_writel(sor, 0, SOR_STATE_0); 178*6b6b6042SThierry Reding tegra_sor_writel(sor, 1, SOR_STATE_0); 179*6b6b6042SThierry Reding tegra_sor_writel(sor, 0, SOR_STATE_0); 180*6b6b6042SThierry Reding } 181*6b6b6042SThierry Reding 182*6b6b6042SThierry Reding static int tegra_sor_setup_pwm(struct tegra_sor *sor, unsigned long timeout) 183*6b6b6042SThierry Reding { 184*6b6b6042SThierry Reding unsigned long value; 185*6b6b6042SThierry Reding 186*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWM_DIV); 187*6b6b6042SThierry Reding value &= ~SOR_PWM_DIV_MASK; 188*6b6b6042SThierry Reding value |= 0x400; /* period */ 189*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PWM_DIV); 190*6b6b6042SThierry Reding 191*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWM_CTL); 192*6b6b6042SThierry Reding value &= ~SOR_PWM_CTL_DUTY_CYCLE_MASK; 193*6b6b6042SThierry Reding value |= 0x400; /* duty cycle */ 194*6b6b6042SThierry Reding value &= ~SOR_PWM_CTL_CLK_SEL; /* clock source: PCLK */ 195*6b6b6042SThierry Reding value |= SOR_PWM_CTL_TRIGGER; 196*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PWM_CTL); 197*6b6b6042SThierry Reding 198*6b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(timeout); 199*6b6b6042SThierry Reding 200*6b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 201*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWM_CTL); 202*6b6b6042SThierry Reding if ((value & SOR_PWM_CTL_TRIGGER) == 0) 203*6b6b6042SThierry Reding return 0; 204*6b6b6042SThierry Reding 205*6b6b6042SThierry Reding usleep_range(25, 100); 206*6b6b6042SThierry Reding } 207*6b6b6042SThierry Reding 208*6b6b6042SThierry Reding return -ETIMEDOUT; 209*6b6b6042SThierry Reding } 210*6b6b6042SThierry Reding 211*6b6b6042SThierry Reding static int tegra_sor_attach(struct tegra_sor *sor) 212*6b6b6042SThierry Reding { 213*6b6b6042SThierry Reding unsigned long value, timeout; 214*6b6b6042SThierry Reding 215*6b6b6042SThierry Reding /* wake up in normal mode */ 216*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE_1); 217*6b6b6042SThierry Reding value |= SOR_SUPER_STATE_HEAD_MODE_AWAKE; 218*6b6b6042SThierry Reding value |= SOR_SUPER_STATE_MODE_NORMAL; 219*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE_1); 220*6b6b6042SThierry Reding tegra_sor_super_update(sor); 221*6b6b6042SThierry Reding 222*6b6b6042SThierry Reding /* attach */ 223*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE_1); 224*6b6b6042SThierry Reding value |= SOR_SUPER_STATE_ATTACHED; 225*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE_1); 226*6b6b6042SThierry Reding tegra_sor_super_update(sor); 227*6b6b6042SThierry Reding 228*6b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 229*6b6b6042SThierry Reding 230*6b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 231*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_TEST); 232*6b6b6042SThierry Reding if ((value & SOR_TEST_ATTACHED) != 0) 233*6b6b6042SThierry Reding return 0; 234*6b6b6042SThierry Reding 235*6b6b6042SThierry Reding usleep_range(25, 100); 236*6b6b6042SThierry Reding } 237*6b6b6042SThierry Reding 238*6b6b6042SThierry Reding return -ETIMEDOUT; 239*6b6b6042SThierry Reding } 240*6b6b6042SThierry Reding 241*6b6b6042SThierry Reding static int tegra_sor_wakeup(struct tegra_sor *sor) 242*6b6b6042SThierry Reding { 243*6b6b6042SThierry Reding struct tegra_dc *dc = to_tegra_dc(sor->output.encoder.crtc); 244*6b6b6042SThierry Reding unsigned long value, timeout; 245*6b6b6042SThierry Reding 246*6b6b6042SThierry Reding /* enable display controller outputs */ 247*6b6b6042SThierry Reding value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL); 248*6b6b6042SThierry Reding value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | 249*6b6b6042SThierry Reding PW4_ENABLE | PM0_ENABLE | PM1_ENABLE; 250*6b6b6042SThierry Reding tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL); 251*6b6b6042SThierry Reding 252*6b6b6042SThierry Reding tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); 253*6b6b6042SThierry Reding tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); 254*6b6b6042SThierry Reding 255*6b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 256*6b6b6042SThierry Reding 257*6b6b6042SThierry Reding /* wait for head to wake up */ 258*6b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 259*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_TEST); 260*6b6b6042SThierry Reding value &= SOR_TEST_HEAD_MODE_MASK; 261*6b6b6042SThierry Reding 262*6b6b6042SThierry Reding if (value == SOR_TEST_HEAD_MODE_AWAKE) 263*6b6b6042SThierry Reding return 0; 264*6b6b6042SThierry Reding 265*6b6b6042SThierry Reding usleep_range(25, 100); 266*6b6b6042SThierry Reding } 267*6b6b6042SThierry Reding 268*6b6b6042SThierry Reding return -ETIMEDOUT; 269*6b6b6042SThierry Reding } 270*6b6b6042SThierry Reding 271*6b6b6042SThierry Reding static int tegra_sor_power_up(struct tegra_sor *sor, unsigned long timeout) 272*6b6b6042SThierry Reding { 273*6b6b6042SThierry Reding unsigned long value; 274*6b6b6042SThierry Reding 275*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 276*6b6b6042SThierry Reding value |= SOR_PWR_TRIGGER | SOR_PWR_NORMAL_STATE_PU; 277*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PWR); 278*6b6b6042SThierry Reding 279*6b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(timeout); 280*6b6b6042SThierry Reding 281*6b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 282*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 283*6b6b6042SThierry Reding if ((value & SOR_PWR_TRIGGER) == 0) 284*6b6b6042SThierry Reding return 0; 285*6b6b6042SThierry Reding 286*6b6b6042SThierry Reding usleep_range(25, 100); 287*6b6b6042SThierry Reding } 288*6b6b6042SThierry Reding 289*6b6b6042SThierry Reding return -ETIMEDOUT; 290*6b6b6042SThierry Reding } 291*6b6b6042SThierry Reding 292*6b6b6042SThierry Reding static int tegra_output_sor_enable(struct tegra_output *output) 293*6b6b6042SThierry Reding { 294*6b6b6042SThierry Reding struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); 295*6b6b6042SThierry Reding struct drm_display_mode *mode = &dc->base.mode; 296*6b6b6042SThierry Reding unsigned int vbe, vse, hbe, hse, vbs, hbs, i; 297*6b6b6042SThierry Reding struct tegra_sor *sor = to_sor(output); 298*6b6b6042SThierry Reding unsigned long value; 299*6b6b6042SThierry Reding int err; 300*6b6b6042SThierry Reding 301*6b6b6042SThierry Reding if (sor->enabled) 302*6b6b6042SThierry Reding return 0; 303*6b6b6042SThierry Reding 304*6b6b6042SThierry Reding err = clk_prepare_enable(sor->clk); 305*6b6b6042SThierry Reding if (err < 0) 306*6b6b6042SThierry Reding return err; 307*6b6b6042SThierry Reding 308*6b6b6042SThierry Reding reset_control_deassert(sor->rst); 309*6b6b6042SThierry Reding 310*6b6b6042SThierry Reding if (sor->dpaux) { 311*6b6b6042SThierry Reding err = tegra_dpaux_enable(sor->dpaux); 312*6b6b6042SThierry Reding if (err < 0) 313*6b6b6042SThierry Reding dev_err(sor->dev, "failed to enable DP: %d\n", err); 314*6b6b6042SThierry Reding } 315*6b6b6042SThierry Reding 316*6b6b6042SThierry Reding err = clk_set_parent(sor->clk, sor->clk_safe); 317*6b6b6042SThierry Reding if (err < 0) 318*6b6b6042SThierry Reding dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); 319*6b6b6042SThierry Reding 320*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 321*6b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; 322*6b6b6042SThierry Reding value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK; 323*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 324*6b6b6042SThierry Reding 325*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 326*6b6b6042SThierry Reding value &= ~SOR_PLL_2_BANDGAP_POWERDOWN; 327*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_2); 328*6b6b6042SThierry Reding usleep_range(20, 100); 329*6b6b6042SThierry Reding 330*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_3); 331*6b6b6042SThierry Reding value |= SOR_PLL_3_PLL_VDD_MODE_V3_3; 332*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_3); 333*6b6b6042SThierry Reding 334*6b6b6042SThierry Reding value = SOR_PLL_0_ICHPMP(0xf) | SOR_PLL_0_VCOCAP_RST | 335*6b6b6042SThierry Reding SOR_PLL_0_PLLREG_LEVEL_V45 | SOR_PLL_0_RESISTOR_EXT; 336*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_0); 337*6b6b6042SThierry Reding 338*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 339*6b6b6042SThierry Reding value |= SOR_PLL_2_SEQ_PLLCAPPD; 340*6b6b6042SThierry Reding value &= ~SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE; 341*6b6b6042SThierry Reding value |= SOR_PLL_2_LVDS_ENABLE; 342*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_2); 343*6b6b6042SThierry Reding 344*6b6b6042SThierry Reding value = SOR_PLL_1_TERM_COMPOUT | SOR_PLL_1_TMDS_TERM; 345*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_1); 346*6b6b6042SThierry Reding 347*6b6b6042SThierry Reding while (true) { 348*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 349*6b6b6042SThierry Reding if ((value & SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE) == 0) 350*6b6b6042SThierry Reding break; 351*6b6b6042SThierry Reding 352*6b6b6042SThierry Reding usleep_range(250, 1000); 353*6b6b6042SThierry Reding } 354*6b6b6042SThierry Reding 355*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 356*6b6b6042SThierry Reding value &= ~SOR_PLL_2_POWERDOWN_OVERRIDE; 357*6b6b6042SThierry Reding value &= ~SOR_PLL_2_PORT_POWERDOWN; 358*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_2); 359*6b6b6042SThierry Reding 360*6b6b6042SThierry Reding /* 361*6b6b6042SThierry Reding * power up 362*6b6b6042SThierry Reding */ 363*6b6b6042SThierry Reding 364*6b6b6042SThierry Reding /* set safe link bandwidth (1.62 Gbps) */ 365*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 366*6b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; 367*6b6b6042SThierry Reding value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G1_62; 368*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 369*6b6b6042SThierry Reding 370*6b6b6042SThierry Reding /* step 1 */ 371*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 372*6b6b6042SThierry Reding value |= SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE | SOR_PLL_2_PORT_POWERDOWN | 373*6b6b6042SThierry Reding SOR_PLL_2_BANDGAP_POWERDOWN; 374*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_2); 375*6b6b6042SThierry Reding 376*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_0); 377*6b6b6042SThierry Reding value |= SOR_PLL_0_VCOPD | SOR_PLL_0_POWER_OFF; 378*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_0); 379*6b6b6042SThierry Reding 380*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); 381*6b6b6042SThierry Reding value &= ~SOR_DP_PADCTL_PAD_CAL_PD; 382*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); 383*6b6b6042SThierry Reding 384*6b6b6042SThierry Reding /* step 2 */ 385*6b6b6042SThierry Reding err = tegra_io_rail_power_on(TEGRA_IO_RAIL_LVDS); 386*6b6b6042SThierry Reding if (err < 0) { 387*6b6b6042SThierry Reding dev_err(sor->dev, "failed to power on I/O rail: %d\n", err); 388*6b6b6042SThierry Reding return err; 389*6b6b6042SThierry Reding } 390*6b6b6042SThierry Reding 391*6b6b6042SThierry Reding usleep_range(5, 100); 392*6b6b6042SThierry Reding 393*6b6b6042SThierry Reding /* step 3 */ 394*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 395*6b6b6042SThierry Reding value &= ~SOR_PLL_2_BANDGAP_POWERDOWN; 396*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_2); 397*6b6b6042SThierry Reding 398*6b6b6042SThierry Reding usleep_range(20, 100); 399*6b6b6042SThierry Reding 400*6b6b6042SThierry Reding /* step 4 */ 401*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_0); 402*6b6b6042SThierry Reding value &= ~SOR_PLL_0_POWER_OFF; 403*6b6b6042SThierry Reding value &= ~SOR_PLL_0_VCOPD; 404*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_0); 405*6b6b6042SThierry Reding 406*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 407*6b6b6042SThierry Reding value &= ~SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE; 408*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_2); 409*6b6b6042SThierry Reding 410*6b6b6042SThierry Reding usleep_range(200, 1000); 411*6b6b6042SThierry Reding 412*6b6b6042SThierry Reding /* step 5 */ 413*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 414*6b6b6042SThierry Reding value &= ~SOR_PLL_2_PORT_POWERDOWN; 415*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_2); 416*6b6b6042SThierry Reding 417*6b6b6042SThierry Reding /* switch to DP clock */ 418*6b6b6042SThierry Reding err = clk_set_parent(sor->clk, sor->clk_dp); 419*6b6b6042SThierry Reding if (err < 0) 420*6b6b6042SThierry Reding dev_err(sor->dev, "failed to set DP parent clock: %d\n", err); 421*6b6b6042SThierry Reding 422*6b6b6042SThierry Reding /* power dplanes (XXX parameterize based on link?) */ 423*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); 424*6b6b6042SThierry Reding value |= SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 | 425*6b6b6042SThierry Reding SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2; 426*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); 427*6b6b6042SThierry Reding 428*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_LINKCTL_0); 429*6b6b6042SThierry Reding value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK; 430*6b6b6042SThierry Reding value |= SOR_DP_LINKCTL_LANE_COUNT(4); 431*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0); 432*6b6b6042SThierry Reding 433*6b6b6042SThierry Reding /* start lane sequencer */ 434*6b6b6042SThierry Reding value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_DOWN | 435*6b6b6042SThierry Reding SOR_LANE_SEQ_CTL_POWER_STATE_UP; 436*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL); 437*6b6b6042SThierry Reding 438*6b6b6042SThierry Reding while (true) { 439*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL); 440*6b6b6042SThierry Reding if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0) 441*6b6b6042SThierry Reding break; 442*6b6b6042SThierry Reding 443*6b6b6042SThierry Reding usleep_range(250, 1000); 444*6b6b6042SThierry Reding } 445*6b6b6042SThierry Reding 446*6b6b6042SThierry Reding /* set link bandwidth (2.7 GHz, XXX: parameterize based on link?) */ 447*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 448*6b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; 449*6b6b6042SThierry Reding value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G2_70; 450*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 451*6b6b6042SThierry Reding 452*6b6b6042SThierry Reding /* set linkctl */ 453*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_LINKCTL_0); 454*6b6b6042SThierry Reding value |= SOR_DP_LINKCTL_ENABLE; 455*6b6b6042SThierry Reding 456*6b6b6042SThierry Reding value &= ~SOR_DP_LINKCTL_TU_SIZE_MASK; 457*6b6b6042SThierry Reding value |= SOR_DP_LINKCTL_TU_SIZE(59); /* XXX: don't hardcode? */ 458*6b6b6042SThierry Reding 459*6b6b6042SThierry Reding value |= SOR_DP_LINKCTL_ENHANCED_FRAME; 460*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0); 461*6b6b6042SThierry Reding 462*6b6b6042SThierry Reding for (i = 0, value = 0; i < 4; i++) { 463*6b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 464*6b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_GALIOS | 465*6b6b6042SThierry Reding SOR_DP_TPG_PATTERN_NONE; 466*6b6b6042SThierry Reding value = (value << 8) | lane; 467*6b6b6042SThierry Reding } 468*6b6b6042SThierry Reding 469*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 470*6b6b6042SThierry Reding 471*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_CONFIG_0); 472*6b6b6042SThierry Reding value &= ~SOR_DP_CONFIG_WATERMARK_MASK; 473*6b6b6042SThierry Reding value |= SOR_DP_CONFIG_WATERMARK(14); /* XXX: don't hardcode? */ 474*6b6b6042SThierry Reding 475*6b6b6042SThierry Reding value &= ~SOR_DP_CONFIG_ACTIVE_SYM_COUNT_MASK; 476*6b6b6042SThierry Reding value |= SOR_DP_CONFIG_ACTIVE_SYM_COUNT(47); /* XXX: don't hardcode? */ 477*6b6b6042SThierry Reding 478*6b6b6042SThierry Reding value &= ~SOR_DP_CONFIG_ACTIVE_SYM_FRAC_MASK; 479*6b6b6042SThierry Reding value |= SOR_DP_CONFIG_ACTIVE_SYM_FRAC(9); /* XXX: don't hardcode? */ 480*6b6b6042SThierry Reding 481*6b6b6042SThierry Reding value &= ~SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; /* XXX: don't hardcode? */ 482*6b6b6042SThierry Reding 483*6b6b6042SThierry Reding value |= SOR_DP_CONFIG_ACTIVE_SYM_ENABLE; 484*6b6b6042SThierry Reding value |= SOR_DP_CONFIG_DISPARITY_NEGATIVE; /* XXX: don't hardcode? */ 485*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_CONFIG_0); 486*6b6b6042SThierry Reding 487*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_AUDIO_HBLANK_SYMBOLS); 488*6b6b6042SThierry Reding value &= ~SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK; 489*6b6b6042SThierry Reding value |= 137; /* XXX: don't hardcode? */ 490*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_AUDIO_HBLANK_SYMBOLS); 491*6b6b6042SThierry Reding 492*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_AUDIO_VBLANK_SYMBOLS); 493*6b6b6042SThierry Reding value &= ~SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK; 494*6b6b6042SThierry Reding value |= 2368; /* XXX: don't hardcode? */ 495*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_AUDIO_VBLANK_SYMBOLS); 496*6b6b6042SThierry Reding 497*6b6b6042SThierry Reding /* enable pad calibration logic */ 498*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); 499*6b6b6042SThierry Reding value |= SOR_DP_PADCTL_PAD_CAL_PD; 500*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); 501*6b6b6042SThierry Reding 502*6b6b6042SThierry Reding if (sor->dpaux) { 503*6b6b6042SThierry Reding /* FIXME: properly convert to struct drm_dp_aux */ 504*6b6b6042SThierry Reding struct drm_dp_aux *aux = (struct drm_dp_aux *)sor->dpaux; 505*6b6b6042SThierry Reding struct drm_dp_link link; 506*6b6b6042SThierry Reding u8 rate, lanes; 507*6b6b6042SThierry Reding 508*6b6b6042SThierry Reding err = drm_dp_link_probe(aux, &link); 509*6b6b6042SThierry Reding if (err < 0) { 510*6b6b6042SThierry Reding dev_err(sor->dev, "failed to probe eDP link: %d\n", 511*6b6b6042SThierry Reding err); 512*6b6b6042SThierry Reding return err; 513*6b6b6042SThierry Reding } 514*6b6b6042SThierry Reding 515*6b6b6042SThierry Reding err = drm_dp_link_power_up(aux, &link); 516*6b6b6042SThierry Reding if (err < 0) { 517*6b6b6042SThierry Reding dev_err(sor->dev, "failed to power up eDP link: %d\n", 518*6b6b6042SThierry Reding err); 519*6b6b6042SThierry Reding return err; 520*6b6b6042SThierry Reding } 521*6b6b6042SThierry Reding 522*6b6b6042SThierry Reding err = drm_dp_link_configure(aux, &link); 523*6b6b6042SThierry Reding if (err < 0) { 524*6b6b6042SThierry Reding dev_err(sor->dev, "failed to configure eDP link: %d\n", 525*6b6b6042SThierry Reding err); 526*6b6b6042SThierry Reding return err; 527*6b6b6042SThierry Reding } 528*6b6b6042SThierry Reding 529*6b6b6042SThierry Reding rate = drm_dp_link_rate_to_bw_code(link.rate); 530*6b6b6042SThierry Reding lanes = link.num_lanes; 531*6b6b6042SThierry Reding 532*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 533*6b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; 534*6b6b6042SThierry Reding value |= SOR_CLK_CNTRL_DP_LINK_SPEED(rate); 535*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 536*6b6b6042SThierry Reding 537*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_LINKCTL_0); 538*6b6b6042SThierry Reding value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK; 539*6b6b6042SThierry Reding value |= SOR_DP_LINKCTL_LANE_COUNT(lanes); 540*6b6b6042SThierry Reding 541*6b6b6042SThierry Reding if (link.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) 542*6b6b6042SThierry Reding value |= SOR_DP_LINKCTL_ENHANCED_FRAME; 543*6b6b6042SThierry Reding 544*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0); 545*6b6b6042SThierry Reding 546*6b6b6042SThierry Reding /* disable training pattern generator */ 547*6b6b6042SThierry Reding 548*6b6b6042SThierry Reding for (i = 0; i < link.num_lanes; i++) { 549*6b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 550*6b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_GALIOS | 551*6b6b6042SThierry Reding SOR_DP_TPG_PATTERN_NONE; 552*6b6b6042SThierry Reding value = (value << 8) | lane; 553*6b6b6042SThierry Reding } 554*6b6b6042SThierry Reding 555*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 556*6b6b6042SThierry Reding 557*6b6b6042SThierry Reding err = tegra_sor_dp_train_fast(sor, &link); 558*6b6b6042SThierry Reding if (err < 0) { 559*6b6b6042SThierry Reding dev_err(sor->dev, "DP fast link training failed: %d\n", 560*6b6b6042SThierry Reding err); 561*6b6b6042SThierry Reding return err; 562*6b6b6042SThierry Reding } 563*6b6b6042SThierry Reding 564*6b6b6042SThierry Reding dev_dbg(sor->dev, "fast link training succeeded\n"); 565*6b6b6042SThierry Reding } 566*6b6b6042SThierry Reding 567*6b6b6042SThierry Reding err = tegra_sor_power_up(sor, 250); 568*6b6b6042SThierry Reding if (err < 0) { 569*6b6b6042SThierry Reding dev_err(sor->dev, "failed to power up SOR: %d\n", err); 570*6b6b6042SThierry Reding return err; 571*6b6b6042SThierry Reding } 572*6b6b6042SThierry Reding 573*6b6b6042SThierry Reding /* start display controller in continuous mode */ 574*6b6b6042SThierry Reding value = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS); 575*6b6b6042SThierry Reding value |= WRITE_MUX; 576*6b6b6042SThierry Reding tegra_dc_writel(dc, value, DC_CMD_STATE_ACCESS); 577*6b6b6042SThierry Reding 578*6b6b6042SThierry Reding tegra_dc_writel(dc, VSYNC_H_POSITION(1), DC_DISP_DISP_TIMING_OPTIONS); 579*6b6b6042SThierry Reding tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, DC_CMD_DISPLAY_COMMAND); 580*6b6b6042SThierry Reding 581*6b6b6042SThierry Reding value = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS); 582*6b6b6042SThierry Reding value &= ~WRITE_MUX; 583*6b6b6042SThierry Reding tegra_dc_writel(dc, value, DC_CMD_STATE_ACCESS); 584*6b6b6042SThierry Reding 585*6b6b6042SThierry Reding /* 586*6b6b6042SThierry Reding * configure panel (24bpp, vsync-, hsync-, DP-A protocol, complete 587*6b6b6042SThierry Reding * raster, associate with display controller) 588*6b6b6042SThierry Reding */ 589*6b6b6042SThierry Reding value = SOR_STATE_ASY_PIXELDEPTH_BPP_24_444 | 590*6b6b6042SThierry Reding SOR_STATE_ASY_VSYNCPOL | 591*6b6b6042SThierry Reding SOR_STATE_ASY_HSYNCPOL | 592*6b6b6042SThierry Reding SOR_STATE_ASY_PROTOCOL_DP_A | 593*6b6b6042SThierry Reding SOR_STATE_ASY_CRC_MODE_COMPLETE | 594*6b6b6042SThierry Reding SOR_STATE_ASY_OWNER(dc->pipe + 1); 595*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_STATE_1); 596*6b6b6042SThierry Reding 597*6b6b6042SThierry Reding /* 598*6b6b6042SThierry Reding * TODO: The video timing programming below doesn't seem to match the 599*6b6b6042SThierry Reding * register definitions. 600*6b6b6042SThierry Reding */ 601*6b6b6042SThierry Reding 602*6b6b6042SThierry Reding value = ((mode->vtotal & 0x7fff) << 16) | (mode->htotal & 0x7fff); 603*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_HEAD_STATE_1(0)); 604*6b6b6042SThierry Reding 605*6b6b6042SThierry Reding vse = mode->vsync_end - mode->vsync_start - 1; 606*6b6b6042SThierry Reding hse = mode->hsync_end - mode->hsync_start - 1; 607*6b6b6042SThierry Reding 608*6b6b6042SThierry Reding value = ((vse & 0x7fff) << 16) | (hse & 0x7fff); 609*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_HEAD_STATE_2(0)); 610*6b6b6042SThierry Reding 611*6b6b6042SThierry Reding vbe = vse + (mode->vsync_start - mode->vdisplay); 612*6b6b6042SThierry Reding hbe = hse + (mode->hsync_start - mode->hdisplay); 613*6b6b6042SThierry Reding 614*6b6b6042SThierry Reding value = ((vbe & 0x7fff) << 16) | (hbe & 0x7fff); 615*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_HEAD_STATE_3(0)); 616*6b6b6042SThierry Reding 617*6b6b6042SThierry Reding vbs = vbe + mode->vdisplay; 618*6b6b6042SThierry Reding hbs = hbe + mode->hdisplay; 619*6b6b6042SThierry Reding 620*6b6b6042SThierry Reding value = ((vbs & 0x7fff) << 16) | (hbs & 0x7fff); 621*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_HEAD_STATE_4(0)); 622*6b6b6042SThierry Reding 623*6b6b6042SThierry Reding /* XXX interlaced mode */ 624*6b6b6042SThierry Reding tegra_sor_writel(sor, 0x00000001, SOR_HEAD_STATE_5(0)); 625*6b6b6042SThierry Reding 626*6b6b6042SThierry Reding /* CSTM (LVDS, link A/B, upper) */ 627*6b6b6042SThierry Reding value = SOR_CSTM_LVDS | SOR_CSTM_LINK_ACT_B | SOR_CSTM_LINK_ACT_B | 628*6b6b6042SThierry Reding SOR_CSTM_UPPER; 629*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CSTM); 630*6b6b6042SThierry Reding 631*6b6b6042SThierry Reding /* PWM setup */ 632*6b6b6042SThierry Reding err = tegra_sor_setup_pwm(sor, 250); 633*6b6b6042SThierry Reding if (err < 0) { 634*6b6b6042SThierry Reding dev_err(sor->dev, "failed to setup PWM: %d\n", err); 635*6b6b6042SThierry Reding return err; 636*6b6b6042SThierry Reding } 637*6b6b6042SThierry Reding 638*6b6b6042SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 639*6b6b6042SThierry Reding value |= SOR_ENABLE; 640*6b6b6042SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 641*6b6b6042SThierry Reding 642*6b6b6042SThierry Reding tegra_sor_update(sor); 643*6b6b6042SThierry Reding 644*6b6b6042SThierry Reding err = tegra_sor_attach(sor); 645*6b6b6042SThierry Reding if (err < 0) { 646*6b6b6042SThierry Reding dev_err(sor->dev, "failed to attach SOR: %d\n", err); 647*6b6b6042SThierry Reding return err; 648*6b6b6042SThierry Reding } 649*6b6b6042SThierry Reding 650*6b6b6042SThierry Reding err = tegra_sor_wakeup(sor); 651*6b6b6042SThierry Reding if (err < 0) { 652*6b6b6042SThierry Reding dev_err(sor->dev, "failed to enable DC: %d\n", err); 653*6b6b6042SThierry Reding return err; 654*6b6b6042SThierry Reding } 655*6b6b6042SThierry Reding 656*6b6b6042SThierry Reding sor->enabled = true; 657*6b6b6042SThierry Reding 658*6b6b6042SThierry Reding return 0; 659*6b6b6042SThierry Reding } 660*6b6b6042SThierry Reding 661*6b6b6042SThierry Reding static int tegra_sor_detach(struct tegra_sor *sor) 662*6b6b6042SThierry Reding { 663*6b6b6042SThierry Reding unsigned long value, timeout; 664*6b6b6042SThierry Reding 665*6b6b6042SThierry Reding /* switch to safe mode */ 666*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE_1); 667*6b6b6042SThierry Reding value &= ~SOR_SUPER_STATE_MODE_NORMAL; 668*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE_1); 669*6b6b6042SThierry Reding tegra_sor_super_update(sor); 670*6b6b6042SThierry Reding 671*6b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 672*6b6b6042SThierry Reding 673*6b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 674*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 675*6b6b6042SThierry Reding if (value & SOR_PWR_MODE_SAFE) 676*6b6b6042SThierry Reding break; 677*6b6b6042SThierry Reding } 678*6b6b6042SThierry Reding 679*6b6b6042SThierry Reding if ((value & SOR_PWR_MODE_SAFE) == 0) 680*6b6b6042SThierry Reding return -ETIMEDOUT; 681*6b6b6042SThierry Reding 682*6b6b6042SThierry Reding /* go to sleep */ 683*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE_1); 684*6b6b6042SThierry Reding value &= ~SOR_SUPER_STATE_HEAD_MODE_MASK; 685*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE_1); 686*6b6b6042SThierry Reding tegra_sor_super_update(sor); 687*6b6b6042SThierry Reding 688*6b6b6042SThierry Reding /* detach */ 689*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE_1); 690*6b6b6042SThierry Reding value &= ~SOR_SUPER_STATE_ATTACHED; 691*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE_1); 692*6b6b6042SThierry Reding tegra_sor_super_update(sor); 693*6b6b6042SThierry Reding 694*6b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 695*6b6b6042SThierry Reding 696*6b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 697*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_TEST); 698*6b6b6042SThierry Reding if ((value & SOR_TEST_ATTACHED) == 0) 699*6b6b6042SThierry Reding break; 700*6b6b6042SThierry Reding 701*6b6b6042SThierry Reding usleep_range(25, 100); 702*6b6b6042SThierry Reding } 703*6b6b6042SThierry Reding 704*6b6b6042SThierry Reding if ((value & SOR_TEST_ATTACHED) != 0) 705*6b6b6042SThierry Reding return -ETIMEDOUT; 706*6b6b6042SThierry Reding 707*6b6b6042SThierry Reding return 0; 708*6b6b6042SThierry Reding } 709*6b6b6042SThierry Reding 710*6b6b6042SThierry Reding static int tegra_sor_power_down(struct tegra_sor *sor) 711*6b6b6042SThierry Reding { 712*6b6b6042SThierry Reding unsigned long value, timeout; 713*6b6b6042SThierry Reding int err; 714*6b6b6042SThierry Reding 715*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 716*6b6b6042SThierry Reding value &= ~SOR_PWR_NORMAL_STATE_PU; 717*6b6b6042SThierry Reding value |= SOR_PWR_TRIGGER; 718*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PWR); 719*6b6b6042SThierry Reding 720*6b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 721*6b6b6042SThierry Reding 722*6b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 723*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 724*6b6b6042SThierry Reding if ((value & SOR_PWR_TRIGGER) == 0) 725*6b6b6042SThierry Reding return 0; 726*6b6b6042SThierry Reding 727*6b6b6042SThierry Reding usleep_range(25, 100); 728*6b6b6042SThierry Reding } 729*6b6b6042SThierry Reding 730*6b6b6042SThierry Reding if ((value & SOR_PWR_TRIGGER) != 0) 731*6b6b6042SThierry Reding return -ETIMEDOUT; 732*6b6b6042SThierry Reding 733*6b6b6042SThierry Reding err = clk_set_parent(sor->clk, sor->clk_safe); 734*6b6b6042SThierry Reding if (err < 0) 735*6b6b6042SThierry Reding dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); 736*6b6b6042SThierry Reding 737*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); 738*6b6b6042SThierry Reding value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 | 739*6b6b6042SThierry Reding SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2); 740*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); 741*6b6b6042SThierry Reding 742*6b6b6042SThierry Reding /* stop lane sequencer */ 743*6b6b6042SThierry Reding value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_DOWN | 744*6b6b6042SThierry Reding SOR_LANE_SEQ_CTL_POWER_STATE_DOWN; 745*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL); 746*6b6b6042SThierry Reding 747*6b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 748*6b6b6042SThierry Reding 749*6b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 750*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL); 751*6b6b6042SThierry Reding if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0) 752*6b6b6042SThierry Reding break; 753*6b6b6042SThierry Reding 754*6b6b6042SThierry Reding usleep_range(25, 100); 755*6b6b6042SThierry Reding } 756*6b6b6042SThierry Reding 757*6b6b6042SThierry Reding if ((value & SOR_LANE_SEQ_CTL_TRIGGER) != 0) 758*6b6b6042SThierry Reding return -ETIMEDOUT; 759*6b6b6042SThierry Reding 760*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 761*6b6b6042SThierry Reding value |= SOR_PLL_2_PORT_POWERDOWN; 762*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_2); 763*6b6b6042SThierry Reding 764*6b6b6042SThierry Reding usleep_range(20, 100); 765*6b6b6042SThierry Reding 766*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_0); 767*6b6b6042SThierry Reding value |= SOR_PLL_0_POWER_OFF; 768*6b6b6042SThierry Reding value |= SOR_PLL_0_VCOPD; 769*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_0); 770*6b6b6042SThierry Reding 771*6b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 772*6b6b6042SThierry Reding value |= SOR_PLL_2_SEQ_PLLCAPPD; 773*6b6b6042SThierry Reding value |= SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE; 774*6b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_2); 775*6b6b6042SThierry Reding 776*6b6b6042SThierry Reding usleep_range(20, 100); 777*6b6b6042SThierry Reding 778*6b6b6042SThierry Reding return 0; 779*6b6b6042SThierry Reding } 780*6b6b6042SThierry Reding 781*6b6b6042SThierry Reding static int tegra_output_sor_disable(struct tegra_output *output) 782*6b6b6042SThierry Reding { 783*6b6b6042SThierry Reding struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); 784*6b6b6042SThierry Reding struct tegra_sor *sor = to_sor(output); 785*6b6b6042SThierry Reding unsigned long value; 786*6b6b6042SThierry Reding int err; 787*6b6b6042SThierry Reding 788*6b6b6042SThierry Reding if (!sor->enabled) 789*6b6b6042SThierry Reding return 0; 790*6b6b6042SThierry Reding 791*6b6b6042SThierry Reding err = tegra_sor_detach(sor); 792*6b6b6042SThierry Reding if (err < 0) { 793*6b6b6042SThierry Reding dev_err(sor->dev, "failed to detach SOR: %d\n", err); 794*6b6b6042SThierry Reding return err; 795*6b6b6042SThierry Reding } 796*6b6b6042SThierry Reding 797*6b6b6042SThierry Reding tegra_sor_writel(sor, 0, SOR_STATE_1); 798*6b6b6042SThierry Reding tegra_sor_update(sor); 799*6b6b6042SThierry Reding 800*6b6b6042SThierry Reding /* 801*6b6b6042SThierry Reding * The following accesses registers of the display controller, so make 802*6b6b6042SThierry Reding * sure it's only executed when the output is attached to one. 803*6b6b6042SThierry Reding */ 804*6b6b6042SThierry Reding if (dc) { 805*6b6b6042SThierry Reding /* 806*6b6b6042SThierry Reding * XXX: We can't do this here because it causes the SOR to go 807*6b6b6042SThierry Reding * into an erroneous state and the output will look scrambled 808*6b6b6042SThierry Reding * the next time it is enabled. Presumably this is because we 809*6b6b6042SThierry Reding * should be doing this only on the next VBLANK. A possible 810*6b6b6042SThierry Reding * solution would be to queue a "power-off" event to trigger 811*6b6b6042SThierry Reding * this code to be run during the next VBLANK. 812*6b6b6042SThierry Reding */ 813*6b6b6042SThierry Reding /* 814*6b6b6042SThierry Reding value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL); 815*6b6b6042SThierry Reding value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | 816*6b6b6042SThierry Reding PW4_ENABLE | PM0_ENABLE | PM1_ENABLE); 817*6b6b6042SThierry Reding tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL); 818*6b6b6042SThierry Reding */ 819*6b6b6042SThierry Reding 820*6b6b6042SThierry Reding value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND); 821*6b6b6042SThierry Reding value &= ~DISP_CTRL_MODE_MASK; 822*6b6b6042SThierry Reding tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND); 823*6b6b6042SThierry Reding 824*6b6b6042SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 825*6b6b6042SThierry Reding value &= ~SOR_ENABLE; 826*6b6b6042SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 827*6b6b6042SThierry Reding 828*6b6b6042SThierry Reding tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); 829*6b6b6042SThierry Reding tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); 830*6b6b6042SThierry Reding } 831*6b6b6042SThierry Reding 832*6b6b6042SThierry Reding err = tegra_sor_power_down(sor); 833*6b6b6042SThierry Reding if (err < 0) { 834*6b6b6042SThierry Reding dev_err(sor->dev, "failed to power down SOR: %d\n", err); 835*6b6b6042SThierry Reding return err; 836*6b6b6042SThierry Reding } 837*6b6b6042SThierry Reding 838*6b6b6042SThierry Reding if (sor->dpaux) { 839*6b6b6042SThierry Reding err = tegra_dpaux_disable(sor->dpaux); 840*6b6b6042SThierry Reding if (err < 0) { 841*6b6b6042SThierry Reding dev_err(sor->dev, "failed to disable DP: %d\n", err); 842*6b6b6042SThierry Reding return err; 843*6b6b6042SThierry Reding } 844*6b6b6042SThierry Reding } 845*6b6b6042SThierry Reding 846*6b6b6042SThierry Reding err = tegra_io_rail_power_off(TEGRA_IO_RAIL_LVDS); 847*6b6b6042SThierry Reding if (err < 0) { 848*6b6b6042SThierry Reding dev_err(sor->dev, "failed to power off I/O rail: %d\n", err); 849*6b6b6042SThierry Reding return err; 850*6b6b6042SThierry Reding } 851*6b6b6042SThierry Reding 852*6b6b6042SThierry Reding reset_control_assert(sor->rst); 853*6b6b6042SThierry Reding clk_disable_unprepare(sor->clk); 854*6b6b6042SThierry Reding 855*6b6b6042SThierry Reding sor->enabled = false; 856*6b6b6042SThierry Reding 857*6b6b6042SThierry Reding return 0; 858*6b6b6042SThierry Reding } 859*6b6b6042SThierry Reding 860*6b6b6042SThierry Reding static int tegra_output_sor_setup_clock(struct tegra_output *output, 861*6b6b6042SThierry Reding struct clk *clk, unsigned long pclk) 862*6b6b6042SThierry Reding { 863*6b6b6042SThierry Reding struct tegra_sor *sor = to_sor(output); 864*6b6b6042SThierry Reding int err; 865*6b6b6042SThierry Reding 866*6b6b6042SThierry Reding /* round to next MHz */ 867*6b6b6042SThierry Reding pclk = DIV_ROUND_UP(pclk / 2, 1000000) * 1000000; 868*6b6b6042SThierry Reding 869*6b6b6042SThierry Reding err = clk_set_parent(clk, sor->clk_parent); 870*6b6b6042SThierry Reding if (err < 0) { 871*6b6b6042SThierry Reding dev_err(sor->dev, "failed to set parent clock: %d\n", err); 872*6b6b6042SThierry Reding return err; 873*6b6b6042SThierry Reding } 874*6b6b6042SThierry Reding 875*6b6b6042SThierry Reding err = clk_set_rate(sor->clk_parent, pclk); 876*6b6b6042SThierry Reding if (err < 0) { 877*6b6b6042SThierry Reding dev_err(sor->dev, "failed to set base clock rate to %lu Hz\n", 878*6b6b6042SThierry Reding pclk * 2); 879*6b6b6042SThierry Reding return err; 880*6b6b6042SThierry Reding } 881*6b6b6042SThierry Reding 882*6b6b6042SThierry Reding return 0; 883*6b6b6042SThierry Reding } 884*6b6b6042SThierry Reding 885*6b6b6042SThierry Reding static int tegra_output_sor_check_mode(struct tegra_output *output, 886*6b6b6042SThierry Reding struct drm_display_mode *mode, 887*6b6b6042SThierry Reding enum drm_mode_status *status) 888*6b6b6042SThierry Reding { 889*6b6b6042SThierry Reding /* 890*6b6b6042SThierry Reding * FIXME: For now, always assume that the mode is okay. 891*6b6b6042SThierry Reding */ 892*6b6b6042SThierry Reding 893*6b6b6042SThierry Reding *status = MODE_OK; 894*6b6b6042SThierry Reding 895*6b6b6042SThierry Reding return 0; 896*6b6b6042SThierry Reding } 897*6b6b6042SThierry Reding 898*6b6b6042SThierry Reding static enum drm_connector_status 899*6b6b6042SThierry Reding tegra_output_sor_detect(struct tegra_output *output) 900*6b6b6042SThierry Reding { 901*6b6b6042SThierry Reding struct tegra_sor *sor = to_sor(output); 902*6b6b6042SThierry Reding 903*6b6b6042SThierry Reding if (sor->dpaux) 904*6b6b6042SThierry Reding return tegra_dpaux_detect(sor->dpaux); 905*6b6b6042SThierry Reding 906*6b6b6042SThierry Reding return connector_status_unknown; 907*6b6b6042SThierry Reding } 908*6b6b6042SThierry Reding 909*6b6b6042SThierry Reding static const struct tegra_output_ops sor_ops = { 910*6b6b6042SThierry Reding .enable = tegra_output_sor_enable, 911*6b6b6042SThierry Reding .disable = tegra_output_sor_disable, 912*6b6b6042SThierry Reding .setup_clock = tegra_output_sor_setup_clock, 913*6b6b6042SThierry Reding .check_mode = tegra_output_sor_check_mode, 914*6b6b6042SThierry Reding .detect = tegra_output_sor_detect, 915*6b6b6042SThierry Reding }; 916*6b6b6042SThierry Reding 917*6b6b6042SThierry Reding static int tegra_sor_init(struct host1x_client *client) 918*6b6b6042SThierry Reding { 919*6b6b6042SThierry Reding struct tegra_drm *tegra = dev_get_drvdata(client->parent); 920*6b6b6042SThierry Reding struct tegra_sor *sor = host1x_client_to_sor(client); 921*6b6b6042SThierry Reding int err; 922*6b6b6042SThierry Reding 923*6b6b6042SThierry Reding if (!sor->dpaux) 924*6b6b6042SThierry Reding return -ENODEV; 925*6b6b6042SThierry Reding 926*6b6b6042SThierry Reding sor->output.type = TEGRA_OUTPUT_EDP; 927*6b6b6042SThierry Reding 928*6b6b6042SThierry Reding sor->output.dev = sor->dev; 929*6b6b6042SThierry Reding sor->output.ops = &sor_ops; 930*6b6b6042SThierry Reding 931*6b6b6042SThierry Reding err = tegra_output_init(tegra->drm, &sor->output); 932*6b6b6042SThierry Reding if (err < 0) { 933*6b6b6042SThierry Reding dev_err(sor->dev, "output setup failed: %d\n", err); 934*6b6b6042SThierry Reding return err; 935*6b6b6042SThierry Reding } 936*6b6b6042SThierry Reding 937*6b6b6042SThierry Reding if (sor->dpaux) { 938*6b6b6042SThierry Reding err = tegra_dpaux_attach(sor->dpaux, &sor->output); 939*6b6b6042SThierry Reding if (err < 0) { 940*6b6b6042SThierry Reding dev_err(sor->dev, "failed to attach DP: %d\n", err); 941*6b6b6042SThierry Reding return err; 942*6b6b6042SThierry Reding } 943*6b6b6042SThierry Reding } 944*6b6b6042SThierry Reding 945*6b6b6042SThierry Reding return 0; 946*6b6b6042SThierry Reding } 947*6b6b6042SThierry Reding 948*6b6b6042SThierry Reding static int tegra_sor_exit(struct host1x_client *client) 949*6b6b6042SThierry Reding { 950*6b6b6042SThierry Reding struct tegra_sor *sor = host1x_client_to_sor(client); 951*6b6b6042SThierry Reding int err; 952*6b6b6042SThierry Reding 953*6b6b6042SThierry Reding err = tegra_output_disable(&sor->output); 954*6b6b6042SThierry Reding if (err < 0) { 955*6b6b6042SThierry Reding dev_err(sor->dev, "output failed to disable: %d\n", err); 956*6b6b6042SThierry Reding return err; 957*6b6b6042SThierry Reding } 958*6b6b6042SThierry Reding 959*6b6b6042SThierry Reding if (sor->dpaux) { 960*6b6b6042SThierry Reding err = tegra_dpaux_detach(sor->dpaux); 961*6b6b6042SThierry Reding if (err < 0) { 962*6b6b6042SThierry Reding dev_err(sor->dev, "failed to detach DP: %d\n", err); 963*6b6b6042SThierry Reding return err; 964*6b6b6042SThierry Reding } 965*6b6b6042SThierry Reding } 966*6b6b6042SThierry Reding 967*6b6b6042SThierry Reding err = tegra_output_exit(&sor->output); 968*6b6b6042SThierry Reding if (err < 0) { 969*6b6b6042SThierry Reding dev_err(sor->dev, "output cleanup failed: %d\n", err); 970*6b6b6042SThierry Reding return err; 971*6b6b6042SThierry Reding } 972*6b6b6042SThierry Reding 973*6b6b6042SThierry Reding return 0; 974*6b6b6042SThierry Reding } 975*6b6b6042SThierry Reding 976*6b6b6042SThierry Reding static const struct host1x_client_ops sor_client_ops = { 977*6b6b6042SThierry Reding .init = tegra_sor_init, 978*6b6b6042SThierry Reding .exit = tegra_sor_exit, 979*6b6b6042SThierry Reding }; 980*6b6b6042SThierry Reding 981*6b6b6042SThierry Reding static int tegra_sor_probe(struct platform_device *pdev) 982*6b6b6042SThierry Reding { 983*6b6b6042SThierry Reding struct device_node *np; 984*6b6b6042SThierry Reding struct tegra_sor *sor; 985*6b6b6042SThierry Reding struct resource *regs; 986*6b6b6042SThierry Reding int err; 987*6b6b6042SThierry Reding 988*6b6b6042SThierry Reding sor = devm_kzalloc(&pdev->dev, sizeof(*sor), GFP_KERNEL); 989*6b6b6042SThierry Reding if (!sor) 990*6b6b6042SThierry Reding return -ENOMEM; 991*6b6b6042SThierry Reding 992*6b6b6042SThierry Reding sor->output.dev = sor->dev = &pdev->dev; 993*6b6b6042SThierry Reding 994*6b6b6042SThierry Reding np = of_parse_phandle(pdev->dev.of_node, "nvidia,dpaux", 0); 995*6b6b6042SThierry Reding if (np) { 996*6b6b6042SThierry Reding sor->dpaux = tegra_dpaux_find_by_of_node(np); 997*6b6b6042SThierry Reding of_node_put(np); 998*6b6b6042SThierry Reding 999*6b6b6042SThierry Reding if (!sor->dpaux) 1000*6b6b6042SThierry Reding return -EPROBE_DEFER; 1001*6b6b6042SThierry Reding } 1002*6b6b6042SThierry Reding 1003*6b6b6042SThierry Reding err = tegra_output_probe(&sor->output); 1004*6b6b6042SThierry Reding if (err < 0) 1005*6b6b6042SThierry Reding return err; 1006*6b6b6042SThierry Reding 1007*6b6b6042SThierry Reding regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1008*6b6b6042SThierry Reding sor->regs = devm_ioremap_resource(&pdev->dev, regs); 1009*6b6b6042SThierry Reding if (IS_ERR(sor->regs)) 1010*6b6b6042SThierry Reding return PTR_ERR(sor->regs); 1011*6b6b6042SThierry Reding 1012*6b6b6042SThierry Reding sor->rst = devm_reset_control_get(&pdev->dev, "sor"); 1013*6b6b6042SThierry Reding if (IS_ERR(sor->rst)) 1014*6b6b6042SThierry Reding return PTR_ERR(sor->rst); 1015*6b6b6042SThierry Reding 1016*6b6b6042SThierry Reding sor->clk = devm_clk_get(&pdev->dev, NULL); 1017*6b6b6042SThierry Reding if (IS_ERR(sor->clk)) 1018*6b6b6042SThierry Reding return PTR_ERR(sor->clk); 1019*6b6b6042SThierry Reding 1020*6b6b6042SThierry Reding sor->clk_parent = devm_clk_get(&pdev->dev, "parent"); 1021*6b6b6042SThierry Reding if (IS_ERR(sor->clk_parent)) 1022*6b6b6042SThierry Reding return PTR_ERR(sor->clk_parent); 1023*6b6b6042SThierry Reding 1024*6b6b6042SThierry Reding err = clk_prepare_enable(sor->clk_parent); 1025*6b6b6042SThierry Reding if (err < 0) 1026*6b6b6042SThierry Reding return err; 1027*6b6b6042SThierry Reding 1028*6b6b6042SThierry Reding sor->clk_safe = devm_clk_get(&pdev->dev, "safe"); 1029*6b6b6042SThierry Reding if (IS_ERR(sor->clk_safe)) 1030*6b6b6042SThierry Reding return PTR_ERR(sor->clk_safe); 1031*6b6b6042SThierry Reding 1032*6b6b6042SThierry Reding err = clk_prepare_enable(sor->clk_safe); 1033*6b6b6042SThierry Reding if (err < 0) 1034*6b6b6042SThierry Reding return err; 1035*6b6b6042SThierry Reding 1036*6b6b6042SThierry Reding sor->clk_dp = devm_clk_get(&pdev->dev, "dp"); 1037*6b6b6042SThierry Reding if (IS_ERR(sor->clk_dp)) 1038*6b6b6042SThierry Reding return PTR_ERR(sor->clk_dp); 1039*6b6b6042SThierry Reding 1040*6b6b6042SThierry Reding err = clk_prepare_enable(sor->clk_dp); 1041*6b6b6042SThierry Reding if (err < 0) 1042*6b6b6042SThierry Reding return err; 1043*6b6b6042SThierry Reding 1044*6b6b6042SThierry Reding INIT_LIST_HEAD(&sor->client.list); 1045*6b6b6042SThierry Reding sor->client.ops = &sor_client_ops; 1046*6b6b6042SThierry Reding sor->client.dev = &pdev->dev; 1047*6b6b6042SThierry Reding 1048*6b6b6042SThierry Reding err = host1x_client_register(&sor->client); 1049*6b6b6042SThierry Reding if (err < 0) { 1050*6b6b6042SThierry Reding dev_err(&pdev->dev, "failed to register host1x client: %d\n", 1051*6b6b6042SThierry Reding err); 1052*6b6b6042SThierry Reding return err; 1053*6b6b6042SThierry Reding } 1054*6b6b6042SThierry Reding 1055*6b6b6042SThierry Reding platform_set_drvdata(pdev, sor); 1056*6b6b6042SThierry Reding 1057*6b6b6042SThierry Reding return 0; 1058*6b6b6042SThierry Reding } 1059*6b6b6042SThierry Reding 1060*6b6b6042SThierry Reding static int tegra_sor_remove(struct platform_device *pdev) 1061*6b6b6042SThierry Reding { 1062*6b6b6042SThierry Reding struct tegra_sor *sor = platform_get_drvdata(pdev); 1063*6b6b6042SThierry Reding int err; 1064*6b6b6042SThierry Reding 1065*6b6b6042SThierry Reding err = host1x_client_unregister(&sor->client); 1066*6b6b6042SThierry Reding if (err < 0) { 1067*6b6b6042SThierry Reding dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 1068*6b6b6042SThierry Reding err); 1069*6b6b6042SThierry Reding return err; 1070*6b6b6042SThierry Reding } 1071*6b6b6042SThierry Reding 1072*6b6b6042SThierry Reding clk_disable_unprepare(sor->clk_parent); 1073*6b6b6042SThierry Reding clk_disable_unprepare(sor->clk_safe); 1074*6b6b6042SThierry Reding clk_disable_unprepare(sor->clk_dp); 1075*6b6b6042SThierry Reding clk_disable_unprepare(sor->clk); 1076*6b6b6042SThierry Reding 1077*6b6b6042SThierry Reding return 0; 1078*6b6b6042SThierry Reding } 1079*6b6b6042SThierry Reding 1080*6b6b6042SThierry Reding static const struct of_device_id tegra_sor_of_match[] = { 1081*6b6b6042SThierry Reding { .compatible = "nvidia,tegra124-sor", }, 1082*6b6b6042SThierry Reding { }, 1083*6b6b6042SThierry Reding }; 1084*6b6b6042SThierry Reding 1085*6b6b6042SThierry Reding struct platform_driver tegra_sor_driver = { 1086*6b6b6042SThierry Reding .driver = { 1087*6b6b6042SThierry Reding .name = "tegra-sor", 1088*6b6b6042SThierry Reding .of_match_table = tegra_sor_of_match, 1089*6b6b6042SThierry Reding }, 1090*6b6b6042SThierry Reding .probe = tegra_sor_probe, 1091*6b6b6042SThierry Reding .remove = tegra_sor_remove, 1092*6b6b6042SThierry Reding }; 1093