blob: 55202888194d4aab2f32427831b5e608f016f565 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Stefan Roesec0132f62016-08-30 16:48:20 +02002/*
3 * Copyright (C) 2015-2016 Marvell International Ltd.
Stefan Roesec0132f62016-08-30 16:48:20 +02004 */
5
6#include <common.h>
7#include <fdtdec.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -06008#include <log.h>
Simon Glass401d1c42020-10-30 21:38:53 -06009#include <asm/global_data.h>
Stefan Roesec0132f62016-08-30 16:48:20 +020010#include <asm/io.h>
Grzegorz Jaszczykb24bb992020-10-18 17:11:11 +030011#include <asm/ptrace.h>
Stefan Roesec0132f62016-08-30 16:48:20 +020012#include <asm/arch/cpu.h>
13#include <asm/arch/soc.h>
Simon Glassc05ed002020-05-10 11:40:11 -060014#include <linux/delay.h>
Stefan Roesec0132f62016-08-30 16:48:20 +020015
Marek BehĂșn4b8cb842018-08-17 12:58:51 +020016#include "comphy_core.h"
Stefan Roesec0132f62016-08-30 16:48:20 +020017#include "sata.h"
18#include "utmi_phy.h"
19
20DECLARE_GLOBAL_DATA_PTR;
21
Grzegorz Jaszczykb24bb992020-10-18 17:11:11 +030022/* Firmware related definitions used for SMC calls */
23#define MV_SIP_COMPHY_POWER_ON 0x82000001
24#define MV_SIP_COMPHY_POWER_OFF 0x82000002
25#define MV_SIP_COMPHY_PLL_LOCK 0x82000003
Grzegorz Jaszczyk2e28b592018-04-03 16:59:12 +020026#define MV_SIP_COMPHY_XFI_TRAIN 0x82000004
Grzegorz Jaszczykb24bb992020-10-18 17:11:11 +030027
Igal Liberman3261f6d2020-10-18 17:11:13 +030028/* Used to distinguish between different possible callers (U-boot/Linux) */
29#define COMPHY_CALLER_UBOOT (0x1 << 21)
30
Grzegorz Jaszczykb24bb992020-10-18 17:11:11 +030031#define COMPHY_FW_MODE_FORMAT(mode) ((mode) << 12)
32#define COMPHY_FW_FORMAT(mode, idx, speeds) \
33 (((mode) << 12) | ((idx) << 8) | ((speeds) << 2))
Grzegorz Jaszczyk0a1a1642020-10-18 17:11:12 +030034
35#define COMPHY_FW_PCIE_FORMAT(pcie_width, clk_src, mode, speeds) \
Igal Liberman3261f6d2020-10-18 17:11:13 +030036 (COMPHY_CALLER_UBOOT | ((pcie_width) << 18) | \
37 ((clk_src) << 17) | COMPHY_FW_FORMAT(mode, 0, speeds))
Grzegorz Jaszczyk0a1a1642020-10-18 17:11:12 +030038
Grzegorz Jaszczykb24bb992020-10-18 17:11:11 +030039#define COMPHY_SATA_MODE 0x1
40#define COMPHY_SGMII_MODE 0x2 /* SGMII 1G */
41#define COMPHY_HS_SGMII_MODE 0x3 /* SGMII 2.5G */
42#define COMPHY_USB3H_MODE 0x4
43#define COMPHY_USB3D_MODE 0x5
44#define COMPHY_PCIE_MODE 0x6
45#define COMPHY_RXAUI_MODE 0x7
46#define COMPHY_XFI_MODE 0x8
47#define COMPHY_SFI_MODE 0x9
48#define COMPHY_USB3_MODE 0xa
49#define COMPHY_AP_MODE 0xb
50
51/* Comphy unit index macro */
52#define COMPHY_UNIT_ID0 0
53#define COMPHY_UNIT_ID1 1
54#define COMPHY_UNIT_ID2 2
55#define COMPHY_UNIT_ID3 3
56
Stefan Roesec0132f62016-08-30 16:48:20 +020057struct utmi_phy_data {
58 void __iomem *utmi_base_addr;
59 void __iomem *usb_cfg_addr;
60 void __iomem *utmi_cfg_addr;
61 u32 utmi_phy_port;
62};
63
Stefan Roesec0132f62016-08-30 16:48:20 +020064static u32 polling_with_timeout(void __iomem *addr, u32 val,
65 u32 mask, unsigned long usec_timout)
66{
67 u32 data;
68
69 do {
70 udelay(1);
71 data = readl(addr) & mask;
72 } while (data != val && --usec_timout > 0);
73
74 if (usec_timout == 0)
75 return data;
76
77 return 0;
78}
79
Grzegorz Jaszczykb24bb992020-10-18 17:11:11 +030080static int comphy_smc(u32 function_id, void __iomem *comphy_base_addr,
81 u32 lane, u32 mode)
82{
83 struct pt_regs pregs = {0};
84
85 pregs.regs[0] = function_id;
86 pregs.regs[1] = (unsigned long)comphy_base_addr;
87 pregs.regs[2] = lane;
88 pregs.regs[3] = mode;
89
90 smc_call(&pregs);
91
92 /*
93 * TODO: Firmware return 0 on success, temporary map it to u-boot
94 * convention, but after all comphy will be reworked the convention in
95 * u-boot should be change and this conversion removed
96 */
97 return pregs.regs[0] ? 0 : 1;
98}
99
Grzegorz Jaszczyk2e28b592018-04-03 16:59:12 +0200100/* This function performs RX training for all FFE possible values.
101 * We get the result for each FFE and eventually the best FFE will
102 * be used and set to the HW.
103 *
104 * Return '1' on succsess.
105 * Return '0' on failure.
106 */
107int comphy_cp110_sfi_rx_training(struct chip_serdes_phy_config *ptr_chip_cfg,
108 u32 lane)
109{
110 int ret;
111
112 debug_enter();
113
114 if (ptr_chip_cfg->comphy_map_data[lane].type != COMPHY_TYPE_SFI) {
115 pr_err("Comphy %d isn't configured to SFI\n", lane);
116 return 0;
117 }
118
119 /* Mode is not relevant for xfi training */
120 ret = comphy_smc(MV_SIP_COMPHY_XFI_TRAIN,
121 ptr_chip_cfg->comphy_base_addr, lane, 0);
122
123 debug_exit();
124
125 return ret;
126}
127
Stefan Roesec0132f62016-08-30 16:48:20 +0200128static int comphy_sata_power_up(u32 lane, void __iomem *hpipe_base,
Grzegorz Jaszczykb24bb992020-10-18 17:11:11 +0300129 void __iomem *comphy_base_addr, int cp_index,
130 u32 type)
Stefan Roesec0132f62016-08-30 16:48:20 +0200131{
132 u32 mask, data, i, ret = 1;
Stefan Roesec0132f62016-08-30 16:48:20 +0200133 void __iomem *sata_base = NULL;
134 int sata_node = -1; /* Set to -1 in order to read the first sata node */
135
136 debug_enter();
137
138 /*
139 * Assumption - each CP has only one SATA controller
140 * Calling fdt_node_offset_by_compatible first time (with sata_node = -1
141 * will return the first node always.
142 * In order to parse each CPs SATA node, fdt_node_offset_by_compatible
143 * must be called again (according to the CP id)
144 */
Igal Liberman528213d2017-04-24 18:45:32 +0300145 for (i = 0; i < (cp_index + 1); i++)
Stefan Roesec0132f62016-08-30 16:48:20 +0200146 sata_node = fdt_node_offset_by_compatible(
147 gd->fdt_blob, sata_node, "marvell,armada-8k-ahci");
148
149 if (sata_node == 0) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900150 pr_err("SATA node not found in FDT\n");
Stefan Roesec0132f62016-08-30 16:48:20 +0200151 return 0;
152 }
153
154 sata_base = (void __iomem *)fdtdec_get_addr_size_auto_noparent(
155 gd->fdt_blob, sata_node, "reg", 0, NULL, true);
156 if (sata_base == NULL) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900157 pr_err("SATA address not found in FDT\n");
Stefan Roesec0132f62016-08-30 16:48:20 +0200158 return 0;
159 }
160
161 debug("SATA address found in FDT %p\n", sata_base);
162
163 debug("stage: MAC configuration - power down comphy\n");
164 /*
165 * MAC configuration powe down comphy use indirect address for
166 * vendor spesific SATA control register
167 */
168 reg_set(sata_base + SATA3_VENDOR_ADDRESS,
169 SATA_CONTROL_REG << SATA3_VENDOR_ADDR_OFSSET,
170 SATA3_VENDOR_ADDR_MASK);
171 /* SATA 0 power down */
172 mask = SATA3_CTRL_SATA0_PD_MASK;
173 data = 0x1 << SATA3_CTRL_SATA0_PD_OFFSET;
174 /* SATA 1 power down */
175 mask |= SATA3_CTRL_SATA1_PD_MASK;
176 data |= 0x1 << SATA3_CTRL_SATA1_PD_OFFSET;
177 /* SATA SSU disable */
178 mask |= SATA3_CTRL_SATA1_ENABLE_MASK;
179 data |= 0x0 << SATA3_CTRL_SATA1_ENABLE_OFFSET;
180 /* SATA port 1 disable */
181 mask |= SATA3_CTRL_SATA_SSU_MASK;
182 data |= 0x0 << SATA3_CTRL_SATA_SSU_OFFSET;
183 reg_set(sata_base + SATA3_VENDOR_DATA, data, mask);
184
Grzegorz Jaszczykb24bb992020-10-18 17:11:11 +0300185 ret = comphy_smc(MV_SIP_COMPHY_POWER_ON, comphy_base_addr, lane, type);
Stefan Roesec0132f62016-08-30 16:48:20 +0200186
Stefan Roesec0132f62016-08-30 16:48:20 +0200187 /*
188 * MAC configuration power up comphy - power up PLL/TX/RX
189 * use indirect address for vendor spesific SATA control register
190 */
191 reg_set(sata_base + SATA3_VENDOR_ADDRESS,
192 SATA_CONTROL_REG << SATA3_VENDOR_ADDR_OFSSET,
193 SATA3_VENDOR_ADDR_MASK);
194 /* SATA 0 power up */
195 mask = SATA3_CTRL_SATA0_PD_MASK;
196 data = 0x0 << SATA3_CTRL_SATA0_PD_OFFSET;
197 /* SATA 1 power up */
198 mask |= SATA3_CTRL_SATA1_PD_MASK;
199 data |= 0x0 << SATA3_CTRL_SATA1_PD_OFFSET;
200 /* SATA SSU enable */
201 mask |= SATA3_CTRL_SATA1_ENABLE_MASK;
202 data |= 0x1 << SATA3_CTRL_SATA1_ENABLE_OFFSET;
203 /* SATA port 1 enable */
204 mask |= SATA3_CTRL_SATA_SSU_MASK;
205 data |= 0x1 << SATA3_CTRL_SATA_SSU_OFFSET;
206 reg_set(sata_base + SATA3_VENDOR_DATA, data, mask);
207
208 /* MBUS request size and interface select register */
209 reg_set(sata_base + SATA3_VENDOR_ADDRESS,
210 SATA_MBUS_SIZE_SELECT_REG << SATA3_VENDOR_ADDR_OFSSET,
211 SATA3_VENDOR_ADDR_MASK);
212 /* Mbus regret enable */
213 reg_set(sata_base + SATA3_VENDOR_DATA,
214 0x1 << SATA_MBUS_REGRET_EN_OFFSET, SATA_MBUS_REGRET_EN_MASK);
215
Grzegorz Jaszczykb24bb992020-10-18 17:11:11 +0300216 ret = comphy_smc(MV_SIP_COMPHY_PLL_LOCK, comphy_base_addr, lane, type);
Stefan Roesec0132f62016-08-30 16:48:20 +0200217
218 debug_exit();
219 return ret;
220}
221
Stefan Roesec0132f62016-08-30 16:48:20 +0200222static void comphy_utmi_power_down(u32 utmi_index, void __iomem *utmi_base_addr,
223 void __iomem *usb_cfg_addr,
224 void __iomem *utmi_cfg_addr,
225 u32 utmi_phy_port)
226{
227 u32 mask, data;
228
229 debug_enter();
230 debug("stage: UTMI %d - Power down transceiver (power down Phy), Power down PLL, and SuspendDM\n",
231 utmi_index);
232 /* Power down UTMI PHY */
233 reg_set(utmi_cfg_addr, 0x0 << UTMI_PHY_CFG_PU_OFFSET,
234 UTMI_PHY_CFG_PU_MASK);
235
236 /*
237 * If UTMI connected to USB Device, configure mux prior to PHY init
238 * (Device can be connected to UTMI0 or to UTMI1)
239 */
Stefan Roesee89acc42017-04-24 18:45:23 +0300240 if (utmi_phy_port == UTMI_PHY_TO_USB3_DEVICE0) {
Stefan Roesec0132f62016-08-30 16:48:20 +0200241 debug("stage: UTMI %d - Enable Device mode and configure UTMI mux\n",
242 utmi_index);
243 /* USB3 Device UTMI enable */
244 mask = UTMI_USB_CFG_DEVICE_EN_MASK;
245 data = 0x1 << UTMI_USB_CFG_DEVICE_EN_OFFSET;
246 /* USB3 Device UTMI MUX */
247 mask |= UTMI_USB_CFG_DEVICE_MUX_MASK;
248 data |= utmi_index << UTMI_USB_CFG_DEVICE_MUX_OFFSET;
249 reg_set(usb_cfg_addr, data, mask);
250 }
251
252 /* Set Test suspendm mode */
253 mask = UTMI_CTRL_STATUS0_SUSPENDM_MASK;
254 data = 0x1 << UTMI_CTRL_STATUS0_SUSPENDM_OFFSET;
255 /* Enable Test UTMI select */
256 mask |= UTMI_CTRL_STATUS0_TEST_SEL_MASK;
257 data |= 0x1 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET;
258 reg_set(utmi_base_addr + UTMI_CTRL_STATUS0_REG, data, mask);
259
260 /* Wait for UTMI power down */
261 mdelay(1);
262
263 debug_exit();
264 return;
265}
266
267static void comphy_utmi_phy_config(u32 utmi_index, void __iomem *utmi_base_addr,
268 void __iomem *usb_cfg_addr,
269 void __iomem *utmi_cfg_addr,
270 u32 utmi_phy_port)
271{
272 u32 mask, data;
273
274 debug_exit();
275 debug("stage: Configure UTMI PHY %d registers\n", utmi_index);
276 /* Reference Clock Divider Select */
277 mask = UTMI_PLL_CTRL_REFDIV_MASK;
278 data = 0x5 << UTMI_PLL_CTRL_REFDIV_OFFSET;
279 /* Feedback Clock Divider Select - 90 for 25Mhz*/
280 mask |= UTMI_PLL_CTRL_FBDIV_MASK;
281 data |= 0x60 << UTMI_PLL_CTRL_FBDIV_OFFSET;
282 /* Select LPFR - 0x0 for 25Mhz/5=5Mhz*/
283 mask |= UTMI_PLL_CTRL_SEL_LPFR_MASK;
284 data |= 0x0 << UTMI_PLL_CTRL_SEL_LPFR_OFFSET;
285 reg_set(utmi_base_addr + UTMI_PLL_CTRL_REG, data, mask);
286
287 /* Impedance Calibration Threshold Setting */
288 reg_set(utmi_base_addr + UTMI_CALIB_CTRL_REG,
Igal Liberman3e69b4a2017-04-30 20:16:55 +0300289 0x7 << UTMI_CALIB_CTRL_IMPCAL_VTH_OFFSET,
Stefan Roesec0132f62016-08-30 16:48:20 +0200290 UTMI_CALIB_CTRL_IMPCAL_VTH_MASK);
291
292 /* Set LS TX driver strength coarse control */
Igal Liberman3e69b4a2017-04-30 20:16:55 +0300293 mask = UTMI_TX_CH_CTRL_AMP_MASK;
294 data = 0x4 << UTMI_TX_CH_CTRL_AMP_OFFSET;
Stefan Roesec0132f62016-08-30 16:48:20 +0200295 reg_set(utmi_base_addr + UTMI_TX_CH_CTRL_REG, data, mask);
296
297 /* Enable SQ */
298 mask = UTMI_RX_CH_CTRL0_SQ_DET_MASK;
299 data = 0x0 << UTMI_RX_CH_CTRL0_SQ_DET_OFFSET;
300 /* Enable analog squelch detect */
301 mask |= UTMI_RX_CH_CTRL0_SQ_ANA_DTC_MASK;
302 data |= 0x1 << UTMI_RX_CH_CTRL0_SQ_ANA_DTC_OFFSET;
303 reg_set(utmi_base_addr + UTMI_RX_CH_CTRL0_REG, data, mask);
304
305 /* Set External squelch calibration number */
306 mask = UTMI_RX_CH_CTRL1_SQ_AMP_CAL_MASK;
307 data = 0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_OFFSET;
308 /* Enable the External squelch calibration */
309 mask |= UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_MASK;
310 data |= 0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_OFFSET;
311 reg_set(utmi_base_addr + UTMI_RX_CH_CTRL1_REG, data, mask);
312
313 /* Set Control VDAT Reference Voltage - 0.325V */
314 mask = UTMI_CHGDTC_CTRL_VDAT_MASK;
315 data = 0x1 << UTMI_CHGDTC_CTRL_VDAT_OFFSET;
316 /* Set Control VSRC Reference Voltage - 0.6V */
317 mask |= UTMI_CHGDTC_CTRL_VSRC_MASK;
318 data |= 0x1 << UTMI_CHGDTC_CTRL_VSRC_OFFSET;
319 reg_set(utmi_base_addr + UTMI_CHGDTC_CTRL_REG, data, mask);
320
321 debug_exit();
322 return;
323}
324
325static int comphy_utmi_power_up(u32 utmi_index, void __iomem *utmi_base_addr,
326 void __iomem *usb_cfg_addr,
327 void __iomem *utmi_cfg_addr, u32 utmi_phy_port)
328{
329 u32 data, mask, ret = 1;
330 void __iomem *addr;
331
332 debug_enter();
333 debug("stage: UTMI %d - Power up transceiver(Power up Phy), and exit SuspendDM\n",
334 utmi_index);
335 /* Power UP UTMI PHY */
336 reg_set(utmi_cfg_addr, 0x1 << UTMI_PHY_CFG_PU_OFFSET,
337 UTMI_PHY_CFG_PU_MASK);
338 /* Disable Test UTMI select */
339 reg_set(utmi_base_addr + UTMI_CTRL_STATUS0_REG,
340 0x0 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET,
341 UTMI_CTRL_STATUS0_TEST_SEL_MASK);
342
343 debug("stage: Polling for PLL and impedance calibration done, and PLL ready done\n");
344 addr = utmi_base_addr + UTMI_CALIB_CTRL_REG;
345 data = UTMI_CALIB_CTRL_IMPCAL_DONE_MASK;
346 mask = data;
347 data = polling_with_timeout(addr, data, mask, 100);
348 if (data != 0) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900349 pr_err("Impedance calibration is not done\n");
Stefan Roesec0132f62016-08-30 16:48:20 +0200350 debug("Read from reg = %p - value = 0x%x\n", addr, data);
351 ret = 0;
352 }
353
354 data = UTMI_CALIB_CTRL_PLLCAL_DONE_MASK;
355 mask = data;
356 data = polling_with_timeout(addr, data, mask, 100);
357 if (data != 0) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900358 pr_err("PLL calibration is not done\n");
Stefan Roesec0132f62016-08-30 16:48:20 +0200359 debug("Read from reg = %p - value = 0x%x\n", addr, data);
360 ret = 0;
361 }
362
363 addr = utmi_base_addr + UTMI_PLL_CTRL_REG;
364 data = UTMI_PLL_CTRL_PLL_RDY_MASK;
365 mask = data;
366 data = polling_with_timeout(addr, data, mask, 100);
367 if (data != 0) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900368 pr_err("PLL is not ready\n");
Stefan Roesec0132f62016-08-30 16:48:20 +0200369 debug("Read from reg = %p - value = 0x%x\n", addr, data);
370 ret = 0;
371 }
372
373 if (ret)
374 debug("Passed\n");
375 else
376 debug("\n");
377
378 debug_exit();
379 return ret;
380}
381
382/*
383 * comphy_utmi_phy_init initialize the UTMI PHY
384 * the init split in 3 parts:
385 * 1. Power down transceiver and PLL
386 * 2. UTMI PHY configure
Omri Itach22bc8682017-04-06 12:54:16 +0300387 * 3. Power up transceiver and PLL
Stefan Roesec0132f62016-08-30 16:48:20 +0200388 * Note: - Power down/up should be once for both UTMI PHYs
389 * - comphy_dedicated_phys_init call this function if at least there is
390 * one UTMI PHY exists in FDT blob. access to cp110_utmi_data[0] is
391 * legal
392 */
393static void comphy_utmi_phy_init(u32 utmi_phy_count,
394 struct utmi_phy_data *cp110_utmi_data)
395{
396 u32 i;
397
398 debug_enter();
399 /* UTMI Power down */
400 for (i = 0; i < utmi_phy_count; i++) {
401 comphy_utmi_power_down(i, cp110_utmi_data[i].utmi_base_addr,
402 cp110_utmi_data[i].usb_cfg_addr,
403 cp110_utmi_data[i].utmi_cfg_addr,
404 cp110_utmi_data[i].utmi_phy_port);
405 }
406 /* PLL Power down */
407 debug("stage: UTMI PHY power down PLL\n");
408 for (i = 0; i < utmi_phy_count; i++) {
409 reg_set(cp110_utmi_data[i].usb_cfg_addr,
410 0x0 << UTMI_USB_CFG_PLL_OFFSET, UTMI_USB_CFG_PLL_MASK);
411 }
412 /* UTMI configure */
413 for (i = 0; i < utmi_phy_count; i++) {
414 comphy_utmi_phy_config(i, cp110_utmi_data[i].utmi_base_addr,
415 cp110_utmi_data[i].usb_cfg_addr,
416 cp110_utmi_data[i].utmi_cfg_addr,
417 cp110_utmi_data[i].utmi_phy_port);
418 }
419 /* UTMI Power up */
420 for (i = 0; i < utmi_phy_count; i++) {
421 if (!comphy_utmi_power_up(i, cp110_utmi_data[i].utmi_base_addr,
422 cp110_utmi_data[i].usb_cfg_addr,
423 cp110_utmi_data[i].utmi_cfg_addr,
424 cp110_utmi_data[i].utmi_phy_port)) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900425 pr_err("Failed to initialize UTMI PHY %d\n", i);
Stefan Roesec0132f62016-08-30 16:48:20 +0200426 continue;
427 }
428 printf("UTMI PHY %d initialized to ", i);
Stefan Roesee89acc42017-04-24 18:45:23 +0300429 if (cp110_utmi_data[i].utmi_phy_port ==
430 UTMI_PHY_TO_USB3_DEVICE0)
Stefan Roesec0132f62016-08-30 16:48:20 +0200431 printf("USB Device\n");
432 else
433 printf("USB Host%d\n",
434 cp110_utmi_data[i].utmi_phy_port);
435 }
436 /* PLL Power up */
437 debug("stage: UTMI PHY power up PLL\n");
438 for (i = 0; i < utmi_phy_count; i++) {
439 reg_set(cp110_utmi_data[i].usb_cfg_addr,
440 0x1 << UTMI_USB_CFG_PLL_OFFSET, UTMI_USB_CFG_PLL_MASK);
441 }
442
443 debug_exit();
444 return;
445}
446
447/*
448 * comphy_dedicated_phys_init initialize the dedicated PHYs
449 * - not muxed SerDes lanes e.g. UTMI PHY
450 */
451void comphy_dedicated_phys_init(void)
452{
453 struct utmi_phy_data cp110_utmi_data[MAX_UTMI_PHY_COUNT];
Omri Itach22bc8682017-04-06 12:54:16 +0300454 int node = -1;
455 int node_idx;
Stefan Roesec0132f62016-08-30 16:48:20 +0200456
457 debug_enter();
458 debug("Initialize USB UTMI PHYs\n");
459
Omri Itach22bc8682017-04-06 12:54:16 +0300460 for (node_idx = 0; node_idx < MAX_UTMI_PHY_COUNT;) {
461 /* Find the UTMI phy node in device tree */
462 node = fdt_node_offset_by_compatible(gd->fdt_blob, node,
463 "marvell,mvebu-utmi-2.6.0");
464 if (node <= 0)
465 break;
Stefan Roesec0132f62016-08-30 16:48:20 +0200466
Omri Itach22bc8682017-04-06 12:54:16 +0300467 /* check if node is enabled */
468 if (!fdtdec_get_is_enabled(gd->fdt_blob, node))
469 continue;
470
Stefan Roesec0132f62016-08-30 16:48:20 +0200471 /* get base address of UTMI phy */
Omri Itach22bc8682017-04-06 12:54:16 +0300472 cp110_utmi_data[node_idx].utmi_base_addr =
Stefan Roesec0132f62016-08-30 16:48:20 +0200473 (void __iomem *)fdtdec_get_addr_size_auto_noparent(
474 gd->fdt_blob, node, "reg", 0, NULL, true);
Omri Itach22bc8682017-04-06 12:54:16 +0300475 if (!cp110_utmi_data[node_idx].utmi_base_addr) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900476 pr_err("UTMI PHY base address is invalid\n");
Stefan Roesec0132f62016-08-30 16:48:20 +0200477 continue;
478 }
479
480 /* get usb config address */
Omri Itach22bc8682017-04-06 12:54:16 +0300481 cp110_utmi_data[node_idx].usb_cfg_addr =
Stefan Roesec0132f62016-08-30 16:48:20 +0200482 (void __iomem *)fdtdec_get_addr_size_auto_noparent(
483 gd->fdt_blob, node, "reg", 1, NULL, true);
Omri Itach22bc8682017-04-06 12:54:16 +0300484 if (!cp110_utmi_data[node_idx].usb_cfg_addr) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900485 pr_err("UTMI PHY base address is invalid\n");
Stefan Roesec0132f62016-08-30 16:48:20 +0200486 continue;
487 }
488
489 /* get UTMI config address */
Omri Itach22bc8682017-04-06 12:54:16 +0300490 cp110_utmi_data[node_idx].utmi_cfg_addr =
Stefan Roesec0132f62016-08-30 16:48:20 +0200491 (void __iomem *)fdtdec_get_addr_size_auto_noparent(
492 gd->fdt_blob, node, "reg", 2, NULL, true);
Omri Itach22bc8682017-04-06 12:54:16 +0300493 if (!cp110_utmi_data[node_idx].utmi_cfg_addr) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900494 pr_err("UTMI PHY base address is invalid\n");
Stefan Roesec0132f62016-08-30 16:48:20 +0200495 continue;
496 }
497
498 /*
499 * get the port number (to check if the utmi connected to
500 * host/device)
501 */
Omri Itach22bc8682017-04-06 12:54:16 +0300502 cp110_utmi_data[node_idx].utmi_phy_port = fdtdec_get_int(
Stefan Roesec0132f62016-08-30 16:48:20 +0200503 gd->fdt_blob, node, "utmi-port", UTMI_PHY_INVALID);
Omri Itach22bc8682017-04-06 12:54:16 +0300504 if (cp110_utmi_data[node_idx].utmi_phy_port ==
505 UTMI_PHY_INVALID) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900506 pr_err("UTMI PHY port type is invalid\n");
Stefan Roesec0132f62016-08-30 16:48:20 +0200507 continue;
508 }
509
Omri Itach22bc8682017-04-06 12:54:16 +0300510 /* count valid UTMI unit */
511 node_idx++;
Stefan Roesec0132f62016-08-30 16:48:20 +0200512 }
513
Omri Itach22bc8682017-04-06 12:54:16 +0300514 if (node_idx > 0)
515 comphy_utmi_phy_init(node_idx, cp110_utmi_data);
Stefan Roesec0132f62016-08-30 16:48:20 +0200516
517 debug_exit();
518}
519
Stefan Roesec0132f62016-08-30 16:48:20 +0200520int comphy_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg,
521 struct comphy_map *serdes_map)
522{
523 struct comphy_map *ptr_comphy_map;
524 void __iomem *comphy_base_addr, *hpipe_base_addr;
Igal Liberman5f41aaf2018-05-09 18:50:29 +0300525 u32 comphy_max_count, lane, id, ret = 0;
Stefan Roesec0132f62016-08-30 16:48:20 +0200526 u32 pcie_width = 0;
Grzegorz Jaszczykb24bb992020-10-18 17:11:11 +0300527 u32 mode;
Stefan Roesec0132f62016-08-30 16:48:20 +0200528
529 debug_enter();
530
531 comphy_max_count = ptr_chip_cfg->comphy_lanes_count;
532 comphy_base_addr = ptr_chip_cfg->comphy_base_addr;
533 hpipe_base_addr = ptr_chip_cfg->hpipe3_base_addr;
534
Stefan Roesec0132f62016-08-30 16:48:20 +0200535 /* Check if the first 4 lanes configured as By-4 */
536 for (lane = 0, ptr_comphy_map = serdes_map; lane < 4;
537 lane++, ptr_comphy_map++) {
Igal Liberman2dbba242017-04-26 15:40:00 +0300538 if (ptr_comphy_map->type != COMPHY_TYPE_PEX0)
Stefan Roesec0132f62016-08-30 16:48:20 +0200539 break;
540 pcie_width++;
541 }
542
543 for (lane = 0, ptr_comphy_map = serdes_map; lane < comphy_max_count;
544 lane++, ptr_comphy_map++) {
545 debug("Initialize serdes number %d\n", lane);
546 debug("Serdes type = 0x%x\n", ptr_comphy_map->type);
547 if (lane == 4) {
548 /*
549 * PCIe lanes above the first 4 lanes, can be only
550 * by1
551 */
552 pcie_width = 1;
553 }
554 switch (ptr_comphy_map->type) {
Igal Liberman2dbba242017-04-26 15:40:00 +0300555 case COMPHY_TYPE_UNCONNECTED:
556 case COMPHY_TYPE_IGNORE:
Stefan Roesec0132f62016-08-30 16:48:20 +0200557 continue;
558 break;
Igal Liberman2dbba242017-04-26 15:40:00 +0300559 case COMPHY_TYPE_PEX0:
560 case COMPHY_TYPE_PEX1:
561 case COMPHY_TYPE_PEX2:
562 case COMPHY_TYPE_PEX3:
Grzegorz Jaszczyk0a1a1642020-10-18 17:11:12 +0300563 mode = COMPHY_FW_PCIE_FORMAT(pcie_width,
564 ptr_comphy_map->clk_src,
565 COMPHY_PCIE_MODE,
566 ptr_comphy_map->speed);
567 ret = comphy_smc(MV_SIP_COMPHY_POWER_ON,
568 ptr_chip_cfg->comphy_base_addr, lane,
569 mode);
Stefan Roesec0132f62016-08-30 16:48:20 +0200570 break;
Igal Liberman2dbba242017-04-26 15:40:00 +0300571 case COMPHY_TYPE_SATA0:
572 case COMPHY_TYPE_SATA1:
Grzegorz Jaszczykb24bb992020-10-18 17:11:11 +0300573 mode = COMPHY_FW_MODE_FORMAT(COMPHY_SATA_MODE);
574 ret = comphy_sata_power_up(lane, hpipe_base_addr,
575 comphy_base_addr,
576 ptr_chip_cfg->cp_index,
577 mode);
Stefan Roesec0132f62016-08-30 16:48:20 +0200578 break;
Igal Liberman2dbba242017-04-26 15:40:00 +0300579 case COMPHY_TYPE_USB3_HOST0:
580 case COMPHY_TYPE_USB3_HOST1:
Grzegorz Jaszczykf635c3b2018-03-29 12:30:20 +0200581 mode = COMPHY_FW_MODE_FORMAT(COMPHY_USB3H_MODE);
582 ret = comphy_smc(MV_SIP_COMPHY_POWER_ON,
583 ptr_chip_cfg->comphy_base_addr, lane,
584 mode);
585 break;
Igal Liberman2dbba242017-04-26 15:40:00 +0300586 case COMPHY_TYPE_USB3_DEVICE:
Grzegorz Jaszczykf635c3b2018-03-29 12:30:20 +0200587 mode = COMPHY_FW_MODE_FORMAT(COMPHY_USB3D_MODE);
588 ret = comphy_smc(MV_SIP_COMPHY_POWER_ON,
589 ptr_chip_cfg->comphy_base_addr, lane,
590 mode);
Stefan Roesec0132f62016-08-30 16:48:20 +0200591 break;
Igal Liberman2dbba242017-04-26 15:40:00 +0300592 case COMPHY_TYPE_SGMII0:
593 case COMPHY_TYPE_SGMII1:
Igal Liberman2dbba242017-04-26 15:40:00 +0300594 case COMPHY_TYPE_SGMII2:
Igal Liberman5f41aaf2018-05-09 18:50:29 +0300595 /* Calculate SGMII ID */
596 id = ptr_comphy_map->type - COMPHY_TYPE_SGMII0;
597
Igal Liberman2dbba242017-04-26 15:40:00 +0300598 if (ptr_comphy_map->speed == COMPHY_SPEED_INVALID) {
Stefan Roesec0132f62016-08-30 16:48:20 +0200599 debug("Warning: SGMII PHY speed in lane %d is invalid, set PHY speed to 1.25G\n",
600 lane);
Igal Liberman2dbba242017-04-26 15:40:00 +0300601 ptr_comphy_map->speed = COMPHY_SPEED_1_25G;
Stefan Roesec0132f62016-08-30 16:48:20 +0200602 }
Grzegorz Jaszczykb24bb992020-10-18 17:11:11 +0300603
Igal Liberman5f41aaf2018-05-09 18:50:29 +0300604 mode = COMPHY_FW_FORMAT(COMPHY_SGMII_MODE, id,
Grzegorz Jaszczykb24bb992020-10-18 17:11:11 +0300605 ptr_comphy_map->speed);
606 ret = comphy_smc(MV_SIP_COMPHY_POWER_ON,
607 ptr_chip_cfg->comphy_base_addr, lane,
608 mode);
Stefan Roesec0132f62016-08-30 16:48:20 +0200609 break;
Igal Liberman2dbba242017-04-26 15:40:00 +0300610 case COMPHY_TYPE_SFI:
Grzegorz Jaszczykb24bb992020-10-18 17:11:11 +0300611 mode = COMPHY_FW_FORMAT(COMPHY_SFI_MODE,
612 COMPHY_UNIT_ID0,
613 ptr_comphy_map->speed);
614 ret = comphy_smc(MV_SIP_COMPHY_POWER_ON,
615 ptr_chip_cfg->comphy_base_addr, lane,
616 mode);
Stefan Roesec0132f62016-08-30 16:48:20 +0200617 break;
Igal Liberman2dbba242017-04-26 15:40:00 +0300618 case COMPHY_TYPE_RXAUI0:
619 case COMPHY_TYPE_RXAUI1:
Grzegorz Jaszczyk26d97632018-03-27 12:52:24 +0200620 mode = COMPHY_FW_MODE_FORMAT(COMPHY_RXAUI_MODE);
621 ret = comphy_smc(MV_SIP_COMPHY_POWER_ON,
622 ptr_chip_cfg->comphy_base_addr, lane,
623 mode);
Stefan Roesec0132f62016-08-30 16:48:20 +0200624 break;
625 default:
626 debug("Unknown SerDes type, skip initialize SerDes %d\n",
627 lane);
628 break;
629 }
630 if (ret == 0) {
631 /*
Stefan Roesed37f0202017-04-24 18:45:25 +0300632 * If interface wans't initialized, set the lane to
Igal Liberman2dbba242017-04-26 15:40:00 +0300633 * COMPHY_TYPE_UNCONNECTED state.
Stefan Roesec0132f62016-08-30 16:48:20 +0200634 */
Igal Liberman2dbba242017-04-26 15:40:00 +0300635 ptr_comphy_map->type = COMPHY_TYPE_UNCONNECTED;
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900636 pr_err("PLL is not locked - Failed to initialize lane %d\n",
Stefan Roesec0132f62016-08-30 16:48:20 +0200637 lane);
638 }
639 }
640
641 debug_exit();
642 return 0;
643}