1 /*
2  * Copyright 2015 Freescale Semiconductor, Inc.
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <asm/io.h>
9 #include <linux/errno.h>
10 #include <asm/arch/fsl_serdes.h>
11 #include <asm/arch/soc.h>
12 
13 #ifdef CONFIG_SYS_FSL_SRDS_1
14 static u8 serdes1_prtcl_map[SERDES_PRCTL_COUNT];
15 #endif
16 #ifdef CONFIG_SYS_FSL_SRDS_2
17 static u8 serdes2_prtcl_map[SERDES_PRCTL_COUNT];
18 #endif
19 
20 int is_serdes_configured(enum srds_prtcl device)
21 {
22 	int ret = 0;
23 
24 #ifdef CONFIG_SYS_FSL_SRDS_1
25 	if (!serdes1_prtcl_map[NONE])
26 		fsl_serdes_init();
27 
28 	ret |= serdes1_prtcl_map[device];
29 #endif
30 #ifdef CONFIG_SYS_FSL_SRDS_2
31 	if (!serdes2_prtcl_map[NONE])
32 		fsl_serdes_init();
33 
34 	ret |= serdes2_prtcl_map[device];
35 #endif
36 
37 	return !!ret;
38 }
39 
40 int serdes_get_first_lane(u32 sd, enum srds_prtcl device)
41 {
42 	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
43 	u32 cfg = gur_in32(&gur->rcwsr[4]);
44 	int i;
45 
46 	switch (sd) {
47 #ifdef CONFIG_SYS_FSL_SRDS_1
48 	case FSL_SRDS_1:
49 		cfg &= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK;
50 		cfg >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT;
51 		break;
52 #endif
53 #ifdef CONFIG_SYS_FSL_SRDS_2
54 	case FSL_SRDS_2:
55 		cfg &= FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_MASK;
56 		cfg >>= FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_SHIFT;
57 		break;
58 #endif
59 	default:
60 		printf("invalid SerDes%d\n", sd);
61 		break;
62 	}
63 
64 	/* Is serdes enabled at all? */
65 	if (unlikely(cfg == 0))
66 		return -ENODEV;
67 
68 	for (i = 0; i < SRDS_MAX_LANES; i++) {
69 		if (serdes_get_prtcl(sd, cfg, i) == device)
70 			return i;
71 	}
72 
73 	return -ENODEV;
74 }
75 
76 int get_serdes_protocol(void)
77 {
78 	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
79 	u32 cfg = gur_in32(&gur->rcwsr[4]) &
80 			  FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK;
81 	cfg >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT;
82 
83 	return cfg;
84 }
85 
86 const char *serdes_clock_to_string(u32 clock)
87 {
88 	switch (clock) {
89 	case SRDS_PLLCR0_RFCK_SEL_100:
90 		return "100";
91 	case SRDS_PLLCR0_RFCK_SEL_125:
92 		return "125";
93 	case SRDS_PLLCR0_RFCK_SEL_156_25:
94 		return "156.25";
95 	default:
96 		return "100";
97 	}
98 }
99 
100 void serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift,
101 		 u8 serdes_prtcl_map[SERDES_PRCTL_COUNT])
102 {
103 	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
104 	u32 cfg;
105 	int lane;
106 
107 	if (serdes_prtcl_map[NONE])
108 		return;
109 
110 	memset(serdes_prtcl_map, 0, sizeof(u8) * SERDES_PRCTL_COUNT);
111 
112 	cfg = gur_in32(&gur->rcwsr[4]) & sd_prctl_mask;
113 	cfg >>= sd_prctl_shift;
114 	printf("Using SERDES%d Protocol: %d (0x%x)\n", sd + 1, cfg, cfg);
115 
116 	if (!is_serdes_prtcl_valid(sd, cfg))
117 		printf("SERDES%d[PRTCL] = 0x%x is not valid\n", sd + 1, cfg);
118 
119 	for (lane = 0; lane < SRDS_MAX_LANES; lane++) {
120 		enum srds_prtcl lane_prtcl = serdes_get_prtcl(sd, cfg, lane);
121 
122 		if (unlikely(lane_prtcl >= SERDES_PRCTL_COUNT))
123 			debug("Unknown SerDes lane protocol %d\n", lane_prtcl);
124 		else
125 			serdes_prtcl_map[lane_prtcl] = 1;
126 	}
127 
128 	/* Set the first element to indicate serdes has been initialized */
129 	serdes_prtcl_map[NONE] = 1;
130 }
131 
132 void fsl_serdes_init(void)
133 {
134 #ifdef CONFIG_SYS_FSL_SRDS_1
135 	serdes_init(FSL_SRDS_1,
136 		    CONFIG_SYS_FSL_SERDES_ADDR,
137 		    FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK,
138 		    FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT,
139 		    serdes1_prtcl_map);
140 #endif
141 #ifdef CONFIG_SYS_FSL_SRDS_2
142 	serdes_init(FSL_SRDS_2,
143 		    CONFIG_SYS_FSL_SERDES_ADDR,
144 		    FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_MASK,
145 		    FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_SHIFT,
146 		    serdes2_prtcl_map);
147 #endif
148 }
149