100f37327SSimon Glass /*
200f37327SSimon Glass * Copyright (c) 2011-2013, NVIDIA Corporation.
300f37327SSimon Glass *
400f37327SSimon Glass * SPDX-License-Identifier: GPL-2.0
500f37327SSimon Glass */
600f37327SSimon Glass
700f37327SSimon Glass #include <common.h>
8d7659212SSimon Glass #include <dm.h>
900f37327SSimon Glass #include <errno.h>
1000f37327SSimon Glass #include <malloc.h>
11d7659212SSimon Glass #include <panel.h>
12*079ff3b9SSimon Glass #include <syscon.h>
13d7659212SSimon Glass #include <video_bridge.h>
1400f37327SSimon Glass #include <asm/io.h>
1500f37327SSimon Glass #include <asm/arch/clock.h>
1600f37327SSimon Glass #include <asm/arch-tegra/dc.h>
1700f37327SSimon Glass #include "displayport.h"
1800f37327SSimon Glass #include "sor.h"
1900f37327SSimon Glass
2000f37327SSimon Glass DECLARE_GLOBAL_DATA_PTR;
2100f37327SSimon Glass
2200f37327SSimon Glass #define DEBUG_SOR 0
2300f37327SSimon Glass
2400f37327SSimon Glass #define APBDEV_PMC_DPD_SAMPLE 0x20
2500f37327SSimon Glass #define APBDEV_PMC_DPD_SAMPLE_ON_DISABLE 0
2600f37327SSimon Glass #define APBDEV_PMC_DPD_SAMPLE_ON_ENABLE 1
2700f37327SSimon Glass #define APBDEV_PMC_SEL_DPD_TIM 0x1c8
2800f37327SSimon Glass #define APBDEV_PMC_SEL_DPD_TIM_SEL_DPD_TIM_DEFAULT 0x7f
2900f37327SSimon Glass #define APBDEV_PMC_IO_DPD2_REQ 0x1c0
3000f37327SSimon Glass #define APBDEV_PMC_IO_DPD2_REQ_LVDS_SHIFT 25
3100f37327SSimon Glass #define APBDEV_PMC_IO_DPD2_REQ_LVDS_OFF (0 << 25)
3200f37327SSimon Glass #define APBDEV_PMC_IO_DPD2_REQ_LVDS_ON (1 << 25)
3300f37327SSimon Glass #define APBDEV_PMC_IO_DPD2_REQ_CODE_SHIFT 30
3400f37327SSimon Glass #define APBDEV_PMC_IO_DPD2_REQ_CODE_DEFAULT_MASK (0x3 << 30)
3500f37327SSimon Glass #define APBDEV_PMC_IO_DPD2_REQ_CODE_IDLE (0 << 30)
3600f37327SSimon Glass #define APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_OFF (1 << 30)
3700f37327SSimon Glass #define APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_ON (2 << 30)
3800f37327SSimon Glass #define APBDEV_PMC_IO_DPD2_STATUS 0x1c4
3900f37327SSimon Glass #define APBDEV_PMC_IO_DPD2_STATUS_LVDS_SHIFT 25
4000f37327SSimon Glass #define APBDEV_PMC_IO_DPD2_STATUS_LVDS_OFF (0 << 25)
4100f37327SSimon Glass #define APBDEV_PMC_IO_DPD2_STATUS_LVDS_ON (1 << 25)
4200f37327SSimon Glass
43d7659212SSimon Glass struct tegra_dc_sor_data {
44d7659212SSimon Glass void *base;
45d7659212SSimon Glass void *pmc_base;
46d7659212SSimon Glass u8 portnum; /* 0 or 1 */
47d7659212SSimon Glass int power_is_up;
48d7659212SSimon Glass struct udevice *panel;
49d7659212SSimon Glass };
50d7659212SSimon Glass
tegra_sor_readl(struct tegra_dc_sor_data * sor,u32 reg)5100f37327SSimon Glass static inline u32 tegra_sor_readl(struct tegra_dc_sor_data *sor, u32 reg)
5200f37327SSimon Glass {
5300f37327SSimon Glass return readl((u32 *)sor->base + reg);
5400f37327SSimon Glass }
5500f37327SSimon Glass
tegra_sor_writel(struct tegra_dc_sor_data * sor,u32 reg,u32 val)5600f37327SSimon Glass static inline void tegra_sor_writel(struct tegra_dc_sor_data *sor, u32 reg,
5700f37327SSimon Glass u32 val)
5800f37327SSimon Glass {
5900f37327SSimon Glass writel(val, (u32 *)sor->base + reg);
6000f37327SSimon Glass }
6100f37327SSimon Glass
tegra_sor_write_field(struct tegra_dc_sor_data * sor,u32 reg,u32 mask,u32 val)6200f37327SSimon Glass static inline void tegra_sor_write_field(struct tegra_dc_sor_data *sor,
6300f37327SSimon Glass u32 reg, u32 mask, u32 val)
6400f37327SSimon Glass {
6500f37327SSimon Glass u32 reg_val = tegra_sor_readl(sor, reg);
6600f37327SSimon Glass reg_val &= ~mask;
6700f37327SSimon Glass reg_val |= val;
6800f37327SSimon Glass tegra_sor_writel(sor, reg, reg_val);
6900f37327SSimon Glass }
7000f37327SSimon Glass
tegra_dp_disable_tx_pu(struct udevice * dev)71d7659212SSimon Glass void tegra_dp_disable_tx_pu(struct udevice *dev)
72dedc44b4SSimon Glass {
73d7659212SSimon Glass struct tegra_dc_sor_data *sor = dev_get_priv(dev);
74d7659212SSimon Glass
75dedc44b4SSimon Glass tegra_sor_write_field(sor, DP_PADCTL(sor->portnum),
76dedc44b4SSimon Glass DP_PADCTL_TX_PU_MASK, DP_PADCTL_TX_PU_DISABLE);
77dedc44b4SSimon Glass }
78dedc44b4SSimon Glass
tegra_dp_set_pe_vs_pc(struct udevice * dev,u32 mask,u32 pe_reg,u32 vs_reg,u32 pc_reg,u8 pc_supported)79d7659212SSimon Glass void tegra_dp_set_pe_vs_pc(struct udevice *dev, u32 mask, u32 pe_reg,
80dedc44b4SSimon Glass u32 vs_reg, u32 pc_reg, u8 pc_supported)
81dedc44b4SSimon Glass {
82d7659212SSimon Glass struct tegra_dc_sor_data *sor = dev_get_priv(dev);
83d7659212SSimon Glass
84dedc44b4SSimon Glass tegra_sor_write_field(sor, PR(sor->portnum), mask, pe_reg);
85dedc44b4SSimon Glass tegra_sor_write_field(sor, DC(sor->portnum), mask, vs_reg);
86dedc44b4SSimon Glass if (pc_supported) {
87dedc44b4SSimon Glass tegra_sor_write_field(sor, POSTCURSOR(sor->portnum), mask,
88dedc44b4SSimon Glass pc_reg);
89dedc44b4SSimon Glass }
90dedc44b4SSimon Glass }
91dedc44b4SSimon Glass
tegra_dc_sor_poll_register(struct tegra_dc_sor_data * sor,u32 reg,u32 mask,u32 exp_val,int poll_interval_us,int timeout_ms)9200f37327SSimon Glass static int tegra_dc_sor_poll_register(struct tegra_dc_sor_data *sor, u32 reg,
9300f37327SSimon Glass u32 mask, u32 exp_val,
9400f37327SSimon Glass int poll_interval_us, int timeout_ms)
9500f37327SSimon Glass {
9600f37327SSimon Glass u32 reg_val = 0;
9700f37327SSimon Glass ulong start;
9800f37327SSimon Glass
9900f37327SSimon Glass start = get_timer(0);
10000f37327SSimon Glass do {
10100f37327SSimon Glass reg_val = tegra_sor_readl(sor, reg);
10200f37327SSimon Glass if (((reg_val & mask) == exp_val))
10300f37327SSimon Glass return 0;
10400f37327SSimon Glass udelay(poll_interval_us);
10500f37327SSimon Glass } while (get_timer(start) < timeout_ms);
10600f37327SSimon Glass
10700f37327SSimon Glass debug("sor_poll_register 0x%x: timeout, (reg_val)0x%08x & (mask)0x%08x != (exp_val)0x%08x\n",
10800f37327SSimon Glass reg, reg_val, mask, exp_val);
10900f37327SSimon Glass
11000f37327SSimon Glass return -ETIMEDOUT;
11100f37327SSimon Glass }
11200f37327SSimon Glass
tegra_dc_sor_set_power_state(struct udevice * dev,int pu_pd)113d7659212SSimon Glass int tegra_dc_sor_set_power_state(struct udevice *dev, int pu_pd)
11400f37327SSimon Glass {
115d7659212SSimon Glass struct tegra_dc_sor_data *sor = dev_get_priv(dev);
11600f37327SSimon Glass u32 reg_val;
11700f37327SSimon Glass u32 orig_val;
11800f37327SSimon Glass
11900f37327SSimon Glass orig_val = tegra_sor_readl(sor, PWR);
12000f37327SSimon Glass
12100f37327SSimon Glass reg_val = pu_pd ? PWR_NORMAL_STATE_PU :
12200f37327SSimon Glass PWR_NORMAL_STATE_PD; /* normal state only */
12300f37327SSimon Glass
12400f37327SSimon Glass if (reg_val == orig_val)
12500f37327SSimon Glass return 0; /* No update needed */
12600f37327SSimon Glass
12700f37327SSimon Glass reg_val |= PWR_SETTING_NEW_TRIGGER;
12800f37327SSimon Glass tegra_sor_writel(sor, PWR, reg_val);
12900f37327SSimon Glass
13000f37327SSimon Glass /* Poll to confirm it is done */
13100f37327SSimon Glass if (tegra_dc_sor_poll_register(sor, PWR,
13200f37327SSimon Glass PWR_SETTING_NEW_DEFAULT_MASK,
13300f37327SSimon Glass PWR_SETTING_NEW_DONE,
13400f37327SSimon Glass 100, TEGRA_SOR_TIMEOUT_MS)) {
13500f37327SSimon Glass debug("dc timeout waiting for SOR_PWR = NEW_DONE\n");
13600f37327SSimon Glass return -EFAULT;
13700f37327SSimon Glass }
13800f37327SSimon Glass
13900f37327SSimon Glass return 0;
14000f37327SSimon Glass }
14100f37327SSimon Glass
tegra_dc_sor_set_dp_linkctl(struct udevice * dev,int ena,u8 training_pattern,const struct tegra_dp_link_config * link_cfg)142d7659212SSimon Glass void tegra_dc_sor_set_dp_linkctl(struct udevice *dev, int ena,
14300f37327SSimon Glass u8 training_pattern,
14400f37327SSimon Glass const struct tegra_dp_link_config *link_cfg)
14500f37327SSimon Glass {
146d7659212SSimon Glass struct tegra_dc_sor_data *sor = dev_get_priv(dev);
14700f37327SSimon Glass u32 reg_val;
14800f37327SSimon Glass
14900f37327SSimon Glass reg_val = tegra_sor_readl(sor, DP_LINKCTL(sor->portnum));
15000f37327SSimon Glass
15100f37327SSimon Glass if (ena)
15200f37327SSimon Glass reg_val |= DP_LINKCTL_ENABLE_YES;
15300f37327SSimon Glass else
15400f37327SSimon Glass reg_val &= DP_LINKCTL_ENABLE_NO;
15500f37327SSimon Glass
15600f37327SSimon Glass reg_val &= ~DP_LINKCTL_TUSIZE_MASK;
15700f37327SSimon Glass reg_val |= (link_cfg->tu_size << DP_LINKCTL_TUSIZE_SHIFT);
15800f37327SSimon Glass
15900f37327SSimon Glass if (link_cfg->enhanced_framing)
16000f37327SSimon Glass reg_val |= DP_LINKCTL_ENHANCEDFRAME_ENABLE;
16100f37327SSimon Glass
16200f37327SSimon Glass tegra_sor_writel(sor, DP_LINKCTL(sor->portnum), reg_val);
16300f37327SSimon Glass
16400f37327SSimon Glass switch (training_pattern) {
16500f37327SSimon Glass case training_pattern_1:
16600f37327SSimon Glass tegra_sor_writel(sor, DP_TPG, 0x41414141);
16700f37327SSimon Glass break;
16800f37327SSimon Glass case training_pattern_2:
16900f37327SSimon Glass case training_pattern_3:
17000f37327SSimon Glass reg_val = (link_cfg->link_bw == SOR_LINK_SPEED_G5_4) ?
17100f37327SSimon Glass 0x43434343 : 0x42424242;
17200f37327SSimon Glass tegra_sor_writel(sor, DP_TPG, reg_val);
17300f37327SSimon Glass break;
17400f37327SSimon Glass default:
17500f37327SSimon Glass tegra_sor_writel(sor, DP_TPG, 0x50505050);
17600f37327SSimon Glass break;
17700f37327SSimon Glass }
17800f37327SSimon Glass }
17900f37327SSimon Glass
tegra_dc_sor_enable_lane_sequencer(struct tegra_dc_sor_data * sor,int pu,int is_lvds)18000f37327SSimon Glass static int tegra_dc_sor_enable_lane_sequencer(struct tegra_dc_sor_data *sor,
18100f37327SSimon Glass int pu, int is_lvds)
18200f37327SSimon Glass {
18300f37327SSimon Glass u32 reg_val;
18400f37327SSimon Glass
18500f37327SSimon Glass /* SOR lane sequencer */
18600f37327SSimon Glass if (pu) {
18700f37327SSimon Glass reg_val = LANE_SEQ_CTL_SETTING_NEW_TRIGGER |
18800f37327SSimon Glass LANE_SEQ_CTL_SEQUENCE_DOWN |
18900f37327SSimon Glass LANE_SEQ_CTL_NEW_POWER_STATE_PU;
19000f37327SSimon Glass } else {
19100f37327SSimon Glass reg_val = LANE_SEQ_CTL_SETTING_NEW_TRIGGER |
19200f37327SSimon Glass LANE_SEQ_CTL_SEQUENCE_UP |
19300f37327SSimon Glass LANE_SEQ_CTL_NEW_POWER_STATE_PD;
19400f37327SSimon Glass }
19500f37327SSimon Glass
19600f37327SSimon Glass if (is_lvds)
19700f37327SSimon Glass reg_val |= 15 << LANE_SEQ_CTL_DELAY_SHIFT;
19800f37327SSimon Glass else
19900f37327SSimon Glass reg_val |= 1 << LANE_SEQ_CTL_DELAY_SHIFT;
20000f37327SSimon Glass
20100f37327SSimon Glass tegra_sor_writel(sor, LANE_SEQ_CTL, reg_val);
20200f37327SSimon Glass
20300f37327SSimon Glass if (tegra_dc_sor_poll_register(sor, LANE_SEQ_CTL,
20400f37327SSimon Glass LANE_SEQ_CTL_SETTING_MASK,
20500f37327SSimon Glass LANE_SEQ_CTL_SETTING_NEW_DONE,
20600f37327SSimon Glass 100, TEGRA_SOR_TIMEOUT_MS)) {
20700f37327SSimon Glass debug("dp: timeout while waiting for SOR lane sequencer to power down lanes\n");
20800f37327SSimon Glass return -1;
20900f37327SSimon Glass }
21000f37327SSimon Glass
21100f37327SSimon Glass return 0;
21200f37327SSimon Glass }
21300f37327SSimon Glass
tegra_dc_sor_power_dplanes(struct udevice * dev,u32 lane_count,int pu)214d7659212SSimon Glass static int tegra_dc_sor_power_dplanes(struct udevice *dev,
21500f37327SSimon Glass u32 lane_count, int pu)
21600f37327SSimon Glass {
217d7659212SSimon Glass struct tegra_dc_sor_data *sor = dev_get_priv(dev);
21800f37327SSimon Glass u32 reg_val;
21900f37327SSimon Glass
22000f37327SSimon Glass reg_val = tegra_sor_readl(sor, DP_PADCTL(sor->portnum));
22100f37327SSimon Glass
22200f37327SSimon Glass if (pu) {
22300f37327SSimon Glass switch (lane_count) {
22400f37327SSimon Glass case 4:
22500f37327SSimon Glass reg_val |= (DP_PADCTL_PD_TXD_3_NO |
22600f37327SSimon Glass DP_PADCTL_PD_TXD_2_NO);
22700f37327SSimon Glass /* fall through */
22800f37327SSimon Glass case 2:
22900f37327SSimon Glass reg_val |= DP_PADCTL_PD_TXD_1_NO;
23000f37327SSimon Glass case 1:
23100f37327SSimon Glass reg_val |= DP_PADCTL_PD_TXD_0_NO;
23200f37327SSimon Glass break;
23300f37327SSimon Glass default:
23400f37327SSimon Glass debug("dp: invalid lane number %d\n", lane_count);
23500f37327SSimon Glass return -1;
23600f37327SSimon Glass }
23700f37327SSimon Glass
23800f37327SSimon Glass tegra_sor_writel(sor, DP_PADCTL(sor->portnum), reg_val);
239d7659212SSimon Glass tegra_dc_sor_set_lane_count(dev, lane_count);
24000f37327SSimon Glass }
24100f37327SSimon Glass
24200f37327SSimon Glass return tegra_dc_sor_enable_lane_sequencer(sor, pu, 0);
24300f37327SSimon Glass }
24400f37327SSimon Glass
tegra_dc_sor_set_panel_power(struct udevice * dev,int power_up)245d7659212SSimon Glass void tegra_dc_sor_set_panel_power(struct udevice *dev, int power_up)
24600f37327SSimon Glass {
247d7659212SSimon Glass struct tegra_dc_sor_data *sor = dev_get_priv(dev);
24800f37327SSimon Glass u32 reg_val;
24900f37327SSimon Glass
25000f37327SSimon Glass reg_val = tegra_sor_readl(sor, DP_PADCTL(sor->portnum));
25100f37327SSimon Glass
25200f37327SSimon Glass if (power_up)
25300f37327SSimon Glass reg_val |= DP_PADCTL_PAD_CAL_PD_POWERUP;
25400f37327SSimon Glass else
25500f37327SSimon Glass reg_val &= ~DP_PADCTL_PAD_CAL_PD_POWERUP;
25600f37327SSimon Glass
25700f37327SSimon Glass tegra_sor_writel(sor, DP_PADCTL(sor->portnum), reg_val);
25800f37327SSimon Glass }
25900f37327SSimon Glass
tegra_dc_sor_config_pwm(struct tegra_dc_sor_data * sor,u32 pwm_div,u32 pwm_dutycycle)26000f37327SSimon Glass static void tegra_dc_sor_config_pwm(struct tegra_dc_sor_data *sor, u32 pwm_div,
26100f37327SSimon Glass u32 pwm_dutycycle)
26200f37327SSimon Glass {
26300f37327SSimon Glass tegra_sor_writel(sor, PWM_DIV, pwm_div);
26400f37327SSimon Glass tegra_sor_writel(sor, PWM_CTL,
26500f37327SSimon Glass (pwm_dutycycle & PWM_CTL_DUTY_CYCLE_MASK) |
26600f37327SSimon Glass PWM_CTL_SETTING_NEW_TRIGGER);
26700f37327SSimon Glass
26800f37327SSimon Glass if (tegra_dc_sor_poll_register(sor, PWM_CTL,
26900f37327SSimon Glass PWM_CTL_SETTING_NEW_SHIFT,
27000f37327SSimon Glass PWM_CTL_SETTING_NEW_DONE,
27100f37327SSimon Glass 100, TEGRA_SOR_TIMEOUT_MS)) {
27200f37327SSimon Glass debug("dp: timeout while waiting for SOR PWM setting\n");
27300f37327SSimon Glass }
27400f37327SSimon Glass }
27500f37327SSimon Glass
tegra_dc_sor_set_dp_mode(struct udevice * dev,const struct tegra_dp_link_config * link_cfg)276d7659212SSimon Glass static void tegra_dc_sor_set_dp_mode(struct udevice *dev,
27700f37327SSimon Glass const struct tegra_dp_link_config *link_cfg)
27800f37327SSimon Glass {
279d7659212SSimon Glass struct tegra_dc_sor_data *sor = dev_get_priv(dev);
28000f37327SSimon Glass u32 reg_val;
28100f37327SSimon Glass
282d7659212SSimon Glass tegra_dc_sor_set_link_bandwidth(dev, link_cfg->link_bw);
28300f37327SSimon Glass
284d7659212SSimon Glass tegra_dc_sor_set_dp_linkctl(dev, 1, training_pattern_none, link_cfg);
28500f37327SSimon Glass reg_val = tegra_sor_readl(sor, DP_CONFIG(sor->portnum));
28600f37327SSimon Glass reg_val &= ~DP_CONFIG_WATERMARK_MASK;
28700f37327SSimon Glass reg_val |= link_cfg->watermark;
28800f37327SSimon Glass reg_val &= ~DP_CONFIG_ACTIVESYM_COUNT_MASK;
28900f37327SSimon Glass reg_val |= (link_cfg->active_count <<
29000f37327SSimon Glass DP_CONFIG_ACTIVESYM_COUNT_SHIFT);
29100f37327SSimon Glass reg_val &= ~DP_CONFIG_ACTIVESYM_FRAC_MASK;
29200f37327SSimon Glass reg_val |= (link_cfg->active_frac <<
29300f37327SSimon Glass DP_CONFIG_ACTIVESYM_FRAC_SHIFT);
29400f37327SSimon Glass if (link_cfg->activepolarity)
29500f37327SSimon Glass reg_val |= DP_CONFIG_ACTIVESYM_POLARITY_POSITIVE;
29600f37327SSimon Glass else
29700f37327SSimon Glass reg_val &= ~DP_CONFIG_ACTIVESYM_POLARITY_POSITIVE;
29800f37327SSimon Glass reg_val |= (DP_CONFIG_ACTIVESYM_CNTL_ENABLE |
29900f37327SSimon Glass DP_CONFIG_RD_RESET_VAL_NEGATIVE);
30000f37327SSimon Glass
30100f37327SSimon Glass tegra_sor_writel(sor, DP_CONFIG(sor->portnum), reg_val);
30200f37327SSimon Glass
30300f37327SSimon Glass /* program h/vblank sym */
30400f37327SSimon Glass tegra_sor_write_field(sor, DP_AUDIO_HBLANK_SYMBOLS,
30500f37327SSimon Glass DP_AUDIO_HBLANK_SYMBOLS_MASK,
30600f37327SSimon Glass link_cfg->hblank_sym);
30700f37327SSimon Glass
30800f37327SSimon Glass tegra_sor_write_field(sor, DP_AUDIO_VBLANK_SYMBOLS,
30900f37327SSimon Glass DP_AUDIO_VBLANK_SYMBOLS_MASK,
31000f37327SSimon Glass link_cfg->vblank_sym);
31100f37327SSimon Glass }
31200f37327SSimon Glass
tegra_dc_sor_super_update(struct tegra_dc_sor_data * sor)31300f37327SSimon Glass static inline void tegra_dc_sor_super_update(struct tegra_dc_sor_data *sor)
31400f37327SSimon Glass {
31500f37327SSimon Glass tegra_sor_writel(sor, SUPER_STATE0, 0);
31600f37327SSimon Glass tegra_sor_writel(sor, SUPER_STATE0, 1);
31700f37327SSimon Glass tegra_sor_writel(sor, SUPER_STATE0, 0);
31800f37327SSimon Glass }
31900f37327SSimon Glass
tegra_dc_sor_update(struct tegra_dc_sor_data * sor)32000f37327SSimon Glass static inline void tegra_dc_sor_update(struct tegra_dc_sor_data *sor)
32100f37327SSimon Glass {
32200f37327SSimon Glass tegra_sor_writel(sor, STATE0, 0);
32300f37327SSimon Glass tegra_sor_writel(sor, STATE0, 1);
32400f37327SSimon Glass tegra_sor_writel(sor, STATE0, 0);
32500f37327SSimon Glass }
32600f37327SSimon Glass
tegra_dc_sor_io_set_dpd(struct tegra_dc_sor_data * sor,int up)32700f37327SSimon Glass static int tegra_dc_sor_io_set_dpd(struct tegra_dc_sor_data *sor, int up)
32800f37327SSimon Glass {
32900f37327SSimon Glass u32 reg_val;
33000f37327SSimon Glass void *pmc_base = sor->pmc_base;
33100f37327SSimon Glass
33200f37327SSimon Glass if (up) {
33300f37327SSimon Glass writel(APBDEV_PMC_DPD_SAMPLE_ON_ENABLE,
33400f37327SSimon Glass pmc_base + APBDEV_PMC_DPD_SAMPLE);
33500f37327SSimon Glass writel(10, pmc_base + APBDEV_PMC_SEL_DPD_TIM);
33600f37327SSimon Glass }
33700f37327SSimon Glass
33800f37327SSimon Glass reg_val = readl(pmc_base + APBDEV_PMC_IO_DPD2_REQ);
33900f37327SSimon Glass reg_val &= ~(APBDEV_PMC_IO_DPD2_REQ_LVDS_ON ||
34000f37327SSimon Glass APBDEV_PMC_IO_DPD2_REQ_CODE_DEFAULT_MASK);
34100f37327SSimon Glass
34200f37327SSimon Glass reg_val = up ? APBDEV_PMC_IO_DPD2_REQ_LVDS_ON |
34300f37327SSimon Glass APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_OFF :
34400f37327SSimon Glass APBDEV_PMC_IO_DPD2_REQ_LVDS_OFF |
34500f37327SSimon Glass APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_ON;
34600f37327SSimon Glass
34700f37327SSimon Glass writel(reg_val, pmc_base + APBDEV_PMC_IO_DPD2_REQ);
34800f37327SSimon Glass
34900f37327SSimon Glass /* Polling */
35000f37327SSimon Glass u32 temp = 10 * 1000;
35100f37327SSimon Glass do {
35200f37327SSimon Glass udelay(20);
35300f37327SSimon Glass reg_val = readl(pmc_base + APBDEV_PMC_IO_DPD2_STATUS);
35400f37327SSimon Glass if (temp > 20)
35500f37327SSimon Glass temp -= 20;
35600f37327SSimon Glass else
35700f37327SSimon Glass break;
35800f37327SSimon Glass } while ((reg_val & APBDEV_PMC_IO_DPD2_STATUS_LVDS_ON) != 0);
35900f37327SSimon Glass
36000f37327SSimon Glass if ((reg_val & APBDEV_PMC_IO_DPD2_STATUS_LVDS_ON) != 0) {
36100f37327SSimon Glass debug("PMC_IO_DPD2 polling failed (0x%x)\n", reg_val);
36200f37327SSimon Glass return -EIO;
36300f37327SSimon Glass }
36400f37327SSimon Glass
36500f37327SSimon Glass if (up) {
36600f37327SSimon Glass writel(APBDEV_PMC_DPD_SAMPLE_ON_DISABLE,
36700f37327SSimon Glass pmc_base + APBDEV_PMC_DPD_SAMPLE);
36800f37327SSimon Glass }
36900f37327SSimon Glass
37000f37327SSimon Glass return 0;
37100f37327SSimon Glass }
37200f37327SSimon Glass
tegra_dc_sor_set_internal_panel(struct udevice * dev,int is_int)373d7659212SSimon Glass void tegra_dc_sor_set_internal_panel(struct udevice *dev, int is_int)
37400f37327SSimon Glass {
375d7659212SSimon Glass struct tegra_dc_sor_data *sor = dev_get_priv(dev);
37600f37327SSimon Glass u32 reg_val;
37700f37327SSimon Glass
37800f37327SSimon Glass reg_val = tegra_sor_readl(sor, DP_SPARE(sor->portnum));
37900f37327SSimon Glass if (is_int)
38000f37327SSimon Glass reg_val |= DP_SPARE_PANEL_INTERNAL;
38100f37327SSimon Glass else
38200f37327SSimon Glass reg_val &= ~DP_SPARE_PANEL_INTERNAL;
38300f37327SSimon Glass
38400f37327SSimon Glass reg_val |= DP_SPARE_SOR_CLK_SEL_MACRO_SORCLK |
38500f37327SSimon Glass DP_SPARE_SEQ_ENABLE_YES;
38600f37327SSimon Glass tegra_sor_writel(sor, DP_SPARE(sor->portnum), reg_val);
38700f37327SSimon Glass }
38800f37327SSimon Glass
tegra_dc_sor_read_link_config(struct udevice * dev,u8 * link_bw,u8 * lane_count)389d7659212SSimon Glass void tegra_dc_sor_read_link_config(struct udevice *dev, u8 *link_bw,
39000f37327SSimon Glass u8 *lane_count)
39100f37327SSimon Glass {
392d7659212SSimon Glass struct tegra_dc_sor_data *sor = dev_get_priv(dev);
39300f37327SSimon Glass u32 reg_val;
39400f37327SSimon Glass
39500f37327SSimon Glass reg_val = tegra_sor_readl(sor, CLK_CNTRL);
39600f37327SSimon Glass *link_bw = (reg_val & CLK_CNTRL_DP_LINK_SPEED_MASK)
39700f37327SSimon Glass >> CLK_CNTRL_DP_LINK_SPEED_SHIFT;
39800f37327SSimon Glass reg_val = tegra_sor_readl(sor,
39900f37327SSimon Glass DP_LINKCTL(sor->portnum));
40000f37327SSimon Glass
40100f37327SSimon Glass switch (reg_val & DP_LINKCTL_LANECOUNT_MASK) {
40200f37327SSimon Glass case DP_LINKCTL_LANECOUNT_ZERO:
40300f37327SSimon Glass *lane_count = 0;
40400f37327SSimon Glass break;
40500f37327SSimon Glass case DP_LINKCTL_LANECOUNT_ONE:
40600f37327SSimon Glass *lane_count = 1;
40700f37327SSimon Glass break;
40800f37327SSimon Glass case DP_LINKCTL_LANECOUNT_TWO:
40900f37327SSimon Glass *lane_count = 2;
41000f37327SSimon Glass break;
41100f37327SSimon Glass case DP_LINKCTL_LANECOUNT_FOUR:
41200f37327SSimon Glass *lane_count = 4;
41300f37327SSimon Glass break;
41400f37327SSimon Glass default:
41500f37327SSimon Glass printf("Unknown lane count\n");
41600f37327SSimon Glass }
41700f37327SSimon Glass }
41800f37327SSimon Glass
tegra_dc_sor_set_link_bandwidth(struct udevice * dev,u8 link_bw)419d7659212SSimon Glass void tegra_dc_sor_set_link_bandwidth(struct udevice *dev, u8 link_bw)
42000f37327SSimon Glass {
421d7659212SSimon Glass struct tegra_dc_sor_data *sor = dev_get_priv(dev);
422d7659212SSimon Glass
42300f37327SSimon Glass tegra_sor_write_field(sor, CLK_CNTRL,
42400f37327SSimon Glass CLK_CNTRL_DP_LINK_SPEED_MASK,
42500f37327SSimon Glass link_bw << CLK_CNTRL_DP_LINK_SPEED_SHIFT);
42600f37327SSimon Glass }
42700f37327SSimon Glass
tegra_dc_sor_set_lane_count(struct udevice * dev,u8 lane_count)428d7659212SSimon Glass void tegra_dc_sor_set_lane_count(struct udevice *dev, u8 lane_count)
42900f37327SSimon Glass {
430d7659212SSimon Glass struct tegra_dc_sor_data *sor = dev_get_priv(dev);
43100f37327SSimon Glass u32 reg_val;
43200f37327SSimon Glass
43300f37327SSimon Glass reg_val = tegra_sor_readl(sor, DP_LINKCTL(sor->portnum));
43400f37327SSimon Glass reg_val &= ~DP_LINKCTL_LANECOUNT_MASK;
43500f37327SSimon Glass switch (lane_count) {
43600f37327SSimon Glass case 0:
43700f37327SSimon Glass break;
43800f37327SSimon Glass case 1:
43900f37327SSimon Glass reg_val |= DP_LINKCTL_LANECOUNT_ONE;
44000f37327SSimon Glass break;
44100f37327SSimon Glass case 2:
44200f37327SSimon Glass reg_val |= DP_LINKCTL_LANECOUNT_TWO;
44300f37327SSimon Glass break;
44400f37327SSimon Glass case 4:
44500f37327SSimon Glass reg_val |= DP_LINKCTL_LANECOUNT_FOUR;
44600f37327SSimon Glass break;
44700f37327SSimon Glass default:
44800f37327SSimon Glass /* 0 should be handled earlier. */
44900f37327SSimon Glass printf("dp: Invalid lane count %d\n", lane_count);
45000f37327SSimon Glass return;
45100f37327SSimon Glass }
45200f37327SSimon Glass tegra_sor_writel(sor, DP_LINKCTL(sor->portnum), reg_val);
45300f37327SSimon Glass }
45400f37327SSimon Glass
45500f37327SSimon Glass /*
45600f37327SSimon Glass * The SOR power sequencer does not work for t124 so SW has to
45700f37327SSimon Glass * go through the power sequence manually
45800f37327SSimon Glass * Power up steps from spec:
45900f37327SSimon Glass * STEP PDPORT PDPLL PDBG PLLVCOD PLLCAPD E_DPD PDCAL
46000f37327SSimon Glass * 1 1 1 1 1 1 1 1
46100f37327SSimon Glass * 2 1 1 1 1 1 0 1
46200f37327SSimon Glass * 3 1 1 0 1 1 0 1
46300f37327SSimon Glass * 4 1 0 0 0 0 0 1
46400f37327SSimon Glass * 5 0 0 0 0 0 0 1
46500f37327SSimon Glass */
tegra_dc_sor_power_up(struct udevice * dev,int is_lvds)466d7659212SSimon Glass static int tegra_dc_sor_power_up(struct udevice *dev, int is_lvds)
46700f37327SSimon Glass {
468d7659212SSimon Glass struct tegra_dc_sor_data *sor = dev_get_priv(dev);
469505907a4SSimon Glass u32 reg;
47000f37327SSimon Glass int ret;
47100f37327SSimon Glass
47200f37327SSimon Glass if (sor->power_is_up)
47300f37327SSimon Glass return 0;
47400f37327SSimon Glass
475505907a4SSimon Glass /*
476505907a4SSimon Glass * If for some reason it is already powered up, don't do it again.
477505907a4SSimon Glass * This can happen if U-Boot is the secondary boot loader.
478505907a4SSimon Glass */
479505907a4SSimon Glass reg = tegra_sor_readl(sor, DP_PADCTL(sor->portnum));
480505907a4SSimon Glass if (reg & DP_PADCTL_PD_TXD_0_NO)
481505907a4SSimon Glass return 0;
482505907a4SSimon Glass
48300f37327SSimon Glass /* Set link bw */
484d7659212SSimon Glass tegra_dc_sor_set_link_bandwidth(dev, is_lvds ?
48500f37327SSimon Glass CLK_CNTRL_DP_LINK_SPEED_LVDS :
48600f37327SSimon Glass CLK_CNTRL_DP_LINK_SPEED_G1_62);
48700f37327SSimon Glass
48800f37327SSimon Glass /* step 1 */
48900f37327SSimon Glass tegra_sor_write_field(sor, PLL2,
49000f37327SSimon Glass PLL2_AUX7_PORT_POWERDOWN_MASK | /* PDPORT */
49100f37327SSimon Glass PLL2_AUX6_BANDGAP_POWERDOWN_MASK | /* PDBG */
49200f37327SSimon Glass PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK, /* PLLCAPD */
49300f37327SSimon Glass PLL2_AUX7_PORT_POWERDOWN_ENABLE |
49400f37327SSimon Glass PLL2_AUX6_BANDGAP_POWERDOWN_ENABLE |
49500f37327SSimon Glass PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_ENABLE);
49600f37327SSimon Glass tegra_sor_write_field(sor, PLL0, PLL0_PWR_MASK | /* PDPLL */
49700f37327SSimon Glass PLL0_VCOPD_MASK, /* PLLVCOPD */
49800f37327SSimon Glass PLL0_PWR_OFF | PLL0_VCOPD_ASSERT);
49900f37327SSimon Glass tegra_sor_write_field(sor, DP_PADCTL(sor->portnum),
50000f37327SSimon Glass DP_PADCTL_PAD_CAL_PD_POWERDOWN, /* PDCAL */
50100f37327SSimon Glass DP_PADCTL_PAD_CAL_PD_POWERDOWN);
50200f37327SSimon Glass
50300f37327SSimon Glass /* step 2 */
50400f37327SSimon Glass ret = tegra_dc_sor_io_set_dpd(sor, 1);
50500f37327SSimon Glass if (ret)
50600f37327SSimon Glass return ret;
50700f37327SSimon Glass udelay(15);
50800f37327SSimon Glass
50900f37327SSimon Glass /* step 3 */
51000f37327SSimon Glass tegra_sor_write_field(sor, PLL2,
51100f37327SSimon Glass PLL2_AUX6_BANDGAP_POWERDOWN_MASK,
51200f37327SSimon Glass PLL2_AUX6_BANDGAP_POWERDOWN_DISABLE);
51300f37327SSimon Glass udelay(25);
51400f37327SSimon Glass
51500f37327SSimon Glass /* step 4 */
51600f37327SSimon Glass tegra_sor_write_field(sor, PLL0,
51700f37327SSimon Glass PLL0_PWR_MASK | /* PDPLL */
51800f37327SSimon Glass PLL0_VCOPD_MASK, /* PLLVCOPD */
51900f37327SSimon Glass PLL0_PWR_ON | PLL0_VCOPD_RESCIND);
52000f37327SSimon Glass /* PLLCAPD */
52100f37327SSimon Glass tegra_sor_write_field(sor, PLL2,
52200f37327SSimon Glass PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK,
52300f37327SSimon Glass PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE);
52400f37327SSimon Glass udelay(225);
52500f37327SSimon Glass
52600f37327SSimon Glass /* step 5 PDPORT */
52700f37327SSimon Glass tegra_sor_write_field(sor, PLL2,
52800f37327SSimon Glass PLL2_AUX7_PORT_POWERDOWN_MASK,
52900f37327SSimon Glass PLL2_AUX7_PORT_POWERDOWN_DISABLE);
53000f37327SSimon Glass
53100f37327SSimon Glass sor->power_is_up = 1;
53200f37327SSimon Glass
53300f37327SSimon Glass return 0;
53400f37327SSimon Glass }
53500f37327SSimon Glass
53600f37327SSimon Glass #if DEBUG_SOR
dump_sor_reg(struct tegra_dc_sor_data * sor)53700f37327SSimon Glass static void dump_sor_reg(struct tegra_dc_sor_data *sor)
53800f37327SSimon Glass {
53900f37327SSimon Glass #define DUMP_REG(a) printk(BIOS_INFO, "%-32s %03x %08x\n", \
54000f37327SSimon Glass #a, a, tegra_sor_readl(sor, a));
54100f37327SSimon Glass
54200f37327SSimon Glass DUMP_REG(SUPER_STATE0);
54300f37327SSimon Glass DUMP_REG(SUPER_STATE1);
54400f37327SSimon Glass DUMP_REG(STATE0);
54500f37327SSimon Glass DUMP_REG(STATE1);
54600f37327SSimon Glass DUMP_REG(NV_HEAD_STATE0(0));
54700f37327SSimon Glass DUMP_REG(NV_HEAD_STATE0(1));
54800f37327SSimon Glass DUMP_REG(NV_HEAD_STATE1(0));
54900f37327SSimon Glass DUMP_REG(NV_HEAD_STATE1(1));
55000f37327SSimon Glass DUMP_REG(NV_HEAD_STATE2(0));
55100f37327SSimon Glass DUMP_REG(NV_HEAD_STATE2(1));
55200f37327SSimon Glass DUMP_REG(NV_HEAD_STATE3(0));
55300f37327SSimon Glass DUMP_REG(NV_HEAD_STATE3(1));
55400f37327SSimon Glass DUMP_REG(NV_HEAD_STATE4(0));
55500f37327SSimon Glass DUMP_REG(NV_HEAD_STATE4(1));
55600f37327SSimon Glass DUMP_REG(NV_HEAD_STATE5(0));
55700f37327SSimon Glass DUMP_REG(NV_HEAD_STATE5(1));
55800f37327SSimon Glass DUMP_REG(CRC_CNTRL);
55900f37327SSimon Glass DUMP_REG(CLK_CNTRL);
56000f37327SSimon Glass DUMP_REG(CAP);
56100f37327SSimon Glass DUMP_REG(PWR);
56200f37327SSimon Glass DUMP_REG(TEST);
56300f37327SSimon Glass DUMP_REG(PLL0);
56400f37327SSimon Glass DUMP_REG(PLL1);
56500f37327SSimon Glass DUMP_REG(PLL2);
56600f37327SSimon Glass DUMP_REG(PLL3);
56700f37327SSimon Glass DUMP_REG(CSTM);
56800f37327SSimon Glass DUMP_REG(LVDS);
56900f37327SSimon Glass DUMP_REG(CRCA);
57000f37327SSimon Glass DUMP_REG(CRCB);
57100f37327SSimon Glass DUMP_REG(SEQ_CTL);
57200f37327SSimon Glass DUMP_REG(LANE_SEQ_CTL);
57300f37327SSimon Glass DUMP_REG(SEQ_INST(0));
57400f37327SSimon Glass DUMP_REG(SEQ_INST(1));
57500f37327SSimon Glass DUMP_REG(SEQ_INST(2));
57600f37327SSimon Glass DUMP_REG(SEQ_INST(3));
57700f37327SSimon Glass DUMP_REG(SEQ_INST(4));
57800f37327SSimon Glass DUMP_REG(SEQ_INST(5));
57900f37327SSimon Glass DUMP_REG(SEQ_INST(6));
58000f37327SSimon Glass DUMP_REG(SEQ_INST(7));
58100f37327SSimon Glass DUMP_REG(SEQ_INST(8));
58200f37327SSimon Glass DUMP_REG(PWM_DIV);
58300f37327SSimon Glass DUMP_REG(PWM_CTL);
58400f37327SSimon Glass DUMP_REG(MSCHECK);
58500f37327SSimon Glass DUMP_REG(XBAR_CTRL);
58600f37327SSimon Glass DUMP_REG(DP_LINKCTL(0));
58700f37327SSimon Glass DUMP_REG(DP_LINKCTL(1));
58800f37327SSimon Glass DUMP_REG(DC(0));
58900f37327SSimon Glass DUMP_REG(DC(1));
59000f37327SSimon Glass DUMP_REG(LANE_DRIVE_CURRENT(0));
59100f37327SSimon Glass DUMP_REG(PR(0));
59200f37327SSimon Glass DUMP_REG(LANE4_PREEMPHASIS(0));
59300f37327SSimon Glass DUMP_REG(POSTCURSOR(0));
59400f37327SSimon Glass DUMP_REG(DP_CONFIG(0));
59500f37327SSimon Glass DUMP_REG(DP_CONFIG(1));
59600f37327SSimon Glass DUMP_REG(DP_MN(0));
59700f37327SSimon Glass DUMP_REG(DP_MN(1));
59800f37327SSimon Glass DUMP_REG(DP_PADCTL(0));
59900f37327SSimon Glass DUMP_REG(DP_PADCTL(1));
60000f37327SSimon Glass DUMP_REG(DP_DEBUG(0));
60100f37327SSimon Glass DUMP_REG(DP_DEBUG(1));
60200f37327SSimon Glass DUMP_REG(DP_SPARE(0));
60300f37327SSimon Glass DUMP_REG(DP_SPARE(1));
60400f37327SSimon Glass DUMP_REG(DP_TPG);
60500f37327SSimon Glass
60600f37327SSimon Glass return;
60700f37327SSimon Glass }
60800f37327SSimon Glass #endif
60900f37327SSimon Glass
tegra_dc_sor_config_panel(struct tegra_dc_sor_data * sor,int is_lvds,const struct tegra_dp_link_config * link_cfg,const struct display_timing * timing)61000f37327SSimon Glass static void tegra_dc_sor_config_panel(struct tegra_dc_sor_data *sor,
61100f37327SSimon Glass int is_lvds,
61200f37327SSimon Glass const struct tegra_dp_link_config *link_cfg,
61300f37327SSimon Glass const struct display_timing *timing)
61400f37327SSimon Glass {
61500f37327SSimon Glass const int head_num = 0;
61600f37327SSimon Glass u32 reg_val = STATE1_ASY_OWNER_HEAD0 << head_num;
61700f37327SSimon Glass u32 vtotal, htotal;
61800f37327SSimon Glass u32 vsync_end, hsync_end;
61900f37327SSimon Glass u32 vblank_end, hblank_end;
62000f37327SSimon Glass u32 vblank_start, hblank_start;
62100f37327SSimon Glass
62200f37327SSimon Glass reg_val |= is_lvds ? STATE1_ASY_PROTOCOL_LVDS_CUSTOM :
62300f37327SSimon Glass STATE1_ASY_PROTOCOL_DP_A;
62400f37327SSimon Glass reg_val |= STATE1_ASY_SUBOWNER_NONE |
62500f37327SSimon Glass STATE1_ASY_CRCMODE_COMPLETE_RASTER;
62600f37327SSimon Glass
62700f37327SSimon Glass reg_val |= STATE1_ASY_HSYNCPOL_NEGATIVE_TRUE;
62800f37327SSimon Glass reg_val |= STATE1_ASY_VSYNCPOL_NEGATIVE_TRUE;
62900f37327SSimon Glass reg_val |= (link_cfg->bits_per_pixel > 18) ?
63000f37327SSimon Glass STATE1_ASY_PIXELDEPTH_BPP_24_444 :
63100f37327SSimon Glass STATE1_ASY_PIXELDEPTH_BPP_18_444;
63200f37327SSimon Glass
63300f37327SSimon Glass tegra_sor_writel(sor, STATE1, reg_val);
63400f37327SSimon Glass
63500f37327SSimon Glass /*
63600f37327SSimon Glass * Skipping programming NV_HEAD_STATE0, assuming:
63700f37327SSimon Glass * interlacing: PROGRESSIVE, dynamic range: VESA, colorspace: RGB
63800f37327SSimon Glass */
63900f37327SSimon Glass vtotal = timing->vsync_len.typ + timing->vback_porch.typ +
64000f37327SSimon Glass timing->vactive.typ + timing->vfront_porch.typ;
64100f37327SSimon Glass htotal = timing->hsync_len.typ + timing->hback_porch.typ +
64200f37327SSimon Glass timing->hactive.typ + timing->hfront_porch.typ;
64300f37327SSimon Glass
64400f37327SSimon Glass tegra_sor_writel(sor, NV_HEAD_STATE1(head_num),
64500f37327SSimon Glass vtotal << NV_HEAD_STATE1_VTOTAL_SHIFT |
64600f37327SSimon Glass htotal << NV_HEAD_STATE1_HTOTAL_SHIFT);
64700f37327SSimon Glass
64800f37327SSimon Glass vsync_end = timing->vsync_len.typ - 1;
64900f37327SSimon Glass hsync_end = timing->hsync_len.typ - 1;
65000f37327SSimon Glass tegra_sor_writel(sor, NV_HEAD_STATE2(head_num),
65100f37327SSimon Glass vsync_end << NV_HEAD_STATE2_VSYNC_END_SHIFT |
65200f37327SSimon Glass hsync_end << NV_HEAD_STATE2_HSYNC_END_SHIFT);
65300f37327SSimon Glass
65400f37327SSimon Glass vblank_end = vsync_end + timing->vback_porch.typ;
65500f37327SSimon Glass hblank_end = hsync_end + timing->hback_porch.typ;
65600f37327SSimon Glass tegra_sor_writel(sor, NV_HEAD_STATE3(head_num),
65700f37327SSimon Glass vblank_end << NV_HEAD_STATE3_VBLANK_END_SHIFT |
65800f37327SSimon Glass hblank_end << NV_HEAD_STATE3_HBLANK_END_SHIFT);
65900f37327SSimon Glass
66000f37327SSimon Glass vblank_start = vblank_end + timing->vactive.typ;
66100f37327SSimon Glass hblank_start = hblank_end + timing->hactive.typ;
66200f37327SSimon Glass tegra_sor_writel(sor, NV_HEAD_STATE4(head_num),
66300f37327SSimon Glass vblank_start << NV_HEAD_STATE4_VBLANK_START_SHIFT |
66400f37327SSimon Glass hblank_start << NV_HEAD_STATE4_HBLANK_START_SHIFT);
66500f37327SSimon Glass
66600f37327SSimon Glass /* TODO: adding interlace mode support */
66700f37327SSimon Glass tegra_sor_writel(sor, NV_HEAD_STATE5(head_num), 0x1);
66800f37327SSimon Glass
66900f37327SSimon Glass tegra_sor_write_field(sor, CSTM,
67000f37327SSimon Glass CSTM_ROTCLK_DEFAULT_MASK |
67100f37327SSimon Glass CSTM_LVDS_EN_ENABLE,
67200f37327SSimon Glass 2 << CSTM_ROTCLK_SHIFT |
67300f37327SSimon Glass is_lvds ? CSTM_LVDS_EN_ENABLE :
67400f37327SSimon Glass CSTM_LVDS_EN_DISABLE);
67500f37327SSimon Glass
67600f37327SSimon Glass tegra_dc_sor_config_pwm(sor, 1024, 1024);
67700f37327SSimon Glass }
67800f37327SSimon Glass
tegra_dc_sor_enable_dc(struct dc_ctlr * disp_ctrl)67900f37327SSimon Glass static void tegra_dc_sor_enable_dc(struct dc_ctlr *disp_ctrl)
68000f37327SSimon Glass {
68100f37327SSimon Glass u32 reg_val = readl(&disp_ctrl->cmd.state_access);
68200f37327SSimon Glass
68300f37327SSimon Glass writel(reg_val | WRITE_MUX_ACTIVE, &disp_ctrl->cmd.state_access);
68400f37327SSimon Glass writel(VSYNC_H_POSITION(1), &disp_ctrl->disp.disp_timing_opt);
68500f37327SSimon Glass
68600f37327SSimon Glass /* Enable DC now - otherwise pure text console may not show. */
68700f37327SSimon Glass writel(CTRL_MODE_C_DISPLAY << CTRL_MODE_SHIFT,
68800f37327SSimon Glass &disp_ctrl->cmd.disp_cmd);
68900f37327SSimon Glass writel(reg_val, &disp_ctrl->cmd.state_access);
69000f37327SSimon Glass }
69100f37327SSimon Glass
tegra_dc_sor_enable_dp(struct udevice * dev,const struct tegra_dp_link_config * link_cfg)692d7659212SSimon Glass int tegra_dc_sor_enable_dp(struct udevice *dev,
69300f37327SSimon Glass const struct tegra_dp_link_config *link_cfg)
69400f37327SSimon Glass {
695d7659212SSimon Glass struct tegra_dc_sor_data *sor = dev_get_priv(dev);
69600f37327SSimon Glass int ret;
69700f37327SSimon Glass
69800f37327SSimon Glass tegra_sor_write_field(sor, CLK_CNTRL,
69900f37327SSimon Glass CLK_CNTRL_DP_CLK_SEL_MASK,
70000f37327SSimon Glass CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK);
70100f37327SSimon Glass
70200f37327SSimon Glass tegra_sor_write_field(sor, PLL2,
70300f37327SSimon Glass PLL2_AUX6_BANDGAP_POWERDOWN_MASK,
70400f37327SSimon Glass PLL2_AUX6_BANDGAP_POWERDOWN_DISABLE);
70500f37327SSimon Glass udelay(25);
70600f37327SSimon Glass
70700f37327SSimon Glass tegra_sor_write_field(sor, PLL3,
70800f37327SSimon Glass PLL3_PLLVDD_MODE_MASK,
70900f37327SSimon Glass PLL3_PLLVDD_MODE_V3_3);
71000f37327SSimon Glass tegra_sor_writel(sor, PLL0,
71100f37327SSimon Glass 0xf << PLL0_ICHPMP_SHFIT |
71200f37327SSimon Glass 0x3 << PLL0_VCOCAP_SHIFT |
71300f37327SSimon Glass PLL0_PLLREG_LEVEL_V45 |
71400f37327SSimon Glass PLL0_RESISTORSEL_EXT |
71500f37327SSimon Glass PLL0_PWR_ON | PLL0_VCOPD_RESCIND);
71600f37327SSimon Glass tegra_sor_write_field(sor, PLL2,
71700f37327SSimon Glass PLL2_AUX1_SEQ_MASK |
71800f37327SSimon Glass PLL2_AUX9_LVDSEN_OVERRIDE |
71900f37327SSimon Glass PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK,
72000f37327SSimon Glass PLL2_AUX1_SEQ_PLLCAPPD_OVERRIDE |
72100f37327SSimon Glass PLL2_AUX9_LVDSEN_OVERRIDE |
72200f37327SSimon Glass PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE);
72300f37327SSimon Glass tegra_sor_writel(sor, PLL1, PLL1_TERM_COMPOUT_HIGH |
72400f37327SSimon Glass PLL1_TMDS_TERM_ENABLE);
72500f37327SSimon Glass
72600f37327SSimon Glass if (tegra_dc_sor_poll_register(sor, PLL2,
72700f37327SSimon Glass PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK,
72800f37327SSimon Glass PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE,
72900f37327SSimon Glass 100, TEGRA_SOR_TIMEOUT_MS)) {
73000f37327SSimon Glass printf("DP failed to lock PLL\n");
73100f37327SSimon Glass return -EIO;
73200f37327SSimon Glass }
73300f37327SSimon Glass
73400f37327SSimon Glass tegra_sor_write_field(sor, PLL2, PLL2_AUX2_MASK |
73500f37327SSimon Glass PLL2_AUX7_PORT_POWERDOWN_MASK,
73600f37327SSimon Glass PLL2_AUX2_OVERRIDE_POWERDOWN |
73700f37327SSimon Glass PLL2_AUX7_PORT_POWERDOWN_DISABLE);
73800f37327SSimon Glass
739d7659212SSimon Glass ret = tegra_dc_sor_power_up(dev, 0);
74000f37327SSimon Glass if (ret) {
74100f37327SSimon Glass debug("DP failed to power up\n");
74200f37327SSimon Glass return ret;
74300f37327SSimon Glass }
74400f37327SSimon Glass
74500f37327SSimon Glass /* re-enable SOR clock */
74600f37327SSimon Glass clock_sor_enable_edp_clock();
74700f37327SSimon Glass
74800f37327SSimon Glass /* Power up lanes */
749d7659212SSimon Glass tegra_dc_sor_power_dplanes(dev, link_cfg->lane_count, 1);
75000f37327SSimon Glass
751d7659212SSimon Glass tegra_dc_sor_set_dp_mode(dev, link_cfg);
75200f37327SSimon Glass debug("%s ret\n", __func__);
75300f37327SSimon Glass
75400f37327SSimon Glass return 0;
75500f37327SSimon Glass }
75600f37327SSimon Glass
tegra_dc_sor_attach(struct udevice * dc_dev,struct udevice * dev,const struct tegra_dp_link_config * link_cfg,const struct display_timing * timing)757d7659212SSimon Glass int tegra_dc_sor_attach(struct udevice *dc_dev, struct udevice *dev,
75800f37327SSimon Glass const struct tegra_dp_link_config *link_cfg,
75900f37327SSimon Glass const struct display_timing *timing)
76000f37327SSimon Glass {
761d7659212SSimon Glass struct tegra_dc_sor_data *sor = dev_get_priv(dev);
76200f37327SSimon Glass struct dc_ctlr *disp_ctrl;
76300f37327SSimon Glass u32 reg_val;
76400f37327SSimon Glass
76500f37327SSimon Glass /* Use the first display controller */
76600f37327SSimon Glass debug("%s\n", __func__);
767*079ff3b9SSimon Glass disp_ctrl = (struct dc_ctlr *)dev_read_addr(dc_dev);
76800f37327SSimon Glass
76900f37327SSimon Glass tegra_dc_sor_enable_dc(disp_ctrl);
77000f37327SSimon Glass tegra_dc_sor_config_panel(sor, 0, link_cfg, timing);
77100f37327SSimon Glass
77200f37327SSimon Glass writel(0x9f00, &disp_ctrl->cmd.state_ctrl);
77300f37327SSimon Glass writel(0x9f, &disp_ctrl->cmd.state_ctrl);
77400f37327SSimon Glass
77500f37327SSimon Glass writel(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
77600f37327SSimon Glass PW4_ENABLE | PM0_ENABLE | PM1_ENABLE,
77700f37327SSimon Glass &disp_ctrl->cmd.disp_pow_ctrl);
77800f37327SSimon Glass
77900f37327SSimon Glass reg_val = tegra_sor_readl(sor, TEST);
78000f37327SSimon Glass if (reg_val & TEST_ATTACHED_TRUE)
78100f37327SSimon Glass return -EEXIST;
78200f37327SSimon Glass
78300f37327SSimon Glass tegra_sor_writel(sor, SUPER_STATE1,
78400f37327SSimon Glass SUPER_STATE1_ATTACHED_NO);
78500f37327SSimon Glass
78600f37327SSimon Glass /*
78700f37327SSimon Glass * Enable display2sor clock at least 2 cycles before DC start,
78800f37327SSimon Glass * to clear sor internal valid signal.
78900f37327SSimon Glass */
79000f37327SSimon Glass writel(SOR_ENABLE, &disp_ctrl->disp.disp_win_opt);
79100f37327SSimon Glass writel(GENERAL_ACT_REQ, &disp_ctrl->cmd.state_ctrl);
79200f37327SSimon Glass writel(0, &disp_ctrl->disp.disp_win_opt);
79300f37327SSimon Glass writel(GENERAL_ACT_REQ, &disp_ctrl->cmd.state_ctrl);
79400f37327SSimon Glass
79500f37327SSimon Glass /* Attach head */
79600f37327SSimon Glass tegra_dc_sor_update(sor);
79700f37327SSimon Glass tegra_sor_writel(sor, SUPER_STATE1,
79800f37327SSimon Glass SUPER_STATE1_ATTACHED_YES);
79900f37327SSimon Glass tegra_sor_writel(sor, SUPER_STATE1,
80000f37327SSimon Glass SUPER_STATE1_ATTACHED_YES |
80100f37327SSimon Glass SUPER_STATE1_ASY_HEAD_OP_AWAKE |
80200f37327SSimon Glass SUPER_STATE1_ASY_ORMODE_NORMAL);
80300f37327SSimon Glass tegra_dc_sor_super_update(sor);
80400f37327SSimon Glass
80500f37327SSimon Glass /* Enable dc */
80600f37327SSimon Glass reg_val = readl(&disp_ctrl->cmd.state_access);
80700f37327SSimon Glass writel(reg_val | WRITE_MUX_ACTIVE, &disp_ctrl->cmd.state_access);
80800f37327SSimon Glass writel(CTRL_MODE_C_DISPLAY << CTRL_MODE_SHIFT,
80900f37327SSimon Glass &disp_ctrl->cmd.disp_cmd);
81000f37327SSimon Glass writel(SOR_ENABLE, &disp_ctrl->disp.disp_win_opt);
81100f37327SSimon Glass writel(reg_val, &disp_ctrl->cmd.state_access);
81200f37327SSimon Glass
81300f37327SSimon Glass if (tegra_dc_sor_poll_register(sor, TEST,
81400f37327SSimon Glass TEST_ACT_HEAD_OPMODE_DEFAULT_MASK,
81500f37327SSimon Glass TEST_ACT_HEAD_OPMODE_AWAKE,
81600f37327SSimon Glass 100,
81700f37327SSimon Glass TEGRA_SOR_ATTACH_TIMEOUT_MS)) {
81800f37327SSimon Glass printf("dc timeout waiting for OPMOD = AWAKE\n");
81900f37327SSimon Glass return -ETIMEDOUT;
82000f37327SSimon Glass } else {
82100f37327SSimon Glass debug("%s: sor is attached\n", __func__);
82200f37327SSimon Glass }
82300f37327SSimon Glass
82400f37327SSimon Glass #if DEBUG_SOR
82500f37327SSimon Glass dump_sor_reg(sor);
82600f37327SSimon Glass #endif
82700f37327SSimon Glass debug("%s: ret=%d\n", __func__, 0);
82800f37327SSimon Glass
82900f37327SSimon Glass return 0;
83000f37327SSimon Glass }
83100f37327SSimon Glass
tegra_dc_sor_set_lane_parm(struct udevice * dev,const struct tegra_dp_link_config * link_cfg)832d7659212SSimon Glass void tegra_dc_sor_set_lane_parm(struct udevice *dev,
83300f37327SSimon Glass const struct tegra_dp_link_config *link_cfg)
83400f37327SSimon Glass {
835d7659212SSimon Glass struct tegra_dc_sor_data *sor = dev_get_priv(dev);
836d7659212SSimon Glass
83700f37327SSimon Glass tegra_sor_writel(sor, LANE_DRIVE_CURRENT(sor->portnum),
83800f37327SSimon Glass link_cfg->drive_current);
83900f37327SSimon Glass tegra_sor_writel(sor, PR(sor->portnum),
84000f37327SSimon Glass link_cfg->preemphasis);
84100f37327SSimon Glass tegra_sor_writel(sor, POSTCURSOR(sor->portnum),
84200f37327SSimon Glass link_cfg->postcursor);
84300f37327SSimon Glass tegra_sor_writel(sor, LVDS, 0);
84400f37327SSimon Glass
845d7659212SSimon Glass tegra_dc_sor_set_link_bandwidth(dev, link_cfg->link_bw);
846d7659212SSimon Glass tegra_dc_sor_set_lane_count(dev, link_cfg->lane_count);
84700f37327SSimon Glass
84800f37327SSimon Glass tegra_sor_write_field(sor, DP_PADCTL(sor->portnum),
84900f37327SSimon Glass DP_PADCTL_TX_PU_ENABLE |
85000f37327SSimon Glass DP_PADCTL_TX_PU_VALUE_DEFAULT_MASK,
85100f37327SSimon Glass DP_PADCTL_TX_PU_ENABLE |
85200f37327SSimon Glass 2 << DP_PADCTL_TX_PU_VALUE_SHIFT);
85300f37327SSimon Glass
85400f37327SSimon Glass /* Precharge */
85500f37327SSimon Glass tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), 0xf0, 0xf0);
85600f37327SSimon Glass udelay(20);
85700f37327SSimon Glass
85800f37327SSimon Glass tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), 0xf0, 0x0);
85900f37327SSimon Glass }
86000f37327SSimon Glass
tegra_dc_sor_set_voltage_swing(struct udevice * dev,const struct tegra_dp_link_config * link_cfg)861d7659212SSimon Glass int tegra_dc_sor_set_voltage_swing(struct udevice *dev,
862dedc44b4SSimon Glass const struct tegra_dp_link_config *link_cfg)
863dedc44b4SSimon Glass {
864d7659212SSimon Glass struct tegra_dc_sor_data *sor = dev_get_priv(dev);
865dedc44b4SSimon Glass u32 drive_current = 0;
866dedc44b4SSimon Glass u32 pre_emphasis = 0;
867dedc44b4SSimon Glass
868dedc44b4SSimon Glass /* Set to a known-good pre-calibrated setting */
869dedc44b4SSimon Glass switch (link_cfg->link_bw) {
870dedc44b4SSimon Glass case SOR_LINK_SPEED_G1_62:
871dedc44b4SSimon Glass case SOR_LINK_SPEED_G2_7:
872dedc44b4SSimon Glass drive_current = 0x13131313;
873dedc44b4SSimon Glass pre_emphasis = 0;
874dedc44b4SSimon Glass break;
875dedc44b4SSimon Glass case SOR_LINK_SPEED_G5_4:
876dedc44b4SSimon Glass debug("T124 does not support 5.4G link clock.\n");
877dedc44b4SSimon Glass default:
878dedc44b4SSimon Glass debug("Invalid sor link bandwidth: %d\n", link_cfg->link_bw);
879dedc44b4SSimon Glass return -ENOLINK;
880dedc44b4SSimon Glass }
881dedc44b4SSimon Glass
882dedc44b4SSimon Glass tegra_sor_writel(sor, LANE_DRIVE_CURRENT(sor->portnum), drive_current);
883dedc44b4SSimon Glass tegra_sor_writel(sor, PR(sor->portnum), pre_emphasis);
884dedc44b4SSimon Glass
885dedc44b4SSimon Glass return 0;
886dedc44b4SSimon Glass }
887dedc44b4SSimon Glass
tegra_dc_sor_power_down_unused_lanes(struct udevice * dev,const struct tegra_dp_link_config * link_cfg)888d7659212SSimon Glass void tegra_dc_sor_power_down_unused_lanes(struct udevice *dev,
88900f37327SSimon Glass const struct tegra_dp_link_config *link_cfg)
89000f37327SSimon Glass {
891d7659212SSimon Glass struct tegra_dc_sor_data *sor = dev_get_priv(dev);
89200f37327SSimon Glass u32 pad_ctrl = 0;
89300f37327SSimon Glass int err = 0;
89400f37327SSimon Glass
89500f37327SSimon Glass switch (link_cfg->lane_count) {
89600f37327SSimon Glass case 4:
89700f37327SSimon Glass pad_ctrl = DP_PADCTL_PD_TXD_0_NO |
89800f37327SSimon Glass DP_PADCTL_PD_TXD_1_NO |
89900f37327SSimon Glass DP_PADCTL_PD_TXD_2_NO |
90000f37327SSimon Glass DP_PADCTL_PD_TXD_3_NO;
90100f37327SSimon Glass break;
90200f37327SSimon Glass case 2:
90300f37327SSimon Glass pad_ctrl = DP_PADCTL_PD_TXD_0_NO |
90400f37327SSimon Glass DP_PADCTL_PD_TXD_1_NO |
90500f37327SSimon Glass DP_PADCTL_PD_TXD_2_YES |
90600f37327SSimon Glass DP_PADCTL_PD_TXD_3_YES;
90700f37327SSimon Glass break;
90800f37327SSimon Glass case 1:
90900f37327SSimon Glass pad_ctrl = DP_PADCTL_PD_TXD_0_NO |
91000f37327SSimon Glass DP_PADCTL_PD_TXD_1_YES |
91100f37327SSimon Glass DP_PADCTL_PD_TXD_2_YES |
91200f37327SSimon Glass DP_PADCTL_PD_TXD_3_YES;
91300f37327SSimon Glass break;
91400f37327SSimon Glass default:
91500f37327SSimon Glass printf("Invalid sor lane count: %u\n", link_cfg->lane_count);
91600f37327SSimon Glass return;
91700f37327SSimon Glass }
91800f37327SSimon Glass
91900f37327SSimon Glass pad_ctrl |= DP_PADCTL_PAD_CAL_PD_POWERDOWN;
92000f37327SSimon Glass tegra_sor_writel(sor, DP_PADCTL(sor->portnum), pad_ctrl);
92100f37327SSimon Glass
92200f37327SSimon Glass err = tegra_dc_sor_enable_lane_sequencer(sor, 0, 0);
92300f37327SSimon Glass if (err) {
92400f37327SSimon Glass debug("Wait for lane power down failed: %d\n", err);
92500f37327SSimon Glass return;
92600f37327SSimon Glass }
92700f37327SSimon Glass }
92800f37327SSimon Glass
tegra_sor_precharge_lanes(struct udevice * dev,const struct tegra_dp_link_config * cfg)929d7659212SSimon Glass int tegra_sor_precharge_lanes(struct udevice *dev,
930dedc44b4SSimon Glass const struct tegra_dp_link_config *cfg)
931dedc44b4SSimon Glass {
932d7659212SSimon Glass struct tegra_dc_sor_data *sor = dev_get_priv(dev);
933dedc44b4SSimon Glass u32 val = 0;
934dedc44b4SSimon Glass
935dedc44b4SSimon Glass switch (cfg->lane_count) {
936dedc44b4SSimon Glass case 4:
937dedc44b4SSimon Glass val |= (DP_PADCTL_PD_TXD_3_NO |
938dedc44b4SSimon Glass DP_PADCTL_PD_TXD_2_NO);
939dedc44b4SSimon Glass /* fall through */
940dedc44b4SSimon Glass case 2:
941dedc44b4SSimon Glass val |= DP_PADCTL_PD_TXD_1_NO;
942dedc44b4SSimon Glass /* fall through */
943dedc44b4SSimon Glass case 1:
944dedc44b4SSimon Glass val |= DP_PADCTL_PD_TXD_0_NO;
945dedc44b4SSimon Glass break;
946dedc44b4SSimon Glass default:
947dedc44b4SSimon Glass debug("dp: invalid lane number %d\n", cfg->lane_count);
948dedc44b4SSimon Glass return -EINVAL;
949dedc44b4SSimon Glass }
950dedc44b4SSimon Glass
951dedc44b4SSimon Glass tegra_sor_write_field(sor, DP_PADCTL(sor->portnum),
952dedc44b4SSimon Glass (0xf << DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT),
953dedc44b4SSimon Glass (val << DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT));
954dedc44b4SSimon Glass udelay(100);
955dedc44b4SSimon Glass tegra_sor_write_field(sor, DP_PADCTL(sor->portnum),
956dedc44b4SSimon Glass (0xf << DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT),
957dedc44b4SSimon Glass 0);
958dedc44b4SSimon Glass
959dedc44b4SSimon Glass return 0;
960dedc44b4SSimon Glass }
961dedc44b4SSimon Glass
tegra_dc_sor_enable_sor(struct dc_ctlr * disp_ctrl,bool enable)962dedc44b4SSimon Glass static void tegra_dc_sor_enable_sor(struct dc_ctlr *disp_ctrl, bool enable)
963dedc44b4SSimon Glass {
964dedc44b4SSimon Glass u32 reg_val = readl(&disp_ctrl->disp.disp_win_opt);
965dedc44b4SSimon Glass
966dedc44b4SSimon Glass reg_val = enable ? reg_val | SOR_ENABLE : reg_val & ~SOR_ENABLE;
967dedc44b4SSimon Glass writel(reg_val, &disp_ctrl->disp.disp_win_opt);
968dedc44b4SSimon Glass }
969dedc44b4SSimon Glass
tegra_dc_sor_detach(struct udevice * dc_dev,struct udevice * dev)970d7659212SSimon Glass int tegra_dc_sor_detach(struct udevice *dc_dev, struct udevice *dev)
971dedc44b4SSimon Glass {
972d7659212SSimon Glass struct tegra_dc_sor_data *sor = dev_get_priv(dev);
973dedc44b4SSimon Glass int dc_reg_ctx[DC_REG_SAVE_SPACE];
974dedc44b4SSimon Glass struct dc_ctlr *disp_ctrl;
975dedc44b4SSimon Glass unsigned long dc_int_mask;
976dedc44b4SSimon Glass int ret;
977dedc44b4SSimon Glass
978dedc44b4SSimon Glass debug("%s\n", __func__);
979dedc44b4SSimon Glass /* Use the first display controller */
980*079ff3b9SSimon Glass disp_ctrl = (struct dc_ctlr *)dev_read_addr(dev);
981dedc44b4SSimon Glass
982dedc44b4SSimon Glass /* Sleep mode */
983dedc44b4SSimon Glass tegra_sor_writel(sor, SUPER_STATE1, SUPER_STATE1_ASY_HEAD_OP_SLEEP |
984dedc44b4SSimon Glass SUPER_STATE1_ASY_ORMODE_SAFE |
985dedc44b4SSimon Glass SUPER_STATE1_ATTACHED_YES);
986dedc44b4SSimon Glass tegra_dc_sor_super_update(sor);
987dedc44b4SSimon Glass
988dedc44b4SSimon Glass tegra_dc_sor_disable_win_short_raster(disp_ctrl, dc_reg_ctx);
989dedc44b4SSimon Glass
990dedc44b4SSimon Glass if (tegra_dc_sor_poll_register(sor, TEST,
991dedc44b4SSimon Glass TEST_ACT_HEAD_OPMODE_DEFAULT_MASK,
992dedc44b4SSimon Glass TEST_ACT_HEAD_OPMODE_SLEEP, 100,
993dedc44b4SSimon Glass TEGRA_SOR_ATTACH_TIMEOUT_MS)) {
994dedc44b4SSimon Glass debug("dc timeout waiting for OPMOD = SLEEP\n");
995dedc44b4SSimon Glass ret = -ETIMEDOUT;
996dedc44b4SSimon Glass goto err;
997dedc44b4SSimon Glass }
998dedc44b4SSimon Glass
999dedc44b4SSimon Glass tegra_sor_writel(sor, SUPER_STATE1, SUPER_STATE1_ASY_HEAD_OP_SLEEP |
1000dedc44b4SSimon Glass SUPER_STATE1_ASY_ORMODE_SAFE |
1001dedc44b4SSimon Glass SUPER_STATE1_ATTACHED_NO);
1002dedc44b4SSimon Glass
1003dedc44b4SSimon Glass /* Mask DC interrupts during the 2 dummy frames required for detach */
1004dedc44b4SSimon Glass dc_int_mask = readl(&disp_ctrl->cmd.int_mask);
1005dedc44b4SSimon Glass writel(0, &disp_ctrl->cmd.int_mask);
1006dedc44b4SSimon Glass
1007dedc44b4SSimon Glass /* Stop DC->SOR path */
1008dedc44b4SSimon Glass tegra_dc_sor_enable_sor(disp_ctrl, false);
1009dedc44b4SSimon Glass ret = tegra_dc_sor_general_act(disp_ctrl);
1010dedc44b4SSimon Glass if (ret)
1011dedc44b4SSimon Glass goto err;
1012dedc44b4SSimon Glass
1013dedc44b4SSimon Glass /* Stop DC */
1014dedc44b4SSimon Glass writel(CTRL_MODE_STOP << CTRL_MODE_SHIFT, &disp_ctrl->cmd.disp_cmd);
1015dedc44b4SSimon Glass ret = tegra_dc_sor_general_act(disp_ctrl);
1016dedc44b4SSimon Glass if (ret)
1017dedc44b4SSimon Glass goto err;
1018dedc44b4SSimon Glass
1019dedc44b4SSimon Glass tegra_dc_sor_restore_win_and_raster(disp_ctrl, dc_reg_ctx);
1020dedc44b4SSimon Glass
1021dedc44b4SSimon Glass writel(dc_int_mask, &disp_ctrl->cmd.int_mask);
1022dedc44b4SSimon Glass
1023dedc44b4SSimon Glass return 0;
1024dedc44b4SSimon Glass err:
1025dedc44b4SSimon Glass debug("%s: ret=%d\n", __func__, ret);
1026dedc44b4SSimon Glass
1027dedc44b4SSimon Glass return ret;
102800f37327SSimon Glass }
102900f37327SSimon Glass
tegra_sor_set_backlight(struct udevice * dev,int percent)1030d7659212SSimon Glass static int tegra_sor_set_backlight(struct udevice *dev, int percent)
103100f37327SSimon Glass {
1032d7659212SSimon Glass struct tegra_dc_sor_data *priv = dev_get_priv(dev);
1033d7659212SSimon Glass int ret;
103400f37327SSimon Glass
1035d7659212SSimon Glass ret = panel_enable_backlight(priv->panel);
1036d7659212SSimon Glass if (ret) {
1037d7659212SSimon Glass debug("sor: Cannot enable panel backlight\n");
1038d7659212SSimon Glass return ret;
1039d7659212SSimon Glass }
104000f37327SSimon Glass
104100f37327SSimon Glass return 0;
104200f37327SSimon Glass }
1043d7659212SSimon Glass
tegra_sor_ofdata_to_platdata(struct udevice * dev)1044d7659212SSimon Glass static int tegra_sor_ofdata_to_platdata(struct udevice *dev)
1045d7659212SSimon Glass {
1046d7659212SSimon Glass struct tegra_dc_sor_data *priv = dev_get_priv(dev);
1047d7659212SSimon Glass int ret;
1048d7659212SSimon Glass
1049*079ff3b9SSimon Glass priv->base = (void *)dev_read_addr(dev);
1050d7659212SSimon Glass
1051*079ff3b9SSimon Glass priv->pmc_base = (void *)syscon_get_first_range(TEGRA_SYSCON_PMC);
1052*079ff3b9SSimon Glass if (IS_ERR(priv->pmc_base))
1053*079ff3b9SSimon Glass return PTR_ERR(priv->pmc_base);
1054d7659212SSimon Glass
1055d7659212SSimon Glass ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, "nvidia,panel",
1056d7659212SSimon Glass &priv->panel);
1057d7659212SSimon Glass if (ret) {
1058d7659212SSimon Glass debug("%s: Cannot find panel for '%s' (ret=%d)\n", __func__,
1059d7659212SSimon Glass dev->name, ret);
1060d7659212SSimon Glass return ret;
1061d7659212SSimon Glass }
1062d7659212SSimon Glass
1063d7659212SSimon Glass return 0;
1064d7659212SSimon Glass }
1065d7659212SSimon Glass
1066d7659212SSimon Glass static const struct video_bridge_ops tegra_sor_ops = {
1067d7659212SSimon Glass .set_backlight = tegra_sor_set_backlight,
1068d7659212SSimon Glass };
1069d7659212SSimon Glass
1070d7659212SSimon Glass static const struct udevice_id tegra_sor_ids[] = {
1071d7659212SSimon Glass { .compatible = "nvidia,tegra124-sor" },
1072d7659212SSimon Glass { }
1073d7659212SSimon Glass };
1074d7659212SSimon Glass
1075d7659212SSimon Glass U_BOOT_DRIVER(sor_tegra) = {
1076d7659212SSimon Glass .name = "sor_tegra",
1077d7659212SSimon Glass .id = UCLASS_VIDEO_BRIDGE,
1078d7659212SSimon Glass .of_match = tegra_sor_ids,
1079d7659212SSimon Glass .ofdata_to_platdata = tegra_sor_ofdata_to_platdata,
1080d7659212SSimon Glass .ops = &tegra_sor_ops,
1081d7659212SSimon Glass .priv_auto_alloc_size = sizeof(struct tegra_dc_sor_data),
1082d7659212SSimon Glass };
1083