aboutsummaryrefslogtreecommitdiff
path: root/src/soc/nvidia/tegra124/sor.c
blob: 6a47833bef9713e14dfbe0b0cf074727751330c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*
 * drivers/video/tegra/dc/sor.c
 *
 * Copyright (c) 2011-2013, NVIDIA Corporation.
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <console/console.h>
#include <arch/io.h>
#include <stdint.h>
#include <lib.h>
#include <stdlib.h>
#include <delay.h>
#include <soc/addressmap.h>
#include <device/device.h>
#include <stdlib.h>
#include <string.h>
#include <cpu/cpu.h>
#include <boot/tables.h>
#include <cbmem.h>
#include <soc/nvidia/tegra/dc.h>
#include "sor.h"
#include <soc/nvidia/tegra/displayport.h>
#include "clk_rst.h"
#include <soc/clock.h>
#include "chip.h"
#include <soc/display.h>

#define APBDEV_PMC_DPD_SAMPLE				(0x20)
#define APBDEV_PMC_DPD_SAMPLE_ON_DISABLE		(0)
#define APBDEV_PMC_DPD_SAMPLE_ON_ENABLE			(1)
#define APBDEV_PMC_SEL_DPD_TIM				(0x1c8)
#define APBDEV_PMC_SEL_DPD_TIM_SEL_DPD_TIM_DEFAULT	(0x7f)
#define APBDEV_PMC_IO_DPD2_REQ				(0x1c0)
#define APBDEV_PMC_IO_DPD2_REQ_LVDS_SHIFT		(25)
#define APBDEV_PMC_IO_DPD2_REQ_LVDS_OFF			(0 << 25)
#define APBDEV_PMC_IO_DPD2_REQ_LVDS_ON			(1 << 25)
#define APBDEV_PMC_IO_DPD2_REQ_CODE_SHIFT               (30)
#define APBDEV_PMC_IO_DPD2_REQ_CODE_DEFAULT_MASK        (0x3 << 30)
#define APBDEV_PMC_IO_DPD2_REQ_CODE_IDLE                (0 << 30)
#define APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_OFF             (1 << 30)
#define APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_ON              (2 << 30)
#define APBDEV_PMC_IO_DPD2_STATUS			(0x1c4)
#define APBDEV_PMC_IO_DPD2_STATUS_LVDS_SHIFT		(25)
#define APBDEV_PMC_IO_DPD2_STATUS_LVDS_OFF		(0 << 25)
#define APBDEV_PMC_IO_DPD2_STATUS_LVDS_ON		(1 << 25)


static inline u32 tegra_sor_readl(struct tegra_dc_sor_data *sor, u32 reg)
{
	u32 reg_val = readl((sor->base + reg * 4));
	return reg_val;
}

static inline void tegra_sor_writel(struct tegra_dc_sor_data *sor,
	u32 reg, u32 val)
{
	writel(val, (sor->base + reg * 4));
}

static inline void tegra_sor_write_field(struct tegra_dc_sor_data *sor,
	u32 reg, u32 mask, u32 val)
{
	u32 reg_val = tegra_sor_readl(sor, reg);
	reg_val &= ~mask;
	reg_val |= val;
	tegra_sor_writel(sor, reg, reg_val);
}

void tegra_dc_sor_set_dp_linkctl(struct tegra_dc_sor_data *sor, int ena,
	u8 training_pattern, const struct tegra_dc_dp_link_config *cfg)
{
	u32 reg_val;

	reg_val = tegra_sor_readl(sor, NV_SOR_DP_LINKCTL(sor->portnum));

	if (ena)
		reg_val |= NV_SOR_DP_LINKCTL_ENABLE_YES;
	else
		reg_val &= NV_SOR_DP_LINKCTL_ENABLE_NO;

	reg_val &= ~NV_SOR_DP_LINKCTL_TUSIZE_MASK;
	reg_val |= (cfg->tu_size << NV_SOR_DP_LINKCTL_TUSIZE_SHIFT);

	if (cfg->enhanced_framing)
		reg_val |= NV_SOR_DP_LINKCTL_ENHANCEDFRAME_ENABLE;

	tegra_sor_writel(sor, NV_SOR_DP_LINKCTL(sor->portnum), reg_val);

	switch (training_pattern) {
	case trainingPattern_1:
		tegra_sor_writel(sor, NV_SOR_DP_TPG, 0x41414141);
		break;
	case trainingPattern_2:
	case trainingPattern_3:
		reg_val = (cfg->link_bw == NV_SOR_LINK_SPEED_G5_4) ?
			0x43434343 : 0x42424242;
		tegra_sor_writel(sor, NV_SOR_DP_TPG, reg_val);
		break;
	default:
		tegra_sor_writel(sor, NV_SOR_DP_TPG, 0x50505050);
		break;
	}
}

void tegra_dc_sor_set_dp_lanedata(struct tegra_dc_sor_data *sor,
	u32 lane, u32 pre_emphasis, u32 drive_current, u32 tx_pu)
{
	u32 d_cur;
	u32 p_emp;


	d_cur = tegra_sor_readl(sor, NV_SOR_DC(sor->portnum));
	p_emp = tegra_sor_readl(sor, NV_SOR_PR(sor->portnum));

	switch (lane) {
	case 0:
		p_emp &= ~NV_SOR_PR_LANE2_DP_LANE0_MASK;
		p_emp |= (pre_emphasis <<
			NV_SOR_PR_LANE2_DP_LANE0_SHIFT);
		d_cur &= ~NV_SOR_DC_LANE2_DP_LANE0_MASK;
		d_cur |= (drive_current <<
			NV_SOR_DC_LANE2_DP_LANE0_SHIFT);
		break;
	case 1:
		p_emp &= ~NV_SOR_PR_LANE1_DP_LANE1_MASK;
		p_emp |= (pre_emphasis <<
			NV_SOR_PR_LANE1_DP_LANE1_SHIFT);
		d_cur &= ~NV_SOR_DC_LANE1_DP_LANE1_MASK;
		d_cur |= (drive_current <<
			NV_SOR_DC_LANE1_DP_LANE1_SHIFT);
		break;
	case 2:
		p_emp &= ~NV_SOR_PR_LANE0_DP_LANE2_MASK;
		p_emp |= (pre_emphasis <<
			NV_SOR_PR_LANE0_DP_LANE2_SHIFT);
		d_cur &= ~NV_SOR_DC_LANE0_DP_LANE2_MASK;
		d_cur |= (drive_current <<
			NV_SOR_DC_LANE0_DP_LANE2_SHIFT);
		break;
	case 3:
		p_emp &= ~NV_SOR_PR_LANE3_DP_LANE3_MASK;
		p_emp |= (pre_emphasis <<
			NV_SOR_PR_LANE3_DP_LANE3_SHIFT);
		d_cur &= ~NV_SOR_DC_LANE3_DP_LANE3_MASK;
		d_cur |= (drive_current <<
			NV_SOR_DC_LANE3_DP_LANE3_SHIFT);
		break;
	default:
		printk(BIOS_SPEW, "dp: sor lane count %d is invalid\n", lane);
	}

	tegra_sor_write_field(sor, NV_SOR_DP_LINKCTL(sor->portnum),
		NV_SOR_DP_PADCTL_TX_PU_VALUE_DEFAULT_MASK,
		tx_pu << NV_SOR_DP_PADCTL_TX_PU_VALUE_SHIFT);

	tegra_sor_writel(sor, NV_SOR_DC(sor->portnum), d_cur);
	tegra_sor_writel(sor, NV_SOR_PR(sor->portnum), p_emp);
}