blob: 9f80a3fda4b1ebb2a509df7c4ed54c6e06240425 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Stefan Roese648391c2016-08-30 16:48:20 +02002/*
3 * Copyright (C) 2015-2016 Marvell International Ltd.
Stefan Roese648391c2016-08-30 16:48:20 +02004 */
5
6#include <common.h>
7#include <fdtdec.h>
Simon Glass0f2af882020-05-10 11:40:05 -06008#include <log.h>
Simon Glass3ba929a2020-10-30 21:38:53 -06009#include <asm/global_data.h>
Stefan Roese648391c2016-08-30 16:48:20 +020010#include <asm/io.h>
Grzegorz Jaszczyk7928a8e2020-10-18 17:11:11 +030011#include <asm/ptrace.h>
Stefan Roese648391c2016-08-30 16:48:20 +020012#include <asm/arch/cpu.h>
13#include <asm/arch/soc.h>
Simon Glassdbd79542020-05-10 11:40:11 -060014#include <linux/delay.h>
Stefan Roese648391c2016-08-30 16:48:20 +020015
Marek BehĂșn19ce44c2018-08-17 12:58:51 +020016#include "comphy_core.h"
Stefan Roese648391c2016-08-30 16:48:20 +020017#include "comphy_hpipe.h"
18#include "sata.h"
19#include "utmi_phy.h"
20
21DECLARE_GLOBAL_DATA_PTR;
22
23#define SD_ADDR(base, lane) (base + 0x1000 * lane)
24#define HPIPE_ADDR(base, lane) (SD_ADDR(base, lane) + 0x800)
25#define COMPHY_ADDR(base, lane) (base + 0x28 * lane)
26
Grzegorz Jaszczyk7928a8e2020-10-18 17:11:11 +030027/* Firmware related definitions used for SMC calls */
28#define MV_SIP_COMPHY_POWER_ON 0x82000001
29#define MV_SIP_COMPHY_POWER_OFF 0x82000002
30#define MV_SIP_COMPHY_PLL_LOCK 0x82000003
31
Igal Liberman67d1a3f2020-10-18 17:11:13 +030032/* Used to distinguish between different possible callers (U-boot/Linux) */
33#define COMPHY_CALLER_UBOOT (0x1 << 21)
34
Grzegorz Jaszczyk7928a8e2020-10-18 17:11:11 +030035#define COMPHY_FW_MODE_FORMAT(mode) ((mode) << 12)
36#define COMPHY_FW_FORMAT(mode, idx, speeds) \
37 (((mode) << 12) | ((idx) << 8) | ((speeds) << 2))
Grzegorz Jaszczykc42b5a32020-10-18 17:11:12 +030038
39#define COMPHY_FW_PCIE_FORMAT(pcie_width, clk_src, mode, speeds) \
Igal Liberman67d1a3f2020-10-18 17:11:13 +030040 (COMPHY_CALLER_UBOOT | ((pcie_width) << 18) | \
41 ((clk_src) << 17) | COMPHY_FW_FORMAT(mode, 0, speeds))
Grzegorz Jaszczykc42b5a32020-10-18 17:11:12 +030042
Grzegorz Jaszczyk7928a8e2020-10-18 17:11:11 +030043#define COMPHY_SATA_MODE 0x1
44#define COMPHY_SGMII_MODE 0x2 /* SGMII 1G */
45#define COMPHY_HS_SGMII_MODE 0x3 /* SGMII 2.5G */
46#define COMPHY_USB3H_MODE 0x4
47#define COMPHY_USB3D_MODE 0x5
48#define COMPHY_PCIE_MODE 0x6
49#define COMPHY_RXAUI_MODE 0x7
50#define COMPHY_XFI_MODE 0x8
51#define COMPHY_SFI_MODE 0x9
52#define COMPHY_USB3_MODE 0xa
53#define COMPHY_AP_MODE 0xb
54
55/* Comphy unit index macro */
56#define COMPHY_UNIT_ID0 0
57#define COMPHY_UNIT_ID1 1
58#define COMPHY_UNIT_ID2 2
59#define COMPHY_UNIT_ID3 3
60
Stefan Roese648391c2016-08-30 16:48:20 +020061struct utmi_phy_data {
62 void __iomem *utmi_base_addr;
63 void __iomem *usb_cfg_addr;
64 void __iomem *utmi_cfg_addr;
65 u32 utmi_phy_port;
66};
67
68/*
69 * For CP-110 we have 2 Selector registers "PHY Selectors",
70 * and "PIPE Selectors".
71 * PIPE selector include USB and PCIe options.
72 * PHY selector include the Ethernet and SATA options, every Ethernet
73 * option has different options, for example: serdes lane2 had option
Stefan Roeseb8b7c672017-04-24 18:45:29 +030074 * Eth_port_0 that include (SGMII0, RXAUI0, SFI)
Stefan Roese648391c2016-08-30 16:48:20 +020075 */
76struct comphy_mux_data cp110_comphy_phy_mux_data[] = {
Igal Libermanffd5d2f2017-04-26 15:40:00 +030077 /* Lane 0 */
78 {4, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_SGMII1, 0x1},
79 {COMPHY_TYPE_SATA1, 0x4} } },
80 /* Lane 1 */
81 {4, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_SGMII2, 0x1},
82 {COMPHY_TYPE_SATA0, 0x4} } },
83 /* Lane 2 */
84 {6, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_SGMII0, 0x1},
85 {COMPHY_TYPE_RXAUI0, 0x1}, {COMPHY_TYPE_SFI, 0x1},
86 {COMPHY_TYPE_SATA0, 0x4} } },
87 /* Lane 3 */
88 {8, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_RXAUI1, 0x1},
89 {COMPHY_TYPE_SGMII1, 0x2}, {COMPHY_TYPE_SATA1, 0x4} } },
90 /* Lane 4 */
91 {7, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_SGMII0, 0x2},
92 {COMPHY_TYPE_RXAUI0, 0x2}, {COMPHY_TYPE_SFI, 0x2},
93 {COMPHY_TYPE_SGMII1, 0x1} } },
94 /* Lane 5 */
95 {6, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_SGMII2, 0x1},
96 {COMPHY_TYPE_RXAUI1, 0x2}, {COMPHY_TYPE_SATA1, 0x4} } },
Stefan Roese648391c2016-08-30 16:48:20 +020097};
98
99struct comphy_mux_data cp110_comphy_pipe_mux_data[] = {
Igal Libermanffd5d2f2017-04-26 15:40:00 +0300100 /* Lane 0 */
101 {2, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_PEX0, 0x4} } },
102 /* Lane 1 */
103 {4, {{COMPHY_TYPE_UNCONNECTED, 0x0},
104 {COMPHY_TYPE_USB3_HOST0, 0x1}, {COMPHY_TYPE_USB3_DEVICE, 0x2},
105 {COMPHY_TYPE_PEX0, 0x4} } },
106 /* Lane 2 */
107 {3, {{COMPHY_TYPE_UNCONNECTED, 0x0},
108 {COMPHY_TYPE_USB3_HOST0, 0x1}, {COMPHY_TYPE_PEX0, 0x4} } },
109 /* Lane 3 */
110 {3, {{COMPHY_TYPE_UNCONNECTED, 0x0},
111 {COMPHY_TYPE_USB3_HOST1, 0x1}, {COMPHY_TYPE_PEX0, 0x4} } },
112 /* Lane 4 */
113 {4, {{COMPHY_TYPE_UNCONNECTED, 0x0},
114 {COMPHY_TYPE_USB3_HOST1, 0x1},
115 {COMPHY_TYPE_USB3_DEVICE, 0x2}, {COMPHY_TYPE_PEX1, 0x4} } },
116 /* Lane 5 */
117 {2, {{COMPHY_TYPE_UNCONNECTED, 0x0}, {COMPHY_TYPE_PEX2, 0x4} } },
Stefan Roese648391c2016-08-30 16:48:20 +0200118};
119
120static u32 polling_with_timeout(void __iomem *addr, u32 val,
121 u32 mask, unsigned long usec_timout)
122{
123 u32 data;
124
125 do {
126 udelay(1);
127 data = readl(addr) & mask;
128 } while (data != val && --usec_timout > 0);
129
130 if (usec_timout == 0)
131 return data;
132
133 return 0;
134}
135
Igal Liberman6795a662021-03-23 11:57:57 +0100136/* This function performs RX training for single FFE value.
137 * The result of the RX training is located in:
138 * Saved DFE values Register[10:15].
139 *
140 * The result is returned to the caller using *result
141 *
142 * Return '1' on succsess.
143 * Return '0' on failure.
144 */
145static int comphy_cp110_test_single_ffe(
146 struct chip_serdes_phy_config *ptr_chip_cfg,
147 u32 lane, u32 ffe, u32 *result)
148{
149 u32 mask, data, timeout;
150 void __iomem *hpipe_base_addr = ptr_chip_cfg->hpipe3_base_addr;
151 void __iomem *hpipe_addr = HPIPE_ADDR(hpipe_base_addr, lane);
152 void __iomem *sd_ip_addr = SD_ADDR(hpipe_base_addr, lane);
153
154 /* Configure PRBS counters */
155 mask = HPIPE_PHY_TEST_PATTERN_SEL_MASK;
156 data = 0xe << HPIPE_PHY_TEST_PATTERN_SEL_OFFSET;
157 reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
158
159 mask = HPIPE_PHY_TEST_DATA_MASK;
160 data = 0x64 << HPIPE_PHY_TEST_DATA_OFFSET;
161 reg_set(hpipe_addr + HPIPE_PHY_TEST_DATA_REG, data, mask);
162
163 mask = HPIPE_PHY_TEST_EN_MASK;
164 data = 0x1 << HPIPE_PHY_TEST_EN_OFFSET;
165 reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
166
167 mdelay(50);
168
169 /* Set the FFE value */
170 mask = HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK;
171 data = ffe << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET;
172 reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
173
174 /* Start RX training */
175 mask = SD_EXTERNAL_STATUS_START_RX_TRAINING_MASK;
176 data = 1 << SD_EXTERNAL_STATUS_START_RX_TRAINING_OFFSET;
177 reg_set(sd_ip_addr + SD_EXTERNAL_STATUS_REG, data, mask);
178
179 /* Check the result of RX training */
180 timeout = RX_TRAINING_TIMEOUT;
181 while (timeout) {
182 data = readl(sd_ip_addr + SD_EXTERNAL_STATUS1_REG);
183 if (data & SD_EXTERNAL_STATUS1_REG_RX_TRAIN_COMP_MASK)
184 break;
185 mdelay(1);
186 timeout--;
187 }
188
189 if (timeout == 0)
190 return 0;
191
192 if (data & SD_EXTERNAL_STATUS1_REG_RX_TRAIN_FAILED_MASK)
193 return 0;
194
195 /* Stop RX training */
196 mask = SD_EXTERNAL_STATUS_START_RX_TRAINING_MASK;
197 data = 0 << SD_EXTERNAL_STATUS_START_RX_TRAINING_OFFSET;
198 reg_set(sd_ip_addr + SD_EXTERNAL_STATUS_REG, data, mask);
199
200 /* Read the result */
201 data = readl(hpipe_addr + HPIPE_SAVED_DFE_VALUES_REG);
202 data &= HPIPE_SAVED_DFE_VALUES_SAV_F0D_MASK;
203 data >>= HPIPE_SAVED_DFE_VALUES_SAV_F0D_OFFSET;
204 *result = data;
205
206 printf("FFE = %d, result = 0x%x\n", ffe, *result);
207
208 /* Clear the PRBS counters */
209 mask = HPIPE_PHY_TEST_RESET_MASK;
210 data = 0x1 << HPIPE_PHY_TEST_RESET_OFFSET;
211 mask |= HPIPE_PHY_TEST_EN_MASK;
212 data |= 0x0 << HPIPE_PHY_TEST_EN_OFFSET;
213 reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
214
215 mask = HPIPE_PHY_TEST_RESET_MASK;
216 data = 0x0 << HPIPE_PHY_TEST_RESET_OFFSET;
217 reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
218
219 return 1;
220}
221
222/* This function performs RX training for all FFE possible values.
223 * We get the result for each FFE and eventually the best FFE will
224 * be used and set to the HW.
225 *
226 * Return '1' on succsess.
227 * Return '0' on failure.
228 */
229int comphy_cp110_sfi_rx_training(struct chip_serdes_phy_config *ptr_chip_cfg,
230 u32 lane)
231{
232 u32 mask, data, i, rx_train_result;
233 u32 max_rx_train = 0, max_rx_train_index = 0;
234 void __iomem *hpipe_base_addr = ptr_chip_cfg->hpipe3_base_addr;
235 void __iomem *hpipe_addr = HPIPE_ADDR(hpipe_base_addr, lane);
236 int ret;
237
238 debug_enter();
239
240 if (ptr_chip_cfg->comphy_map_data[lane].type != COMPHY_TYPE_SFI) {
241 pr_err("Comphy %d isn't configured to SFI\n", lane);
242 return 0;
243 }
244
245 /* Configure SQ threshold and CDR lock */
246 mask = HPIPE_SQUELCH_THRESH_IN_MASK;
247 data = 0xc << HPIPE_SQUELCH_THRESH_IN_OFFSET;
248 reg_set(hpipe_addr + HPIPE_SQUELCH_FFE_SETTING_REG, data, mask);
249
250 mask = HPIPE_SQ_DEGLITCH_WIDTH_P_MASK;
251 data = 0xf << HPIPE_SQ_DEGLITCH_WIDTH_P_OFFSET;
252 mask |= HPIPE_SQ_DEGLITCH_WIDTH_N_MASK;
253 data |= 0xf << HPIPE_SQ_DEGLITCH_WIDTH_N_OFFSET;
254 mask |= HPIPE_SQ_DEGLITCH_EN_MASK;
255 data |= 0x1 << HPIPE_SQ_DEGLITCH_EN_OFFSET;
256 reg_set(hpipe_addr + HPIPE_SQ_GLITCH_FILTER_CTRL, data, mask);
257
258 mask = HPIPE_CDR_LOCK_DET_EN_MASK;
259 data = 0x1 << HPIPE_CDR_LOCK_DET_EN_OFFSET;
260 reg_set(hpipe_addr + HPIPE_LOOPBACK_REG, data, mask);
261
262 udelay(100);
263
264 /* Determine if we have a cable attached to this comphy, if not,
265 * we can't perform RX training.
266 */
267 data = readl(hpipe_addr + HPIPE_SQUELCH_FFE_SETTING_REG);
268 if (data & HPIPE_SQUELCH_DETECTED_MASK) {
269 pr_err("Squelsh is not detected, can't perform RX training\n");
270 return 0;
271 }
272
273 data = readl(hpipe_addr + HPIPE_LOOPBACK_REG);
274 if (!(data & HPIPE_CDR_LOCK_MASK)) {
275 pr_err("CDR is not locked, can't perform RX training\n");
276 return 0;
277 }
278
279 /* Do preparations for RX training */
280 mask = HPIPE_DFE_RES_FORCE_MASK;
281 data = 0x0 << HPIPE_DFE_RES_FORCE_OFFSET;
282 reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
283
284 mask = HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK;
285 data = 0xf << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET;
286 mask |= HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
287 data |= 1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
288 reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
289
290 /* Performs RX training for all possible FFE (Feed Forward
291 * Equalization, possible values are 0-7).
292 * We update the best value reached and the FFE which gave this value.
293 */
294 for (i = 0; i < MAX_NUM_OF_FFE; i++) {
295 rx_train_result = 0;
296 ret = comphy_cp110_test_single_ffe(ptr_chip_cfg, lane,
297 i, &rx_train_result);
298
299 if (ret && (rx_train_result > max_rx_train)) {
300 max_rx_train = rx_train_result;
301 max_rx_train_index = i;
302 }
303 }
304
305 /* If we were able to determine which FFE gives the best value,
306 * now we need to set it and run RX training again (only for this
307 * FFE).
308 */
309 if (max_rx_train) {
310 ret = comphy_cp110_test_single_ffe(ptr_chip_cfg, lane,
311 max_rx_train_index,
312 &rx_train_result);
313 if (ret == 1)
314 printf("RX Training passed(FFE = %d, result = 0x%x)\n",
315 max_rx_train_index, rx_train_result);
316 } else {
317 pr_err("RX training failed\n");
318 ret = 0;
319 }
320
321 debug_exit();
322
323 return ret;
324}
325
Stefan Roese648391c2016-08-30 16:48:20 +0200326static int comphy_usb3_power_up(u32 lane, void __iomem *hpipe_base,
327 void __iomem *comphy_base)
328{
329 u32 mask, data, ret = 1;
330 void __iomem *hpipe_addr = HPIPE_ADDR(hpipe_base, lane);
331 void __iomem *comphy_addr = COMPHY_ADDR(comphy_base, lane);
332 void __iomem *addr;
333
334 debug_enter();
335 debug("stage: RFU configurations - hard reset comphy\n");
336 /* RFU configurations - hard reset comphy */
337 mask = COMMON_PHY_CFG1_PWR_UP_MASK;
338 data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
339 mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
340 data |= 0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
341 mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
342 data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
343 mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
344 data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
345 mask |= COMMON_PHY_PHY_MODE_MASK;
346 data |= 0x1 << COMMON_PHY_PHY_MODE_OFFSET;
347 reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
348
349 /* release from hard reset */
350 mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
351 data = 0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
352 mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
353 data |= 0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
354 reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
355
356 /* Wait 1ms - until band gap and ref clock ready */
357 mdelay(1);
358
359 /* Start comphy Configuration */
360 debug("stage: Comphy configuration\n");
361 /* Set PIPE soft reset */
362 mask = HPIPE_RST_CLK_CTRL_PIPE_RST_MASK;
363 data = 0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET;
364 /* Set PHY datapath width mode for V0 */
365 mask |= HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK;
366 data |= 0x0 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET;
367 /* Set Data bus width USB mode for V0 */
368 mask |= HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK;
369 data |= 0x0 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET;
370 /* Set CORE_CLK output frequency for 250Mhz */
371 mask |= HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK;
372 data |= 0x0 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET;
373 reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG, data, mask);
374 /* Set PLL ready delay for 0x2 */
375 reg_set(hpipe_addr + HPIPE_CLK_SRC_LO_REG,
376 0x2 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET,
377 HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK);
378 /* Set reference clock to come from group 1 - 25Mhz */
379 reg_set(hpipe_addr + HPIPE_MISC_REG,
380 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET,
381 HPIPE_MISC_REFCLK_SEL_MASK);
382 /* Set reference frequcency select - 0x2 */
383 mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
384 data = 0x2 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
385 /* Set PHY mode to USB - 0x5 */
386 mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
387 data |= 0x5 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
388 reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask);
389 /* Set the amount of time spent in the LoZ state - set for 0x7 */
390 reg_set(hpipe_addr + HPIPE_GLOBAL_PM_CTRL,
391 0x7 << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET,
392 HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK);
393 /* Set max PHY generation setting - 5Gbps */
394 reg_set(hpipe_addr + HPIPE_INTERFACE_REG,
395 0x1 << HPIPE_INTERFACE_GEN_MAX_OFFSET,
396 HPIPE_INTERFACE_GEN_MAX_MASK);
397 /* Set select data width 20Bit (SEL_BITS[2:0]) */
398 reg_set(hpipe_addr + HPIPE_LOOPBACK_REG,
399 0x1 << HPIPE_LOOPBACK_SEL_OFFSET,
400 HPIPE_LOOPBACK_SEL_MASK);
401 /* select de-emphasize 3.5db */
402 reg_set(hpipe_addr + HPIPE_LANE_CONFIG0_REG,
403 0x1 << HPIPE_LANE_CONFIG0_TXDEEMPH0_OFFSET,
404 HPIPE_LANE_CONFIG0_TXDEEMPH0_MASK);
405 /* override tx margining from the MAC */
406 reg_set(hpipe_addr + HPIPE_TST_MODE_CTRL_REG,
407 0x1 << HPIPE_TST_MODE_CTRL_MODE_MARGIN_OFFSET,
408 HPIPE_TST_MODE_CTRL_MODE_MARGIN_MASK);
409
410 /* Start analog paramters from ETP(HW) */
411 debug("stage: Analog paramters from ETP(HW)\n");
412 /* Set Pin DFE_PAT_DIS -> Bit[1]: PIN_DFE_PAT_DIS = 0x0 */
413 mask = HPIPE_LANE_CFG4_DFE_CTRL_MASK;
414 data = 0x1 << HPIPE_LANE_CFG4_DFE_CTRL_OFFSET;
415 /* Set Override PHY DFE control pins for 0x1 */
416 mask |= HPIPE_LANE_CFG4_DFE_OVER_MASK;
417 data |= 0x1 << HPIPE_LANE_CFG4_DFE_OVER_OFFSET;
418 /* Set Spread Spectrum Clock Enable fot 0x1 */
419 mask |= HPIPE_LANE_CFG4_SSC_CTRL_MASK;
420 data |= 0x1 << HPIPE_LANE_CFG4_SSC_CTRL_OFFSET;
421 reg_set(hpipe_addr + HPIPE_LANE_CFG4_REG, data, mask);
422 /* End of analog parameters */
423
424 debug("stage: Comphy power up\n");
425 /* Release from PIPE soft reset */
426 reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG,
427 0x0 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET,
428 HPIPE_RST_CLK_CTRL_PIPE_RST_MASK);
429
430 /* wait 15ms - for comphy calibration done */
431 debug("stage: Check PLL\n");
432 /* Read lane status */
433 addr = hpipe_addr + HPIPE_LANE_STATUS1_REG;
434 data = HPIPE_LANE_STATUS1_PCLK_EN_MASK;
435 mask = data;
436 data = polling_with_timeout(addr, data, mask, 15000);
437 if (data != 0) {
438 debug("Read from reg = %p - value = 0x%x\n",
439 hpipe_addr + HPIPE_LANE_STATUS1_REG, data);
Masahiro Yamada81e10422017-09-16 14:10:41 +0900440 pr_err("HPIPE_LANE_STATUS1_PCLK_EN_MASK is 0\n");
Stefan Roese648391c2016-08-30 16:48:20 +0200441 ret = 0;
442 }
443
444 debug_exit();
445 return ret;
446}
447
Grzegorz Jaszczyk7928a8e2020-10-18 17:11:11 +0300448static int comphy_smc(u32 function_id, void __iomem *comphy_base_addr,
449 u32 lane, u32 mode)
450{
451 struct pt_regs pregs = {0};
452
453 pregs.regs[0] = function_id;
454 pregs.regs[1] = (unsigned long)comphy_base_addr;
455 pregs.regs[2] = lane;
456 pregs.regs[3] = mode;
457
458 smc_call(&pregs);
459
460 /*
461 * TODO: Firmware return 0 on success, temporary map it to u-boot
462 * convention, but after all comphy will be reworked the convention in
463 * u-boot should be change and this conversion removed
464 */
465 return pregs.regs[0] ? 0 : 1;
466}
467
Stefan Roese648391c2016-08-30 16:48:20 +0200468static int comphy_sata_power_up(u32 lane, void __iomem *hpipe_base,
Grzegorz Jaszczyk7928a8e2020-10-18 17:11:11 +0300469 void __iomem *comphy_base_addr, int cp_index,
470 u32 type)
Stefan Roese648391c2016-08-30 16:48:20 +0200471{
472 u32 mask, data, i, ret = 1;
Stefan Roese648391c2016-08-30 16:48:20 +0200473 void __iomem *sata_base = NULL;
474 int sata_node = -1; /* Set to -1 in order to read the first sata node */
475
476 debug_enter();
477
478 /*
479 * Assumption - each CP has only one SATA controller
480 * Calling fdt_node_offset_by_compatible first time (with sata_node = -1
481 * will return the first node always.
482 * In order to parse each CPs SATA node, fdt_node_offset_by_compatible
483 * must be called again (according to the CP id)
484 */
Igal Libermanc8855ce2017-04-24 18:45:32 +0300485 for (i = 0; i < (cp_index + 1); i++)
Stefan Roese648391c2016-08-30 16:48:20 +0200486 sata_node = fdt_node_offset_by_compatible(
487 gd->fdt_blob, sata_node, "marvell,armada-8k-ahci");
488
489 if (sata_node == 0) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900490 pr_err("SATA node not found in FDT\n");
Stefan Roese648391c2016-08-30 16:48:20 +0200491 return 0;
492 }
493
494 sata_base = (void __iomem *)fdtdec_get_addr_size_auto_noparent(
495 gd->fdt_blob, sata_node, "reg", 0, NULL, true);
496 if (sata_base == NULL) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900497 pr_err("SATA address not found in FDT\n");
Stefan Roese648391c2016-08-30 16:48:20 +0200498 return 0;
499 }
500
501 debug("SATA address found in FDT %p\n", sata_base);
502
503 debug("stage: MAC configuration - power down comphy\n");
504 /*
505 * MAC configuration powe down comphy use indirect address for
506 * vendor spesific SATA control register
507 */
508 reg_set(sata_base + SATA3_VENDOR_ADDRESS,
509 SATA_CONTROL_REG << SATA3_VENDOR_ADDR_OFSSET,
510 SATA3_VENDOR_ADDR_MASK);
511 /* SATA 0 power down */
512 mask = SATA3_CTRL_SATA0_PD_MASK;
513 data = 0x1 << SATA3_CTRL_SATA0_PD_OFFSET;
514 /* SATA 1 power down */
515 mask |= SATA3_CTRL_SATA1_PD_MASK;
516 data |= 0x1 << SATA3_CTRL_SATA1_PD_OFFSET;
517 /* SATA SSU disable */
518 mask |= SATA3_CTRL_SATA1_ENABLE_MASK;
519 data |= 0x0 << SATA3_CTRL_SATA1_ENABLE_OFFSET;
520 /* SATA port 1 disable */
521 mask |= SATA3_CTRL_SATA_SSU_MASK;
522 data |= 0x0 << SATA3_CTRL_SATA_SSU_OFFSET;
523 reg_set(sata_base + SATA3_VENDOR_DATA, data, mask);
524
Grzegorz Jaszczyk7928a8e2020-10-18 17:11:11 +0300525 ret = comphy_smc(MV_SIP_COMPHY_POWER_ON, comphy_base_addr, lane, type);
Stefan Roese648391c2016-08-30 16:48:20 +0200526
Stefan Roese648391c2016-08-30 16:48:20 +0200527 /*
528 * MAC configuration power up comphy - power up PLL/TX/RX
529 * use indirect address for vendor spesific SATA control register
530 */
531 reg_set(sata_base + SATA3_VENDOR_ADDRESS,
532 SATA_CONTROL_REG << SATA3_VENDOR_ADDR_OFSSET,
533 SATA3_VENDOR_ADDR_MASK);
534 /* SATA 0 power up */
535 mask = SATA3_CTRL_SATA0_PD_MASK;
536 data = 0x0 << SATA3_CTRL_SATA0_PD_OFFSET;
537 /* SATA 1 power up */
538 mask |= SATA3_CTRL_SATA1_PD_MASK;
539 data |= 0x0 << SATA3_CTRL_SATA1_PD_OFFSET;
540 /* SATA SSU enable */
541 mask |= SATA3_CTRL_SATA1_ENABLE_MASK;
542 data |= 0x1 << SATA3_CTRL_SATA1_ENABLE_OFFSET;
543 /* SATA port 1 enable */
544 mask |= SATA3_CTRL_SATA_SSU_MASK;
545 data |= 0x1 << SATA3_CTRL_SATA_SSU_OFFSET;
546 reg_set(sata_base + SATA3_VENDOR_DATA, data, mask);
547
548 /* MBUS request size and interface select register */
549 reg_set(sata_base + SATA3_VENDOR_ADDRESS,
550 SATA_MBUS_SIZE_SELECT_REG << SATA3_VENDOR_ADDR_OFSSET,
551 SATA3_VENDOR_ADDR_MASK);
552 /* Mbus regret enable */
553 reg_set(sata_base + SATA3_VENDOR_DATA,
554 0x1 << SATA_MBUS_REGRET_EN_OFFSET, SATA_MBUS_REGRET_EN_MASK);
555
Grzegorz Jaszczyk7928a8e2020-10-18 17:11:11 +0300556 ret = comphy_smc(MV_SIP_COMPHY_PLL_LOCK, comphy_base_addr, lane, type);
Stefan Roese648391c2016-08-30 16:48:20 +0200557
558 debug_exit();
559 return ret;
560}
561
Stefan Roese648391c2016-08-30 16:48:20 +0200562static void comphy_utmi_power_down(u32 utmi_index, void __iomem *utmi_base_addr,
563 void __iomem *usb_cfg_addr,
564 void __iomem *utmi_cfg_addr,
565 u32 utmi_phy_port)
566{
567 u32 mask, data;
568
569 debug_enter();
570 debug("stage: UTMI %d - Power down transceiver (power down Phy), Power down PLL, and SuspendDM\n",
571 utmi_index);
572 /* Power down UTMI PHY */
573 reg_set(utmi_cfg_addr, 0x0 << UTMI_PHY_CFG_PU_OFFSET,
574 UTMI_PHY_CFG_PU_MASK);
575
576 /*
577 * If UTMI connected to USB Device, configure mux prior to PHY init
578 * (Device can be connected to UTMI0 or to UTMI1)
579 */
Stefan Roeseb781f572017-04-24 18:45:23 +0300580 if (utmi_phy_port == UTMI_PHY_TO_USB3_DEVICE0) {
Stefan Roese648391c2016-08-30 16:48:20 +0200581 debug("stage: UTMI %d - Enable Device mode and configure UTMI mux\n",
582 utmi_index);
583 /* USB3 Device UTMI enable */
584 mask = UTMI_USB_CFG_DEVICE_EN_MASK;
585 data = 0x1 << UTMI_USB_CFG_DEVICE_EN_OFFSET;
586 /* USB3 Device UTMI MUX */
587 mask |= UTMI_USB_CFG_DEVICE_MUX_MASK;
588 data |= utmi_index << UTMI_USB_CFG_DEVICE_MUX_OFFSET;
589 reg_set(usb_cfg_addr, data, mask);
590 }
591
592 /* Set Test suspendm mode */
593 mask = UTMI_CTRL_STATUS0_SUSPENDM_MASK;
594 data = 0x1 << UTMI_CTRL_STATUS0_SUSPENDM_OFFSET;
595 /* Enable Test UTMI select */
596 mask |= UTMI_CTRL_STATUS0_TEST_SEL_MASK;
597 data |= 0x1 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET;
598 reg_set(utmi_base_addr + UTMI_CTRL_STATUS0_REG, data, mask);
599
600 /* Wait for UTMI power down */
601 mdelay(1);
602
603 debug_exit();
604 return;
605}
606
607static void comphy_utmi_phy_config(u32 utmi_index, void __iomem *utmi_base_addr,
608 void __iomem *usb_cfg_addr,
609 void __iomem *utmi_cfg_addr,
610 u32 utmi_phy_port)
611{
612 u32 mask, data;
613
614 debug_exit();
615 debug("stage: Configure UTMI PHY %d registers\n", utmi_index);
616 /* Reference Clock Divider Select */
617 mask = UTMI_PLL_CTRL_REFDIV_MASK;
618 data = 0x5 << UTMI_PLL_CTRL_REFDIV_OFFSET;
619 /* Feedback Clock Divider Select - 90 for 25Mhz*/
620 mask |= UTMI_PLL_CTRL_FBDIV_MASK;
621 data |= 0x60 << UTMI_PLL_CTRL_FBDIV_OFFSET;
622 /* Select LPFR - 0x0 for 25Mhz/5=5Mhz*/
623 mask |= UTMI_PLL_CTRL_SEL_LPFR_MASK;
624 data |= 0x0 << UTMI_PLL_CTRL_SEL_LPFR_OFFSET;
625 reg_set(utmi_base_addr + UTMI_PLL_CTRL_REG, data, mask);
626
627 /* Impedance Calibration Threshold Setting */
628 reg_set(utmi_base_addr + UTMI_CALIB_CTRL_REG,
Igal Liberman32af2162017-04-30 20:16:55 +0300629 0x7 << UTMI_CALIB_CTRL_IMPCAL_VTH_OFFSET,
Stefan Roese648391c2016-08-30 16:48:20 +0200630 UTMI_CALIB_CTRL_IMPCAL_VTH_MASK);
631
632 /* Set LS TX driver strength coarse control */
Igal Liberman32af2162017-04-30 20:16:55 +0300633 mask = UTMI_TX_CH_CTRL_AMP_MASK;
634 data = 0x4 << UTMI_TX_CH_CTRL_AMP_OFFSET;
Stefan Roese648391c2016-08-30 16:48:20 +0200635 reg_set(utmi_base_addr + UTMI_TX_CH_CTRL_REG, data, mask);
636
637 /* Enable SQ */
638 mask = UTMI_RX_CH_CTRL0_SQ_DET_MASK;
639 data = 0x0 << UTMI_RX_CH_CTRL0_SQ_DET_OFFSET;
640 /* Enable analog squelch detect */
641 mask |= UTMI_RX_CH_CTRL0_SQ_ANA_DTC_MASK;
642 data |= 0x1 << UTMI_RX_CH_CTRL0_SQ_ANA_DTC_OFFSET;
643 reg_set(utmi_base_addr + UTMI_RX_CH_CTRL0_REG, data, mask);
644
645 /* Set External squelch calibration number */
646 mask = UTMI_RX_CH_CTRL1_SQ_AMP_CAL_MASK;
647 data = 0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_OFFSET;
648 /* Enable the External squelch calibration */
649 mask |= UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_MASK;
650 data |= 0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_OFFSET;
651 reg_set(utmi_base_addr + UTMI_RX_CH_CTRL1_REG, data, mask);
652
653 /* Set Control VDAT Reference Voltage - 0.325V */
654 mask = UTMI_CHGDTC_CTRL_VDAT_MASK;
655 data = 0x1 << UTMI_CHGDTC_CTRL_VDAT_OFFSET;
656 /* Set Control VSRC Reference Voltage - 0.6V */
657 mask |= UTMI_CHGDTC_CTRL_VSRC_MASK;
658 data |= 0x1 << UTMI_CHGDTC_CTRL_VSRC_OFFSET;
659 reg_set(utmi_base_addr + UTMI_CHGDTC_CTRL_REG, data, mask);
660
661 debug_exit();
662 return;
663}
664
665static int comphy_utmi_power_up(u32 utmi_index, void __iomem *utmi_base_addr,
666 void __iomem *usb_cfg_addr,
667 void __iomem *utmi_cfg_addr, u32 utmi_phy_port)
668{
669 u32 data, mask, ret = 1;
670 void __iomem *addr;
671
672 debug_enter();
673 debug("stage: UTMI %d - Power up transceiver(Power up Phy), and exit SuspendDM\n",
674 utmi_index);
675 /* Power UP UTMI PHY */
676 reg_set(utmi_cfg_addr, 0x1 << UTMI_PHY_CFG_PU_OFFSET,
677 UTMI_PHY_CFG_PU_MASK);
678 /* Disable Test UTMI select */
679 reg_set(utmi_base_addr + UTMI_CTRL_STATUS0_REG,
680 0x0 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET,
681 UTMI_CTRL_STATUS0_TEST_SEL_MASK);
682
683 debug("stage: Polling for PLL and impedance calibration done, and PLL ready done\n");
684 addr = utmi_base_addr + UTMI_CALIB_CTRL_REG;
685 data = UTMI_CALIB_CTRL_IMPCAL_DONE_MASK;
686 mask = data;
687 data = polling_with_timeout(addr, data, mask, 100);
688 if (data != 0) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900689 pr_err("Impedance calibration is not done\n");
Stefan Roese648391c2016-08-30 16:48:20 +0200690 debug("Read from reg = %p - value = 0x%x\n", addr, data);
691 ret = 0;
692 }
693
694 data = UTMI_CALIB_CTRL_PLLCAL_DONE_MASK;
695 mask = data;
696 data = polling_with_timeout(addr, data, mask, 100);
697 if (data != 0) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900698 pr_err("PLL calibration is not done\n");
Stefan Roese648391c2016-08-30 16:48:20 +0200699 debug("Read from reg = %p - value = 0x%x\n", addr, data);
700 ret = 0;
701 }
702
703 addr = utmi_base_addr + UTMI_PLL_CTRL_REG;
704 data = UTMI_PLL_CTRL_PLL_RDY_MASK;
705 mask = data;
706 data = polling_with_timeout(addr, data, mask, 100);
707 if (data != 0) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900708 pr_err("PLL is not ready\n");
Stefan Roese648391c2016-08-30 16:48:20 +0200709 debug("Read from reg = %p - value = 0x%x\n", addr, data);
710 ret = 0;
711 }
712
713 if (ret)
714 debug("Passed\n");
715 else
716 debug("\n");
717
718 debug_exit();
719 return ret;
720}
721
722/*
723 * comphy_utmi_phy_init initialize the UTMI PHY
724 * the init split in 3 parts:
725 * 1. Power down transceiver and PLL
726 * 2. UTMI PHY configure
Omri Itach561930c2017-04-06 12:54:16 +0300727 * 3. Power up transceiver and PLL
Stefan Roese648391c2016-08-30 16:48:20 +0200728 * Note: - Power down/up should be once for both UTMI PHYs
729 * - comphy_dedicated_phys_init call this function if at least there is
730 * one UTMI PHY exists in FDT blob. access to cp110_utmi_data[0] is
731 * legal
732 */
733static void comphy_utmi_phy_init(u32 utmi_phy_count,
734 struct utmi_phy_data *cp110_utmi_data)
735{
736 u32 i;
737
738 debug_enter();
739 /* UTMI Power down */
740 for (i = 0; i < utmi_phy_count; i++) {
741 comphy_utmi_power_down(i, cp110_utmi_data[i].utmi_base_addr,
742 cp110_utmi_data[i].usb_cfg_addr,
743 cp110_utmi_data[i].utmi_cfg_addr,
744 cp110_utmi_data[i].utmi_phy_port);
745 }
746 /* PLL Power down */
747 debug("stage: UTMI PHY power down PLL\n");
748 for (i = 0; i < utmi_phy_count; i++) {
749 reg_set(cp110_utmi_data[i].usb_cfg_addr,
750 0x0 << UTMI_USB_CFG_PLL_OFFSET, UTMI_USB_CFG_PLL_MASK);
751 }
752 /* UTMI configure */
753 for (i = 0; i < utmi_phy_count; i++) {
754 comphy_utmi_phy_config(i, cp110_utmi_data[i].utmi_base_addr,
755 cp110_utmi_data[i].usb_cfg_addr,
756 cp110_utmi_data[i].utmi_cfg_addr,
757 cp110_utmi_data[i].utmi_phy_port);
758 }
759 /* UTMI Power up */
760 for (i = 0; i < utmi_phy_count; i++) {
761 if (!comphy_utmi_power_up(i, cp110_utmi_data[i].utmi_base_addr,
762 cp110_utmi_data[i].usb_cfg_addr,
763 cp110_utmi_data[i].utmi_cfg_addr,
764 cp110_utmi_data[i].utmi_phy_port)) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900765 pr_err("Failed to initialize UTMI PHY %d\n", i);
Stefan Roese648391c2016-08-30 16:48:20 +0200766 continue;
767 }
768 printf("UTMI PHY %d initialized to ", i);
Stefan Roeseb781f572017-04-24 18:45:23 +0300769 if (cp110_utmi_data[i].utmi_phy_port ==
770 UTMI_PHY_TO_USB3_DEVICE0)
Stefan Roese648391c2016-08-30 16:48:20 +0200771 printf("USB Device\n");
772 else
773 printf("USB Host%d\n",
774 cp110_utmi_data[i].utmi_phy_port);
775 }
776 /* PLL Power up */
777 debug("stage: UTMI PHY power up PLL\n");
778 for (i = 0; i < utmi_phy_count; i++) {
779 reg_set(cp110_utmi_data[i].usb_cfg_addr,
780 0x1 << UTMI_USB_CFG_PLL_OFFSET, UTMI_USB_CFG_PLL_MASK);
781 }
782
783 debug_exit();
784 return;
785}
786
787/*
788 * comphy_dedicated_phys_init initialize the dedicated PHYs
789 * - not muxed SerDes lanes e.g. UTMI PHY
790 */
791void comphy_dedicated_phys_init(void)
792{
793 struct utmi_phy_data cp110_utmi_data[MAX_UTMI_PHY_COUNT];
Omri Itach561930c2017-04-06 12:54:16 +0300794 int node = -1;
795 int node_idx;
Stefan Roese648391c2016-08-30 16:48:20 +0200796
797 debug_enter();
798 debug("Initialize USB UTMI PHYs\n");
799
Omri Itach561930c2017-04-06 12:54:16 +0300800 for (node_idx = 0; node_idx < MAX_UTMI_PHY_COUNT;) {
801 /* Find the UTMI phy node in device tree */
802 node = fdt_node_offset_by_compatible(gd->fdt_blob, node,
803 "marvell,mvebu-utmi-2.6.0");
804 if (node <= 0)
805 break;
Stefan Roese648391c2016-08-30 16:48:20 +0200806
Omri Itach561930c2017-04-06 12:54:16 +0300807 /* check if node is enabled */
808 if (!fdtdec_get_is_enabled(gd->fdt_blob, node))
809 continue;
810
Stefan Roese648391c2016-08-30 16:48:20 +0200811 /* get base address of UTMI phy */
Omri Itach561930c2017-04-06 12:54:16 +0300812 cp110_utmi_data[node_idx].utmi_base_addr =
Stefan Roese648391c2016-08-30 16:48:20 +0200813 (void __iomem *)fdtdec_get_addr_size_auto_noparent(
814 gd->fdt_blob, node, "reg", 0, NULL, true);
Omri Itach561930c2017-04-06 12:54:16 +0300815 if (!cp110_utmi_data[node_idx].utmi_base_addr) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900816 pr_err("UTMI PHY base address is invalid\n");
Stefan Roese648391c2016-08-30 16:48:20 +0200817 continue;
818 }
819
820 /* get usb config address */
Omri Itach561930c2017-04-06 12:54:16 +0300821 cp110_utmi_data[node_idx].usb_cfg_addr =
Stefan Roese648391c2016-08-30 16:48:20 +0200822 (void __iomem *)fdtdec_get_addr_size_auto_noparent(
823 gd->fdt_blob, node, "reg", 1, NULL, true);
Omri Itach561930c2017-04-06 12:54:16 +0300824 if (!cp110_utmi_data[node_idx].usb_cfg_addr) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900825 pr_err("UTMI PHY base address is invalid\n");
Stefan Roese648391c2016-08-30 16:48:20 +0200826 continue;
827 }
828
829 /* get UTMI config address */
Omri Itach561930c2017-04-06 12:54:16 +0300830 cp110_utmi_data[node_idx].utmi_cfg_addr =
Stefan Roese648391c2016-08-30 16:48:20 +0200831 (void __iomem *)fdtdec_get_addr_size_auto_noparent(
832 gd->fdt_blob, node, "reg", 2, NULL, true);
Omri Itach561930c2017-04-06 12:54:16 +0300833 if (!cp110_utmi_data[node_idx].utmi_cfg_addr) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900834 pr_err("UTMI PHY base address is invalid\n");
Stefan Roese648391c2016-08-30 16:48:20 +0200835 continue;
836 }
837
838 /*
839 * get the port number (to check if the utmi connected to
840 * host/device)
841 */
Omri Itach561930c2017-04-06 12:54:16 +0300842 cp110_utmi_data[node_idx].utmi_phy_port = fdtdec_get_int(
Stefan Roese648391c2016-08-30 16:48:20 +0200843 gd->fdt_blob, node, "utmi-port", UTMI_PHY_INVALID);
Omri Itach561930c2017-04-06 12:54:16 +0300844 if (cp110_utmi_data[node_idx].utmi_phy_port ==
845 UTMI_PHY_INVALID) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900846 pr_err("UTMI PHY port type is invalid\n");
Stefan Roese648391c2016-08-30 16:48:20 +0200847 continue;
848 }
849
Omri Itach561930c2017-04-06 12:54:16 +0300850 /* count valid UTMI unit */
851 node_idx++;
Stefan Roese648391c2016-08-30 16:48:20 +0200852 }
853
Omri Itach561930c2017-04-06 12:54:16 +0300854 if (node_idx > 0)
855 comphy_utmi_phy_init(node_idx, cp110_utmi_data);
Stefan Roese648391c2016-08-30 16:48:20 +0200856
857 debug_exit();
858}
859
860static void comphy_mux_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg,
861 struct comphy_map *serdes_map)
862{
863 void __iomem *comphy_base_addr;
864 struct comphy_map comphy_map_pipe_data[MAX_LANE_OPTIONS];
865 struct comphy_map comphy_map_phy_data[MAX_LANE_OPTIONS];
866 u32 lane, comphy_max_count;
867
868 comphy_max_count = ptr_chip_cfg->comphy_lanes_count;
869 comphy_base_addr = ptr_chip_cfg->comphy_base_addr;
870
871 /*
872 * Copy the SerDes map configuration for PIPE map and PHY map
873 * the comphy_mux_init modify the type of the lane if the type
874 * is not valid because we have 2 selectores run the
875 * comphy_mux_init twice and after that update the original
876 * serdes_map
877 */
878 for (lane = 0; lane < comphy_max_count; lane++) {
879 comphy_map_pipe_data[lane].type = serdes_map[lane].type;
880 comphy_map_pipe_data[lane].speed = serdes_map[lane].speed;
881 comphy_map_phy_data[lane].type = serdes_map[lane].type;
882 comphy_map_phy_data[lane].speed = serdes_map[lane].speed;
883 }
884 ptr_chip_cfg->mux_data = cp110_comphy_phy_mux_data;
885 comphy_mux_init(ptr_chip_cfg, comphy_map_phy_data,
886 comphy_base_addr + COMMON_SELECTOR_PHY_OFFSET);
887
888 ptr_chip_cfg->mux_data = cp110_comphy_pipe_mux_data;
889 comphy_mux_init(ptr_chip_cfg, comphy_map_pipe_data,
890 comphy_base_addr + COMMON_SELECTOR_PIPE_OFFSET);
891 /* Fix the type after check the PHY and PIPE configuration */
892 for (lane = 0; lane < comphy_max_count; lane++) {
Igal Libermanffd5d2f2017-04-26 15:40:00 +0300893 if ((comphy_map_pipe_data[lane].type == COMPHY_TYPE_UNCONNECTED) &&
894 (comphy_map_phy_data[lane].type == COMPHY_TYPE_UNCONNECTED))
895 serdes_map[lane].type = COMPHY_TYPE_UNCONNECTED;
Stefan Roese648391c2016-08-30 16:48:20 +0200896 }
897}
898
899int comphy_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg,
900 struct comphy_map *serdes_map)
901{
902 struct comphy_map *ptr_comphy_map;
903 void __iomem *comphy_base_addr, *hpipe_base_addr;
904 u32 comphy_max_count, lane, ret = 0;
905 u32 pcie_width = 0;
Grzegorz Jaszczyk7928a8e2020-10-18 17:11:11 +0300906 u32 mode;
Stefan Roese648391c2016-08-30 16:48:20 +0200907
908 debug_enter();
909
910 comphy_max_count = ptr_chip_cfg->comphy_lanes_count;
911 comphy_base_addr = ptr_chip_cfg->comphy_base_addr;
912 hpipe_base_addr = ptr_chip_cfg->hpipe3_base_addr;
913
914 /* Config Comphy mux configuration */
915 comphy_mux_cp110_init(ptr_chip_cfg, serdes_map);
916
917 /* Check if the first 4 lanes configured as By-4 */
918 for (lane = 0, ptr_comphy_map = serdes_map; lane < 4;
919 lane++, ptr_comphy_map++) {
Igal Libermanffd5d2f2017-04-26 15:40:00 +0300920 if (ptr_comphy_map->type != COMPHY_TYPE_PEX0)
Stefan Roese648391c2016-08-30 16:48:20 +0200921 break;
922 pcie_width++;
923 }
924
925 for (lane = 0, ptr_comphy_map = serdes_map; lane < comphy_max_count;
926 lane++, ptr_comphy_map++) {
927 debug("Initialize serdes number %d\n", lane);
928 debug("Serdes type = 0x%x\n", ptr_comphy_map->type);
929 if (lane == 4) {
930 /*
931 * PCIe lanes above the first 4 lanes, can be only
932 * by1
933 */
934 pcie_width = 1;
935 }
936 switch (ptr_comphy_map->type) {
Igal Libermanffd5d2f2017-04-26 15:40:00 +0300937 case COMPHY_TYPE_UNCONNECTED:
938 case COMPHY_TYPE_IGNORE:
Stefan Roese648391c2016-08-30 16:48:20 +0200939 continue;
940 break;
Igal Libermanffd5d2f2017-04-26 15:40:00 +0300941 case COMPHY_TYPE_PEX0:
942 case COMPHY_TYPE_PEX1:
943 case COMPHY_TYPE_PEX2:
944 case COMPHY_TYPE_PEX3:
Grzegorz Jaszczykc42b5a32020-10-18 17:11:12 +0300945 mode = COMPHY_FW_PCIE_FORMAT(pcie_width,
946 ptr_comphy_map->clk_src,
947 COMPHY_PCIE_MODE,
948 ptr_comphy_map->speed);
949 ret = comphy_smc(MV_SIP_COMPHY_POWER_ON,
950 ptr_chip_cfg->comphy_base_addr, lane,
951 mode);
Stefan Roese648391c2016-08-30 16:48:20 +0200952 break;
Igal Libermanffd5d2f2017-04-26 15:40:00 +0300953 case COMPHY_TYPE_SATA0:
954 case COMPHY_TYPE_SATA1:
Grzegorz Jaszczyk7928a8e2020-10-18 17:11:11 +0300955 mode = COMPHY_FW_MODE_FORMAT(COMPHY_SATA_MODE);
956 ret = comphy_sata_power_up(lane, hpipe_base_addr,
957 comphy_base_addr,
958 ptr_chip_cfg->cp_index,
959 mode);
Stefan Roese648391c2016-08-30 16:48:20 +0200960 break;
Igal Libermanffd5d2f2017-04-26 15:40:00 +0300961 case COMPHY_TYPE_USB3_HOST0:
962 case COMPHY_TYPE_USB3_HOST1:
963 case COMPHY_TYPE_USB3_DEVICE:
Stefan Roese648391c2016-08-30 16:48:20 +0200964 ret = comphy_usb3_power_up(lane, hpipe_base_addr,
965 comphy_base_addr);
966 break;
Igal Libermanffd5d2f2017-04-26 15:40:00 +0300967 case COMPHY_TYPE_SGMII0:
968 case COMPHY_TYPE_SGMII1:
969 if (ptr_comphy_map->speed == COMPHY_SPEED_INVALID) {
Grzegorz Jaszczyk7928a8e2020-10-18 17:11:11 +0300970 debug("Warning: ");
971 debug("SGMII PHY speed in lane %d is invalid,",
972 lane);
973 debug(" set PHY speed to 1.25G\n");
Igal Libermanffd5d2f2017-04-26 15:40:00 +0300974 ptr_comphy_map->speed = COMPHY_SPEED_1_25G;
Grzegorz Jaszczyk7928a8e2020-10-18 17:11:11 +0300975 }
976
977 /*
978 * UINIT_ID not relevant for SGMII0 and SGMII1 - will be
979 * ignored by firmware
980 */
981 mode = COMPHY_FW_FORMAT(COMPHY_SGMII_MODE,
982 COMPHY_UNIT_ID0,
983 ptr_comphy_map->speed);
984 ret = comphy_smc(MV_SIP_COMPHY_POWER_ON,
985 ptr_chip_cfg->comphy_base_addr, lane,
986 mode);
987 break;
Igal Libermanffd5d2f2017-04-26 15:40:00 +0300988 case COMPHY_TYPE_SGMII2:
Igal Libermanffd5d2f2017-04-26 15:40:00 +0300989 if (ptr_comphy_map->speed == COMPHY_SPEED_INVALID) {
Stefan Roese648391c2016-08-30 16:48:20 +0200990 debug("Warning: SGMII PHY speed in lane %d is invalid, set PHY speed to 1.25G\n",
991 lane);
Igal Libermanffd5d2f2017-04-26 15:40:00 +0300992 ptr_comphy_map->speed = COMPHY_SPEED_1_25G;
Stefan Roese648391c2016-08-30 16:48:20 +0200993 }
Grzegorz Jaszczyk7928a8e2020-10-18 17:11:11 +0300994
995 mode = COMPHY_FW_FORMAT(COMPHY_SGMII_MODE,
996 COMPHY_UNIT_ID2,
997 ptr_comphy_map->speed);
998 ret = comphy_smc(MV_SIP_COMPHY_POWER_ON,
999 ptr_chip_cfg->comphy_base_addr, lane,
1000 mode);
Stefan Roese648391c2016-08-30 16:48:20 +02001001 break;
Igal Libermanffd5d2f2017-04-26 15:40:00 +03001002 case COMPHY_TYPE_SFI:
Grzegorz Jaszczyk7928a8e2020-10-18 17:11:11 +03001003 mode = COMPHY_FW_FORMAT(COMPHY_SFI_MODE,
1004 COMPHY_UNIT_ID0,
1005 ptr_comphy_map->speed);
1006 ret = comphy_smc(MV_SIP_COMPHY_POWER_ON,
1007 ptr_chip_cfg->comphy_base_addr, lane,
1008 mode);
Stefan Roese648391c2016-08-30 16:48:20 +02001009 break;
Igal Libermanffd5d2f2017-04-26 15:40:00 +03001010 case COMPHY_TYPE_RXAUI0:
1011 case COMPHY_TYPE_RXAUI1:
Grzegorz Jaszczykbeb4a912018-03-27 12:52:24 +02001012 mode = COMPHY_FW_MODE_FORMAT(COMPHY_RXAUI_MODE);
1013 ret = comphy_smc(MV_SIP_COMPHY_POWER_ON,
1014 ptr_chip_cfg->comphy_base_addr, lane,
1015 mode);
Stefan Roese648391c2016-08-30 16:48:20 +02001016 break;
1017 default:
1018 debug("Unknown SerDes type, skip initialize SerDes %d\n",
1019 lane);
1020 break;
1021 }
1022 if (ret == 0) {
1023 /*
Stefan Roese4fbca012017-04-24 18:45:25 +03001024 * If interface wans't initialized, set the lane to
Igal Libermanffd5d2f2017-04-26 15:40:00 +03001025 * COMPHY_TYPE_UNCONNECTED state.
Stefan Roese648391c2016-08-30 16:48:20 +02001026 */
Igal Libermanffd5d2f2017-04-26 15:40:00 +03001027 ptr_comphy_map->type = COMPHY_TYPE_UNCONNECTED;
Masahiro Yamada81e10422017-09-16 14:10:41 +09001028 pr_err("PLL is not locked - Failed to initialize lane %d\n",
Stefan Roese648391c2016-08-30 16:48:20 +02001029 lane);
1030 }
1031 }
1032
1033 debug_exit();
1034 return 0;
1035}