1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2d60a2099SWang Huan /*
3d60a2099SWang Huan  * Copyright 2014 Freescale Semiconductor, Inc.
4d60a2099SWang Huan  */
5d60a2099SWang Huan 
6d60a2099SWang Huan #include <common.h>
7d60a2099SWang Huan #include <asm/arch/fsl_serdes.h>
8d60a2099SWang Huan #include <asm/arch/immap_ls102xa.h>
91221ce45SMasahiro Yamada #include <linux/errno.h>
10d60a2099SWang Huan #include <asm/io.h>
11d60a2099SWang Huan #include "fsl_ls1_serdes.h"
12d60a2099SWang Huan 
13d60a2099SWang Huan #ifdef CONFIG_SYS_FSL_SRDS_1
14d60a2099SWang Huan static u64 serdes1_prtcl_map;
15d60a2099SWang Huan #endif
16d60a2099SWang Huan #ifdef CONFIG_SYS_FSL_SRDS_2
17d60a2099SWang Huan static u64 serdes2_prtcl_map;
18d60a2099SWang Huan #endif
19d60a2099SWang Huan 
is_serdes_configured(enum srds_prtcl device)20d60a2099SWang Huan int is_serdes_configured(enum srds_prtcl device)
21d60a2099SWang Huan {
22d60a2099SWang Huan 	u64 ret = 0;
23d60a2099SWang Huan 
24d60a2099SWang Huan #ifdef CONFIG_SYS_FSL_SRDS_1
2571fe2225SHou Zhiqiang 	if (!(serdes1_prtcl_map & (1ULL << NONE)))
2671fe2225SHou Zhiqiang 		fsl_serdes_init();
2771fe2225SHou Zhiqiang 
28d60a2099SWang Huan 	ret |= (1ULL << device) & serdes1_prtcl_map;
29d60a2099SWang Huan #endif
30d60a2099SWang Huan #ifdef CONFIG_SYS_FSL_SRDS_2
3171fe2225SHou Zhiqiang 	if (!(serdes2_prtcl_map & (1ULL << NONE)))
3271fe2225SHou Zhiqiang 		fsl_serdes_init();
3371fe2225SHou Zhiqiang 
34d60a2099SWang Huan 	ret |= (1ULL << device) & serdes2_prtcl_map;
35d60a2099SWang Huan #endif
36d60a2099SWang Huan 
37d60a2099SWang Huan 	return !!ret;
38d60a2099SWang Huan }
39d60a2099SWang Huan 
serdes_get_first_lane(u32 sd,enum srds_prtcl device)40d60a2099SWang Huan int serdes_get_first_lane(u32 sd, enum srds_prtcl device)
41d60a2099SWang Huan {
42d60a2099SWang Huan 	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
43d60a2099SWang Huan 	u32 cfg = in_be32(&gur->rcwsr[4]);
44d60a2099SWang Huan 	int i;
45d60a2099SWang Huan 
46d60a2099SWang Huan 	switch (sd) {
47d60a2099SWang Huan #ifdef CONFIG_SYS_FSL_SRDS_1
48d60a2099SWang Huan 	case FSL_SRDS_1:
49d60a2099SWang Huan 		cfg &= RCWSR4_SRDS1_PRTCL_MASK;
50d60a2099SWang Huan 		cfg >>= RCWSR4_SRDS1_PRTCL_SHIFT;
51d60a2099SWang Huan 		break;
52d60a2099SWang Huan #endif
53d60a2099SWang Huan #ifdef CONFIG_SYS_FSL_SRDS_2
54d60a2099SWang Huan 	case FSL_SRDS_2:
55d60a2099SWang Huan 		cfg &= RCWSR4_SRDS2_PRTCL_MASK;
56d60a2099SWang Huan 		cfg >>= RCWSR4_SRDS2_PRTCL_SHIFT;
57d60a2099SWang Huan 		break;
58d60a2099SWang Huan #endif
59d60a2099SWang Huan 	default:
60d60a2099SWang Huan 		printf("invalid SerDes%d\n", sd);
61d60a2099SWang Huan 		break;
62d60a2099SWang Huan 	}
63d60a2099SWang Huan 	/* Is serdes enabled at all? */
64d60a2099SWang Huan 	if (unlikely(cfg == 0))
65d60a2099SWang Huan 		return -ENODEV;
66d60a2099SWang Huan 
67d60a2099SWang Huan 	for (i = 0; i < SRDS_MAX_LANES; i++) {
68d60a2099SWang Huan 		if (serdes_get_prtcl(sd, cfg, i) == device)
69d60a2099SWang Huan 			return i;
70d60a2099SWang Huan 	}
71d60a2099SWang Huan 
72d60a2099SWang Huan 	return -ENODEV;
73d60a2099SWang Huan }
74d60a2099SWang Huan 
serdes_init(u32 sd,u32 sd_addr,u32 sd_prctl_mask,u32 sd_prctl_shift)75d60a2099SWang Huan u64 serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift)
76d60a2099SWang Huan {
77d60a2099SWang Huan 	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
78d60a2099SWang Huan 	u64 serdes_prtcl_map = 0;
79d60a2099SWang Huan 	u32 cfg;
80d60a2099SWang Huan 	int lane;
81d60a2099SWang Huan 
82d60a2099SWang Huan 	cfg = in_be32(&gur->rcwsr[4]) & sd_prctl_mask;
83d60a2099SWang Huan 	cfg >>= sd_prctl_shift;
84d60a2099SWang Huan 	printf("Using SERDES%d Protocol: %d (0x%x)\n", sd + 1, cfg, cfg);
85d60a2099SWang Huan 
86d60a2099SWang Huan 	if (!is_serdes_prtcl_valid(sd, cfg))
87d60a2099SWang Huan 		printf("SERDES%d[PRTCL] = 0x%x is not valid\n", sd + 1, cfg);
88d60a2099SWang Huan 
89d60a2099SWang Huan 	for (lane = 0; lane < SRDS_MAX_LANES; lane++) {
90d60a2099SWang Huan 		enum srds_prtcl lane_prtcl = serdes_get_prtcl(sd, cfg, lane);
91d60a2099SWang Huan 
92d60a2099SWang Huan 		serdes_prtcl_map |= (1ULL << lane_prtcl);
93d60a2099SWang Huan 	}
94d60a2099SWang Huan 
9571fe2225SHou Zhiqiang 	/* Set the first bit to indicate serdes has been initialized */
9671fe2225SHou Zhiqiang 	serdes_prtcl_map |= (1ULL << NONE);
9771fe2225SHou Zhiqiang 
98d60a2099SWang Huan 	return serdes_prtcl_map;
99d60a2099SWang Huan }
100d60a2099SWang Huan 
fsl_serdes_init(void)101d60a2099SWang Huan void fsl_serdes_init(void)
102d60a2099SWang Huan {
103d60a2099SWang Huan #ifdef CONFIG_SYS_FSL_SRDS_1
10471fe2225SHou Zhiqiang 	if (!(serdes1_prtcl_map & (1ULL << NONE)))
105d60a2099SWang Huan 		serdes1_prtcl_map = serdes_init(FSL_SRDS_1,
106d60a2099SWang Huan 					CONFIG_SYS_FSL_SERDES_ADDR,
107d60a2099SWang Huan 					RCWSR4_SRDS1_PRTCL_MASK,
108d60a2099SWang Huan 					RCWSR4_SRDS1_PRTCL_SHIFT);
109d60a2099SWang Huan #endif
110d60a2099SWang Huan #ifdef CONFIG_SYS_FSL_SRDS_2
11171fe2225SHou Zhiqiang 	if (!(serdes2_prtcl_map & (1ULL << NONE)))
112d60a2099SWang Huan 		serdes2_prtcl_map = serdes_init(FSL_SRDS_2,
113d60a2099SWang Huan 					CONFIG_SYS_FSL_SERDES_ADDR +
114d60a2099SWang Huan 					FSL_SRDS_2 * 0x1000,
115d60a2099SWang Huan 					RCWSR4_SRDS2_PRTCL_MASK,
116d60a2099SWang Huan 					RCWSR4_SRDS2_PRTCL_SHIFT);
117d60a2099SWang Huan #endif
118d60a2099SWang Huan }
119d60a2099SWang Huan 
serdes_clock_to_string(u32 clock)120d60a2099SWang Huan const char *serdes_clock_to_string(u32 clock)
121d60a2099SWang Huan {
122d60a2099SWang Huan 	switch (clock) {
123d60a2099SWang Huan 	case SRDS_PLLCR0_RFCK_SEL_100:
124d60a2099SWang Huan 		return "100";
125d60a2099SWang Huan 	case SRDS_PLLCR0_RFCK_SEL_125:
126d60a2099SWang Huan 		return "125";
127d60a2099SWang Huan 	default:
128d60a2099SWang Huan 		return "100";
129d60a2099SWang Huan 	}
130d60a2099SWang Huan }
131