2 * This file is part of the coreboot project.
4 * Copyright 2014 Google Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 #include <console/console.h>
21 #include <soc/addressmap.h>
22 #include <soc/clock.h>
23 #include <device/device.h>
24 #include <soc/nvidia/tegra/types.h>
25 #include <soc/display.h>
26 #include <soc/mipi_dsi.h>
27 #include <soc/tegra_dsi.h>
28 #include "jdi_25x18_display/panel-jdi-lpm102a188a.h"
30 static unsigned long dsi_pads
[] = {
31 0x0c0, /* DSIA channel A & B pads */
32 0x300, /* DSIB channel A & B pads */
35 static struct tegra_mipi mipi_data
= {
36 .regs
= (void *)TEGRA_MIPI_CAL_BASE
,
39 static inline unsigned long tegra_mipi_readl(struct tegra_mipi
*mipi
,
42 return read32(mipi
->regs
+ (reg
<< 2));
45 static inline void tegra_mipi_writel(struct tegra_mipi
*mipi
,
46 unsigned long value
, unsigned long reg
)
48 write32(mipi
->regs
+ (reg
<< 2), value
);
51 static const struct tegra_mipi_pad tegra210_mipi_pads
[] = {
52 { .data
= MIPI_CAL_CONFIG_CSIA
, .clk
= 0 },
53 { .data
= MIPI_CAL_CONFIG_CSIB
, .clk
= 0 },
54 { .data
= MIPI_CAL_CONFIG_CSIC
, .clk
= 0 },
55 { .data
= MIPI_CAL_CONFIG_CSID
, .clk
= 0 },
56 { .data
= MIPI_CAL_CONFIG_CSIE
, .clk
= 0 },
57 { .data
= MIPI_CAL_CONFIG_CSIF
, .clk
= 0 },
58 { .data
= MIPI_CAL_CONFIG_DSIA
, .clk
= MIPI_CAL_CONFIG_DSIA_CLK
},
59 { .data
= MIPI_CAL_CONFIG_DSIB
, .clk
= MIPI_CAL_CONFIG_DSIB_CLK
},
60 { .data
= MIPI_CAL_CONFIG_DSIC
, .clk
= MIPI_CAL_CONFIG_DSIC_CLK
},
61 { .data
= MIPI_CAL_CONFIG_DSID
, .clk
= MIPI_CAL_CONFIG_DSID_CLK
},
64 static const struct tegra_mipi_soc tegra210_mipi_soc
= {
66 .pads
= tegra210_mipi_pads
,
67 .num_pads
= ARRAY_SIZE(tegra210_mipi_pads
),
68 .clock_enable_override
= 1,
69 .needs_vclamp_ref
= 0,
70 .pad_drive_down_ref
= 0x0,
71 .pad_drive_up_ref
= 0x3,
72 .pad_vclamp_level
= 0x1,
73 .pad_vauxp_level
= 0x1,
81 struct tegra_mipi_device
*tegra_mipi_request(struct tegra_mipi_device
*device
,
84 device
->mipi
= &mipi_data
;
85 device
->mipi
->soc
= &tegra210_mipi_soc
;
86 device
->pads
= dsi_pads
[device_index
];
91 static int tegra_mipi_wait(struct tegra_mipi
*mipi
)
93 u32 poll_interval_us
= 1000;
94 u32 timeout_us
= 250 * 1000;
98 value
= tegra_mipi_readl(mipi
, MIPI_CAL_STATUS
);
99 if ((value
& MIPI_CAL_STATUS_ACTIVE
) == 0 &&
100 (value
& MIPI_CAL_STATUS_DONE
) != 0)
103 if (timeout_us
> poll_interval_us
)
104 timeout_us
-= poll_interval_us
;
108 udelay(poll_interval_us
);
111 printk(BIOS_ERR
, "%s: ERROR: timeout\n", __func__
);
115 int tegra_mipi_calibrate(struct tegra_mipi_device
*device
)
117 const struct tegra_mipi_soc
*soc
= device
->mipi
->soc
;
122 value
= tegra_mipi_readl(device
->mipi
, MIPI_CAL_BIAS_PAD_CFG0
);
123 value
&= ~MIPI_CAL_BIAS_PAD_PDVCLAMP
;
125 if (soc
->needs_vclamp_ref
)
126 value
|= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF
;
128 tegra_mipi_writel(device
->mipi
, value
, MIPI_CAL_BIAS_PAD_CFG0
);
130 value
= MIPI_CAL_BIAS_PAD_DRV_DN_REF(soc
->pad_drive_down_ref
) |
131 MIPI_CAL_BIAS_PAD_DRV_UP_REF(soc
->pad_drive_up_ref
);
132 tegra_mipi_writel(device
->mipi
, value
, MIPI_CAL_BIAS_PAD_CFG1
);
134 value
= tegra_mipi_readl(device
->mipi
, MIPI_CAL_BIAS_PAD_CFG2
);
135 value
&= ~MIPI_CAL_BIAS_PAD_PDVREG
;
136 tegra_mipi_writel(device
->mipi
, value
, MIPI_CAL_BIAS_PAD_CFG2
);
138 value
= tegra_mipi_readl(device
->mipi
, MIPI_CAL_BIAS_PAD_CFG2
);
139 value
&= ~MIPI_CAL_BIAS_PAD_VCLAMP(0x7);
140 value
&= ~MIPI_CAL_BIAS_PAD_VAUXP(0x7);
141 value
|= MIPI_CAL_BIAS_PAD_VCLAMP(soc
->pad_vclamp_level
);
142 value
|= MIPI_CAL_BIAS_PAD_VAUXP(soc
->pad_vauxp_level
);
143 tegra_mipi_writel(device
->mipi
, value
, MIPI_CAL_BIAS_PAD_CFG2
);
145 for (i
= 0; i
< soc
->num_pads
; i
++) {
146 u32 clk
= 0, data
= 0;
148 if (device
->pads
& BIT(i
)) {
149 data
= MIPI_CAL_CONFIG_SELECT
|
150 MIPI_CAL_CONFIG_HSPDOS(soc
->hspdos
) |
151 MIPI_CAL_CONFIG_HSPUOS(soc
->hspuos
) |
152 MIPI_CAL_CONFIG_TERMOS(soc
->termos
);
153 clk
= MIPI_CAL_CONFIG_SELECT
|
154 MIPI_CAL_CONFIG_HSCLKPDOSD(soc
->hsclkpdos
) |
155 MIPI_CAL_CONFIG_HSCLKPUOSD(soc
->hsclkpuos
);
158 tegra_mipi_writel(device
->mipi
, data
, soc
->pads
[i
].data
);
160 if (soc
->has_clk_lane
&& soc
->pads
[i
].clk
!= 0)
161 tegra_mipi_writel(device
->mipi
, clk
, soc
->pads
[i
].clk
);
164 value
= tegra_mipi_readl(device
->mipi
, MIPI_CAL_CTRL
);
165 value
&= ~MIPI_CAL_CTRL_NOISE_FILTER(0xf);
166 value
&= ~MIPI_CAL_CTRL_PRESCALE(0x3);
167 value
|= MIPI_CAL_CTRL_NOISE_FILTER(0xa);
168 value
|= MIPI_CAL_CTRL_PRESCALE(0x2);
170 if (!soc
->clock_enable_override
)
171 value
&= ~MIPI_CAL_CTRL_CLKEN_OVR
;
173 value
|= MIPI_CAL_CTRL_CLKEN_OVR
;
175 tegra_mipi_writel(device
->mipi
, value
, MIPI_CAL_CTRL
);
177 /* clear any pending status bits */
178 value
= tegra_mipi_readl(device
->mipi
, MIPI_CAL_STATUS
);
179 tegra_mipi_writel(device
->mipi
, value
, MIPI_CAL_STATUS
);
181 value
= tegra_mipi_readl(device
->mipi
, MIPI_CAL_CTRL
);
182 value
|= MIPI_CAL_CTRL_START
;
183 tegra_mipi_writel(device
->mipi
, value
, MIPI_CAL_CTRL
);
185 err
= tegra_mipi_wait(device
->mipi
);
187 printk(BIOS_ERR
, "failed to calibrate MIPI pads: %d\n", err
);
189 printk(BIOS_INFO
, "MIPI calibration done\n");
191 value
= tegra_mipi_readl(device
->mipi
, MIPI_CAL_BIAS_PAD_CFG0
);
193 if (soc
->needs_vclamp_ref
)
194 value
&= ~MIPI_CAL_BIAS_PAD_E_VCLAMP_REF
;
196 value
|= MIPI_CAL_BIAS_PAD_PDVCLAMP
;
197 tegra_mipi_writel(device
->mipi
, value
, MIPI_CAL_BIAS_PAD_CFG0
);