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