blob: 731917cef434ca6df6ecba0a34ae8c2292e9c241 [file] [log] [blame]
Neil Armstrongd8d11692020-12-29 14:59:01 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Amlogic AXG MIPI + PCIE analog PHY driver
4 *
5 * Copyright (C) 2019 Remi Pommarel <repk@triplefau.lt>
6 * Copyright (C) 2020 BayLibre, SAS
7 * Author: Neil Armstrong <narmstrong@baylibre.com>
8 */
9
Neil Armstrongd8d11692020-12-29 14:59:01 +010010#include <log.h>
11#include <malloc.h>
12#include <asm/io.h>
13#include <bitfield.h>
14#include <dm.h>
15#include <errno.h>
16#include <generic-phy.h>
17#include <regmap.h>
18#include <syscon.h>
19#include <linux/delay.h>
20#include <power/regulator.h>
21#include <reset.h>
22#include <clk.h>
23#include <phy-mipi-dphy.h>
24
25#include <linux/bitops.h>
26#include <linux/compat.h>
27#include <linux/bitfield.h>
28
29#define HHI_MIPI_CNTL0 0x00
30#define HHI_MIPI_CNTL0_COMMON_BLOCK GENMASK(31, 28)
31#define HHI_MIPI_CNTL0_ENABLE BIT(29)
32#define HHI_MIPI_CNTL0_BANDGAP BIT(26)
33#define HHI_MIPI_CNTL0_DIF_REF_CTL1 GENMASK(25, 16)
34#define HHI_MIPI_CNTL0_DIF_REF_CTL0 GENMASK(15, 0)
35
36#define HHI_MIPI_CNTL1 0x04
37#define HHI_MIPI_CNTL1_CH0_CML_PDR_EN BIT(12)
38#define HHI_MIPI_CNTL1_LP_ABILITY GENMASK(5, 4)
39#define HHI_MIPI_CNTL1_LP_RESISTER BIT(3)
40#define HHI_MIPI_CNTL1_INPUT_SETTING BIT(2)
41#define HHI_MIPI_CNTL1_INPUT_SEL BIT(1)
42#define HHI_MIPI_CNTL1_PRBS7_EN BIT(0)
43
44#define HHI_MIPI_CNTL2 0x08
45#define HHI_MIPI_CNTL2_CH_PU GENMASK(31, 25)
46#define HHI_MIPI_CNTL2_CH_CTL GENMASK(24, 19)
47#define HHI_MIPI_CNTL2_CH0_DIGDR_EN BIT(18)
48#define HHI_MIPI_CNTL2_CH_DIGDR_EN BIT(17)
49#define HHI_MIPI_CNTL2_LPULPS_EN BIT(16)
50#define HHI_MIPI_CNTL2_CH_EN GENMASK(15, 11)
51#define HHI_MIPI_CNTL2_CH0_LP_CTL GENMASK(10, 1)
52
53#define DSI_LANE_0 (1 << 4)
54#define DSI_LANE_1 (1 << 3)
55#define DSI_LANE_CLK (1 << 2)
56#define DSI_LANE_2 (1 << 1)
57#define DSI_LANE_3 (1 << 0)
58#define DSI_LANE_MASK (0x1F)
59
60struct phy_meson_axg_mipi_pcie_analog_priv {
61 struct regmap *regmap;
62 struct phy_configure_opts_mipi_dphy config;
63 bool dsi_configured;
64 bool dsi_enabled;
65 bool powered;
66};
67
68static void phy_bandgap_enable(struct phy_meson_axg_mipi_pcie_analog_priv *priv)
69{
70 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
71 HHI_MIPI_CNTL0_BANDGAP, HHI_MIPI_CNTL0_BANDGAP);
72
73 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
74 HHI_MIPI_CNTL0_ENABLE, HHI_MIPI_CNTL0_ENABLE);
75}
76
77static void phy_bandgap_disable(struct phy_meson_axg_mipi_pcie_analog_priv *priv)
78{
79 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
80 HHI_MIPI_CNTL0_BANDGAP, 0);
81 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
82 HHI_MIPI_CNTL0_ENABLE, 0);
83}
84
85static void phy_dsi_analog_enable(struct phy_meson_axg_mipi_pcie_analog_priv *priv)
86{
87 u32 reg;
88
89 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
90 HHI_MIPI_CNTL0_DIF_REF_CTL1,
91 FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL1, 0x1b8));
92 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
93 BIT(31), BIT(31));
94 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
95 HHI_MIPI_CNTL0_DIF_REF_CTL0,
96 FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL0, 0x8));
97
98 regmap_write(priv->regmap, HHI_MIPI_CNTL1, 0x001e);
99
100 regmap_write(priv->regmap, HHI_MIPI_CNTL2,
101 (0x26e0 << 16) | (0x459 << 0));
102
103 reg = DSI_LANE_CLK;
104 switch (priv->config.lanes) {
105 case 4:
106 reg |= DSI_LANE_3;
107 fallthrough;
108 case 3:
109 reg |= DSI_LANE_2;
110 fallthrough;
111 case 2:
112 reg |= DSI_LANE_1;
113 fallthrough;
114 case 1:
115 reg |= DSI_LANE_0;
116 break;
117 default:
118 reg = 0;
119 }
120
121 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL2,
122 HHI_MIPI_CNTL2_CH_EN,
123 FIELD_PREP(HHI_MIPI_CNTL2_CH_EN, reg));
124
125 priv->dsi_enabled = true;
126}
127
128static void phy_dsi_analog_disable(struct phy_meson_axg_mipi_pcie_analog_priv *priv)
129{
130 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
131 HHI_MIPI_CNTL0_DIF_REF_CTL1,
132 FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL1, 0));
133 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0, BIT(31), 0);
134 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
135 HHI_MIPI_CNTL0_DIF_REF_CTL1, 0);
136
137 regmap_write(priv->regmap, HHI_MIPI_CNTL1, 0x6);
138
139 regmap_write(priv->regmap, HHI_MIPI_CNTL2, 0x00200000);
140
141 priv->dsi_enabled = false;
142}
143
144static int phy_meson_axg_mipi_pcie_analog_configure(struct phy *phy, void *params)
145{
146 struct udevice *dev = phy->dev;
147 struct phy_meson_axg_mipi_pcie_analog_priv *priv = dev_get_priv(dev);
148 struct phy_configure_opts_mipi_dphy *config = params;
149 int ret;
150
151 ret = phy_mipi_dphy_config_validate(config);
152 if (ret)
153 return ret;
154
155 memcpy(&priv->config, config, sizeof(priv->config));
156
157 priv->dsi_configured = true;
158
159 /* If PHY was already powered on, setup the DSI analog part */
160 if (priv->powered) {
161 /* If reconfiguring, disable & reconfigure */
162 if (priv->dsi_enabled)
163 phy_dsi_analog_disable(priv);
164
165 udelay(100);
166
167 phy_dsi_analog_enable(priv);
168 }
169
170 return 0;
171}
172
173static int phy_meson_axg_mipi_pcie_analog_power_on(struct phy *phy)
174{
175 struct udevice *dev = phy->dev;
176 struct phy_meson_axg_mipi_pcie_analog_priv *priv = dev_get_priv(dev);
177
178 phy_bandgap_enable(priv);
179
180 if (priv->dsi_configured)
181 phy_dsi_analog_enable(priv);
182
183 priv->powered = true;
184
185 return 0;
186}
187
188static int phy_meson_axg_mipi_pcie_analog_power_off(struct phy *phy)
189{
190 struct udevice *dev = phy->dev;
191 struct phy_meson_axg_mipi_pcie_analog_priv *priv = dev_get_priv(dev);
192
193 phy_bandgap_disable(priv);
194
195 if (priv->dsi_enabled)
196 phy_dsi_analog_disable(priv);
197
198 priv->powered = false;
199
200 return 0;
201}
202
203struct phy_ops meson_axg_mipi_pcie_analog_ops = {
204 .power_on = phy_meson_axg_mipi_pcie_analog_power_on,
205 .power_off = phy_meson_axg_mipi_pcie_analog_power_off,
206 .configure = phy_meson_axg_mipi_pcie_analog_configure,
207};
208
209int meson_axg_mipi_pcie_analog_probe(struct udevice *dev)
210{
211 struct phy_meson_axg_mipi_pcie_analog_priv *priv = dev_get_priv(dev);
212
Alper Nebi Yasak0a887542021-05-14 23:54:20 +0300213 priv->regmap = syscon_node_to_regmap(dev_ofnode(dev_get_parent(dev)));
Neil Armstrongd8d11692020-12-29 14:59:01 +0100214 if (IS_ERR(priv->regmap))
215 return PTR_ERR(priv->regmap);
216
217 return 0;
218}
219
220static const struct udevice_id meson_axg_mipi_pcie_analog_ids[] = {
221 { .compatible = "amlogic,axg-mipi-pcie-analog-phy" },
222 { }
223};
224
225U_BOOT_DRIVER(meson_axg_mipi_pcie_analog) = {
226 .name = "meson_axg_mipi_pcie_analog",
227 .id = UCLASS_PHY,
228 .of_match = meson_axg_mipi_pcie_analog_ids,
229 .probe = meson_axg_mipi_pcie_analog_probe,
230 .ops = &meson_axg_mipi_pcie_analog_ops,
Alper Nebi Yasakf37193e2021-05-14 23:54:19 +0300231 .priv_auto = sizeof(struct phy_meson_axg_mipi_pcie_analog_priv),
Neil Armstrongd8d11692020-12-29 14:59:01 +0100232};