blob: 2df3c1a9942609a30268133a1b4412042b3244ed [file] [log] [blame]
Svyatoslav Ryhelba04d192024-01-23 19:16:28 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2013 NVIDIA Corporation
4 * Copyright (c) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
5 */
6
7#include <dm.h>
8#include <clk.h>
9#include <misc.h>
10#include <linux/delay.h>
11#include <linux/iopoll.h>
12
13#include <asm/io.h>
14
15/* MIPI control registers 0x00 ~ 0x60 */
16struct mipi_ctlr {
17 uint mipi_cal_ctrl;
18 uint mipi_cal_autocal_ctrl;
19 uint mipi_cal_status;
20
21 uint unused1[2];
22
23 uint mipi_cal_config_csia;
24 uint mipi_cal_config_csib;
25 uint mipi_cal_config_csic;
26 uint mipi_cal_config_csid;
27 uint mipi_cal_config_csie;
28
29 uint unused2[4];
30
31 uint mipi_cal_config_dsia;
32 uint mipi_cal_config_dsib;
33 uint mipi_cal_config_dsic;
34 uint mipi_cal_config_dsid;
35
36 uint unused3[4];
37
38 uint mipi_cal_bias_pad_cfg0;
39 uint mipi_cal_bias_pad_cfg1;
40 uint mipi_cal_bias_pad_cfg2;
41};
42
43#define MIPI_CAL_CTRL_NOISE_FILTER(x) (((x) & 0xf) << 26)
44#define MIPI_CAL_CTRL_PRESCALE(x) (((x) & 0x3) << 24)
45#define MIPI_CAL_CTRL_CLKEN_OVR BIT(4)
46#define MIPI_CAL_CTRL_START BIT(0)
47
48#define MIPI_CAL_STATUS_DONE BIT(16)
49#define MIPI_CAL_STATUS_ACTIVE BIT(0)
50
51#define MIPI_CAL_OVERIDE(x) (((x) & 0x1) << 30)
52#define MIPI_CAL_SEL(x) (((x) & 0x1) << 21)
53#define MIPI_CAL_HSPDOS(x) (((x) & 0x1f) << 16)
54#define MIPI_CAL_HSPUOS(x) (((x) & 0x1f) << 8)
55#define MIPI_CAL_TERMOS(x) (((x) & 0x1f) << 0)
56
57#define MIPI_CAL_BIAS_PAD_PDVCLAMP BIT(1)
58#define MIPI_CAL_BIAS_PAD_E_VCLAMP_REF BIT(0)
59
60#define MIPI_CAL_BIAS_PAD_DRV_DN_REF(x) (((x) & 0x7) << 16)
61#define MIPI_CAL_BIAS_PAD_DRV_UP_REF(x) (((x) & 0x7) << 8)
62
63#define MIPI_CAL_BIAS_PAD_VCLAMP(x) (((x) & 0x7) << 16)
64#define MIPI_CAL_BIAS_PAD_VAUXP(x) (((x) & 0x7) << 4)
65#define MIPI_CAL_BIAS_PAD_PDVREG BIT(1)
66
67struct tegra_mipi_priv {
68 struct mipi_ctlr *mipi;
69 struct clk *mipi_cal;
70};
71
72static int tegra_mipi_calibrate(struct udevice *dev, int offset, const void *buf,
73 int size)
74{
75 struct tegra_mipi_priv *priv = dev_get_priv(dev);
76 u32 value;
77
78 value = MIPI_CAL_BIAS_PAD_DRV_DN_REF(0x2) |
79 MIPI_CAL_BIAS_PAD_DRV_UP_REF(0x0);
80 writel(value, &priv->mipi->mipi_cal_bias_pad_cfg1);
81
82 value = readl(&priv->mipi->mipi_cal_bias_pad_cfg2);
83 value &= ~MIPI_CAL_BIAS_PAD_VCLAMP(0x7);
84 value &= ~MIPI_CAL_BIAS_PAD_VAUXP(0x7);
85 writel(value, &priv->mipi->mipi_cal_bias_pad_cfg2);
86
87 value = MIPI_CAL_OVERIDE(0x0) | MIPI_CAL_SEL(0x1) |
88 MIPI_CAL_HSPDOS(0x0) | MIPI_CAL_HSPUOS(0x4) |
89 MIPI_CAL_TERMOS(0x5);
90 writel(value, &priv->mipi->mipi_cal_config_dsia);
91 writel(value, &priv->mipi->mipi_cal_config_dsib);
92
93 /* Deselect PAD C */
94 value = readl(&priv->mipi->mipi_cal_config_dsic);
95 value &= ~(MIPI_CAL_SEL(0x1));
96 writel(value, &priv->mipi->mipi_cal_config_dsic);
97
98 /* Deselect PAD D */
99 value = readl(&priv->mipi->mipi_cal_config_dsid);
100 value &= ~(MIPI_CAL_SEL(0x1));
101 writel(value, &priv->mipi->mipi_cal_config_dsid);
102
103 value = readl(&priv->mipi->mipi_cal_ctrl);
104 value &= ~MIPI_CAL_CTRL_NOISE_FILTER(0xf);
105 value &= ~MIPI_CAL_CTRL_PRESCALE(0x3);
106 value |= MIPI_CAL_CTRL_NOISE_FILTER(0xa) |
107 MIPI_CAL_CTRL_PRESCALE(0x2) |
108 MIPI_CAL_CTRL_CLKEN_OVR;
109 writel(value, &priv->mipi->mipi_cal_ctrl);
110
111 /* clear any pending status bits */
112 value = readl(&priv->mipi->mipi_cal_status);
113 writel(value, &priv->mipi->mipi_cal_status);
114
115 value = readl(&priv->mipi->mipi_cal_ctrl);
116 value |= MIPI_CAL_CTRL_START;
117 writel(value, &priv->mipi->mipi_cal_ctrl);
118
119 /*
120 * Wait for min 72uS to let calibration logic finish calibration
121 * sequence codes before waiting for pads idle state to apply the
122 * results.
123 */
124 udelay(80);
125
126 return readl_poll_sleep_timeout(&priv->mipi->mipi_cal_status, value,
127 !(value & MIPI_CAL_STATUS_ACTIVE) &&
128 (value & MIPI_CAL_STATUS_DONE), 100,
129 250000);
130}
131
132static int tegra_mipi_enable(struct udevice *dev, bool val)
133{
134 struct tegra_mipi_priv *priv = dev_get_priv(dev);
135 u32 value;
136
137 clk_enable(priv->mipi_cal);
138
139 value = readl(&priv->mipi->mipi_cal_bias_pad_cfg0);
140 value &= ~MIPI_CAL_BIAS_PAD_PDVCLAMP;
141 value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF;
142 writel(value, &priv->mipi->mipi_cal_bias_pad_cfg0);
143
144 value = readl(&priv->mipi->mipi_cal_bias_pad_cfg2);
145 value &= ~MIPI_CAL_BIAS_PAD_PDVREG;
146 writel(value, &priv->mipi->mipi_cal_bias_pad_cfg2);
147
148 return 0;
149}
150
151static const struct misc_ops tegra_mipi_ops = {
152 .write = tegra_mipi_calibrate,
153 .set_enabled = tegra_mipi_enable,
154};
155
156static int tegra_mipi_probe(struct udevice *dev)
157{
158 struct tegra_mipi_priv *priv = dev_get_priv(dev);
159
160 priv->mipi = (struct mipi_ctlr *)dev_read_addr_ptr(dev);
161 if (!priv->mipi) {
162 log_debug("%s: no MIPI controller address\n", __func__);
163 return -EINVAL;
164 }
165
166 priv->mipi_cal = devm_clk_get(dev, NULL);
167 if (IS_ERR(priv->mipi_cal)) {
168 log_debug("%s: Could not get MIPI clock: %ld\n",
169 __func__, PTR_ERR(priv->mipi_cal));
170 return PTR_ERR(priv->mipi_cal);
171 }
172
173 return 0;
174}
175
176static const struct udevice_id tegra_mipi_ids[] = {
177 { .compatible = "nvidia,tegra114-mipi" },
178 { }
179};
180
181U_BOOT_DRIVER(tegra_mipi) = {
182 .name = "tegra_mipi",
183 .id = UCLASS_MISC,
184 .ops = &tegra_mipi_ops,
185 .of_match = tegra_mipi_ids,
186 .probe = tegra_mipi_probe,
187 .priv_auto = sizeof(struct tegra_mipi_priv),
188};