blob: 7a402df5940fcd5ec473f4ec99be7d89d48571a3 [file] [log] [blame]
Jimmy Zhange3a938d2014-09-15 16:50:36 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2014 Google Inc.
5 *
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.
9 *
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.
Jimmy Zhange3a938d2014-09-15 16:50:36 -070014 */
15#include <console/console.h>
16#include <arch/io.h>
17#include <stdint.h>
18#include <lib.h>
19#include <stdlib.h>
20#include <delay.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"
29
30static unsigned long dsi_pads[] = {
31 0x060, /* DSIA & DSIB pads */
32 0x180, /* DSIC & DSID pads */
33};
34
35static struct tegra_mipi mipi_data = {
36 .regs = (void *)TEGRA_MIPI_CAL_BASE,
37};
38
39static inline unsigned long tegra_mipi_readl(struct tegra_mipi *mipi,
40 unsigned long reg)
41{
Julius Werner2f37bd62015-02-19 14:51:15 -080042 return read32(mipi->regs + (reg << 2));
Jimmy Zhange3a938d2014-09-15 16:50:36 -070043}
44
45static inline void tegra_mipi_writel(struct tegra_mipi *mipi,
46 unsigned long value, unsigned long reg)
47{
Julius Werner2f37bd62015-02-19 14:51:15 -080048 write32(mipi->regs + (reg << 2), value);
Jimmy Zhange3a938d2014-09-15 16:50:36 -070049}
50
51static const struct calibration_regs tegra124_mipi_calibration_regs[] = {
52 { .data = MIPI_CAL_CONFIG_CSIA, .clk = MIPI_CAL_CONFIG_CSIAB_CLK },
53 { .data = MIPI_CAL_CONFIG_CSIB, .clk = MIPI_CAL_CONFIG_CSIAB_CLK },
54 { .data = MIPI_CAL_CONFIG_CSIC, .clk = MIPI_CAL_CONFIG_CSICD_CLK },
55 { .data = MIPI_CAL_CONFIG_CSID, .clk = MIPI_CAL_CONFIG_CSICD_CLK },
56 { .data = MIPI_CAL_CONFIG_CSIE, .clk = MIPI_CAL_CONFIG_CSIE_CLK },
57 { .data = MIPI_CAL_CONFIG_DSIA, .clk = MIPI_CAL_CONFIG_DSIAB_CLK },
58 { .data = MIPI_CAL_CONFIG_DSIB, .clk = MIPI_CAL_CONFIG_DSIAB_CLK },
59};
60static const struct tegra_mipi_config tegra124_mipi_config = {
61 .calibrate_clk_lane = 1,
62 .regs = tegra124_mipi_calibration_regs,
63 .num_pads = ARRAY_SIZE(tegra124_mipi_calibration_regs),
64};
65
66struct tegra_mipi_device *tegra_mipi_request(struct tegra_mipi_device *device,
67 int device_index)
68{
69 device->mipi = &mipi_data;
70 device->config = &tegra124_mipi_config;
71 device->pads = dsi_pads[device_index];
72
73 return device;
74}
75
76static int tegra_mipi_wait(struct tegra_mipi *mipi)
77{
78 u32 poll_interval_us = 1000;
79 u32 timeout_us = 250 * 1000;
80 unsigned long value;
81
82 do {
83 value = tegra_mipi_readl(mipi, MIPI_CAL_STATUS);
84 if ((value & MIPI_CAL_STATUS_ACTIVE) == 0 &&
85 (value & MIPI_CAL_STATUS_DONE) != 0)
86 return 0;
87
88 if (timeout_us > poll_interval_us)
89 timeout_us -= poll_interval_us;
90 else
91 break;
92
93 udelay(poll_interval_us);
94 } while (1);
95
96 printk(BIOS_ERR, "%s: ERROR: timeout\n", __func__);
97 return -ETIMEDOUT;
98}
99
100int tegra_mipi_calibrate(struct tegra_mipi_device *device)
101{
102 const struct tegra_mipi_config *cfg = device->config;
103 unsigned long value, clk_value;
104 unsigned int i;
105 int err;
106
107 value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG0);
108 value &= ~MIPI_CAL_BIAS_PAD_PDVCLAMP;
109 value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF;
110 tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG0);
111
112 tegra_mipi_writel(device->mipi, MIPI_CAL_BIAS_PAD_CFG1_DEFAULT,
113 MIPI_CAL_BIAS_PAD_CFG1);
114
115 value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2);
116 value &= ~MIPI_CAL_BIAS_PAD_PDVREG;
117 tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG2);
118
119 for (i = 0; i < cfg->num_pads; i++) {
120 if (device->pads & BIT(i)) {
121 value = MIPI_CAL_CONFIG_SELECT |
122 MIPI_CAL_CONFIG_HSPDOS(0) |
123 MIPI_CAL_CONFIG_HSPUOS(4) |
124 MIPI_CAL_CONFIG_TERMOS(5);
125 clk_value = MIPI_CAL_CONFIG_SELECT |
126 MIPI_CAL_CONFIG_HSCLKPDOSD(0) |
127 MIPI_CAL_CONFIG_HSCLKPUOSD(4);
128 } else {
129 value = 0;
130 clk_value = 0;
131 }
132
133 tegra_mipi_writel(device->mipi, value, cfg->regs[i].data);
134
135 if (cfg->calibrate_clk_lane)
136 tegra_mipi_writel(device->mipi, clk_value,
137 cfg->regs[i].clk);
138 }
139
140 value = tegra_mipi_readl(device->mipi, MIPI_CAL_CTRL);
141 value |= MIPI_CAL_CTRL_START;
142 tegra_mipi_writel(device->mipi, value, MIPI_CAL_CTRL);
143
144 err = tegra_mipi_wait(device->mipi);
145
146 return err;
147}