1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2a47a12beSStefan Roese /*
36ab4011bSKumar Gala * Copyright 2008,2010 Freescale Semiconductor, Inc.
4a47a12beSStefan Roese * Dave Liu <daveliu@freescale.com>
5a47a12beSStefan Roese */
6a47a12beSStefan Roese
7a47a12beSStefan Roese #include <config.h>
8a47a12beSStefan Roese #include <common.h>
9a47a12beSStefan Roese #include <asm/io.h>
10a47a12beSStefan Roese #include <asm/immap_85xx.h>
116ab4011bSKumar Gala #include <asm/fsl_serdes.h>
12a47a12beSStefan Roese
13a47a12beSStefan Roese /* PORDEVSR register */
14a47a12beSStefan Roese #define GUTS_PORDEVSR_OFFS 0xc
15a47a12beSStefan Roese #define GUTS_PORDEVSR_SERDES2_IO_SEL 0x38000000
16a47a12beSStefan Roese #define GUTS_PORDEVSR_SERDES2_IO_SEL_SHIFT 27
17a47a12beSStefan Roese
18a47a12beSStefan Roese /* SerDes CR0 register */
19a47a12beSStefan Roese #define FSL_SRDSCR0_OFFS 0x0
20a47a12beSStefan Roese #define FSL_SRDSCR0_TXEQA_MASK 0x00007000
21a47a12beSStefan Roese #define FSL_SRDSCR0_TXEQA_SGMII 0x00004000
22a47a12beSStefan Roese #define FSL_SRDSCR0_TXEQA_SATA 0x00001000
23a47a12beSStefan Roese #define FSL_SRDSCR0_TXEQE_MASK 0x00000700
24a47a12beSStefan Roese #define FSL_SRDSCR0_TXEQE_SGMII 0x00000400
25a47a12beSStefan Roese #define FSL_SRDSCR0_TXEQE_SATA 0x00000100
26a47a12beSStefan Roese
27a47a12beSStefan Roese /* SerDes CR1 register */
28a47a12beSStefan Roese #define FSL_SRDSCR1_OFFS 0x4
29a47a12beSStefan Roese #define FSL_SRDSCR1_LANEA_MASK 0x80200000
30a47a12beSStefan Roese #define FSL_SRDSCR1_LANEA_OFF 0x80200000
31a47a12beSStefan Roese #define FSL_SRDSCR1_LANEE_MASK 0x08020000
32a47a12beSStefan Roese #define FSL_SRDSCR1_LANEE_OFF 0x08020000
33a47a12beSStefan Roese
34a47a12beSStefan Roese /* SerDes CR2 register */
35a47a12beSStefan Roese #define FSL_SRDSCR2_OFFS 0x8
36a47a12beSStefan Roese #define FSL_SRDSCR2_EICA_MASK 0x00001f00
37a47a12beSStefan Roese #define FSL_SRDSCR2_EICA_SGMII 0x00000400
38a47a12beSStefan Roese #define FSL_SRDSCR2_EICA_SATA 0x00001400
39a47a12beSStefan Roese #define FSL_SRDSCR2_EICE_MASK 0x0000001f
40a47a12beSStefan Roese #define FSL_SRDSCR2_EICE_SGMII 0x00000004
41a47a12beSStefan Roese #define FSL_SRDSCR2_EICE_SATA 0x00000014
42a47a12beSStefan Roese
43a47a12beSStefan Roese /* SerDes CR3 register */
44a47a12beSStefan Roese #define FSL_SRDSCR3_OFFS 0xc
45a47a12beSStefan Roese #define FSL_SRDSCR3_LANEA_MASK 0x3f000700
46a47a12beSStefan Roese #define FSL_SRDSCR3_LANEA_SGMII 0x00000000
47a47a12beSStefan Roese #define FSL_SRDSCR3_LANEA_SATA 0x15000500
48a47a12beSStefan Roese #define FSL_SRDSCR3_LANEE_MASK 0x003f0007
49a47a12beSStefan Roese #define FSL_SRDSCR3_LANEE_SGMII 0x00000000
50a47a12beSStefan Roese #define FSL_SRDSCR3_LANEE_SATA 0x00150005
51a47a12beSStefan Roese
526ab4011bSKumar Gala #define SRDS1_MAX_LANES 8
536ab4011bSKumar Gala #define SRDS2_MAX_LANES 2
546ab4011bSKumar Gala
55af025065SKumar Gala static u32 serdes1_prtcl_map, serdes2_prtcl_map;
56af025065SKumar Gala
576ab4011bSKumar Gala static u8 serdes1_cfg_tbl[][SRDS1_MAX_LANES] = {
586ab4011bSKumar Gala [0x2] = {PCIE1, PCIE1, PCIE1, PCIE1, NONE, NONE, NONE, NONE},
596ab4011bSKumar Gala [0x3] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1},
606ab4011bSKumar Gala [0x5] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2},
616ab4011bSKumar Gala [0x7] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE3, PCIE3},
626ab4011bSKumar Gala };
636ab4011bSKumar Gala
646ab4011bSKumar Gala static u8 serdes2_cfg_tbl[][SRDS2_MAX_LANES] = {
656ab4011bSKumar Gala [0x1] = {SATA1, SATA2},
666ab4011bSKumar Gala [0x3] = {SATA1, NONE},
676ab4011bSKumar Gala [0x4] = {SGMII_TSEC1, SGMII_TSEC3},
686ab4011bSKumar Gala [0x6] = {SGMII_TSEC1, NONE},
696ab4011bSKumar Gala };
706ab4011bSKumar Gala
is_serdes_configured(enum srds_prtcl device)716ab4011bSKumar Gala int is_serdes_configured(enum srds_prtcl device)
726ab4011bSKumar Gala {
7371fe2225SHou Zhiqiang int ret;
7471fe2225SHou Zhiqiang
7571fe2225SHou Zhiqiang if (!(serdes1_prtcl_map & (1 << NONE)))
7671fe2225SHou Zhiqiang fsl_serdes_init();
7771fe2225SHou Zhiqiang
7871fe2225SHou Zhiqiang ret = (1 << device) & serdes1_prtcl_map;
796ab4011bSKumar Gala
80af025065SKumar Gala if (ret)
81af025065SKumar Gala return ret;
826ab4011bSKumar Gala
8371fe2225SHou Zhiqiang if (!(serdes2_prtcl_map & (1 << NONE)))
8471fe2225SHou Zhiqiang fsl_serdes_init();
8571fe2225SHou Zhiqiang
86af025065SKumar Gala return (1 << device) & serdes2_prtcl_map;
876ab4011bSKumar Gala }
886ab4011bSKumar Gala
fsl_serdes_init(void)89a47a12beSStefan Roese void fsl_serdes_init(void)
90a47a12beSStefan Roese {
91a47a12beSStefan Roese void *guts = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
92a47a12beSStefan Roese void *sd = (void *)CONFIG_SYS_MPC85xx_SERDES2_ADDR;
93a47a12beSStefan Roese u32 pordevsr = in_be32(guts + GUTS_PORDEVSR_OFFS);
94af025065SKumar Gala u32 srds1_io_sel, srds2_io_sel;
95a47a12beSStefan Roese u32 tmp;
96af025065SKumar Gala int lane;
97af025065SKumar Gala
9871fe2225SHou Zhiqiang if (serdes1_prtcl_map & (1 << NONE) &&
9971fe2225SHou Zhiqiang serdes2_prtcl_map & (1 << NONE))
10071fe2225SHou Zhiqiang return;
10171fe2225SHou Zhiqiang
102af025065SKumar Gala srds1_io_sel = (pordevsr & MPC85xx_PORDEVSR_IO_SEL) >>
103af025065SKumar Gala MPC85xx_PORDEVSR_IO_SEL_SHIFT;
104a47a12beSStefan Roese
105a47a12beSStefan Roese /* parse the SRDS2_IO_SEL of PORDEVSR */
106a47a12beSStefan Roese srds2_io_sel = (pordevsr & GUTS_PORDEVSR_SERDES2_IO_SEL)
107a47a12beSStefan Roese >> GUTS_PORDEVSR_SERDES2_IO_SEL_SHIFT;
108a47a12beSStefan Roese
109af025065SKumar Gala debug("PORDEVSR[SRDS1_IO_SEL] = %x\n", srds1_io_sel);
110af025065SKumar Gala debug("PORDEVSR[SRDS2_IO_SEL] = %x\n", srds2_io_sel);
111af025065SKumar Gala
112a47a12beSStefan Roese switch (srds2_io_sel) {
113a47a12beSStefan Roese case 1: /* Lane A - SATA1, Lane E - SATA2 */
114a47a12beSStefan Roese /* CR 0 */
115a47a12beSStefan Roese tmp = in_be32(sd + FSL_SRDSCR0_OFFS);
116a47a12beSStefan Roese tmp &= ~FSL_SRDSCR0_TXEQA_MASK;
117a47a12beSStefan Roese tmp |= FSL_SRDSCR0_TXEQA_SATA;
118a47a12beSStefan Roese tmp &= ~FSL_SRDSCR0_TXEQE_MASK;
119a47a12beSStefan Roese tmp |= FSL_SRDSCR0_TXEQE_SATA;
120a47a12beSStefan Roese out_be32(sd + FSL_SRDSCR0_OFFS, tmp);
121a47a12beSStefan Roese /* CR 1 */
122a47a12beSStefan Roese tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
123a47a12beSStefan Roese tmp &= ~FSL_SRDSCR1_LANEA_MASK;
124a47a12beSStefan Roese tmp &= ~FSL_SRDSCR1_LANEE_MASK;
125a47a12beSStefan Roese out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
126a47a12beSStefan Roese /* CR 2 */
127a47a12beSStefan Roese tmp = in_be32(sd + FSL_SRDSCR2_OFFS);
128a47a12beSStefan Roese tmp &= ~FSL_SRDSCR2_EICA_MASK;
129a47a12beSStefan Roese tmp |= FSL_SRDSCR2_EICA_SATA;
130a47a12beSStefan Roese tmp &= ~FSL_SRDSCR2_EICE_MASK;
131a47a12beSStefan Roese tmp |= FSL_SRDSCR2_EICE_SATA;
132a47a12beSStefan Roese out_be32(sd + FSL_SRDSCR2_OFFS, tmp);
133a47a12beSStefan Roese /* CR 3 */
134a47a12beSStefan Roese tmp = in_be32(sd + FSL_SRDSCR3_OFFS);
135a47a12beSStefan Roese tmp &= ~FSL_SRDSCR3_LANEA_MASK;
136a47a12beSStefan Roese tmp |= FSL_SRDSCR3_LANEA_SATA;
137a47a12beSStefan Roese tmp &= ~FSL_SRDSCR3_LANEE_MASK;
138a47a12beSStefan Roese tmp |= FSL_SRDSCR3_LANEE_SATA;
139a47a12beSStefan Roese out_be32(sd + FSL_SRDSCR3_OFFS, tmp);
140a47a12beSStefan Roese break;
141a47a12beSStefan Roese case 3: /* Lane A - SATA1, Lane E - disabled */
142a47a12beSStefan Roese /* CR 0 */
143a47a12beSStefan Roese tmp = in_be32(sd + FSL_SRDSCR0_OFFS);
144a47a12beSStefan Roese tmp &= ~FSL_SRDSCR0_TXEQA_MASK;
145a47a12beSStefan Roese tmp |= FSL_SRDSCR0_TXEQA_SATA;
146a47a12beSStefan Roese out_be32(sd + FSL_SRDSCR0_OFFS, tmp);
147a47a12beSStefan Roese /* CR 1 */
148a47a12beSStefan Roese tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
149a47a12beSStefan Roese tmp &= ~FSL_SRDSCR1_LANEE_MASK;
150a47a12beSStefan Roese tmp |= FSL_SRDSCR1_LANEE_OFF;
151a47a12beSStefan Roese out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
152a47a12beSStefan Roese /* CR 2 */
153a47a12beSStefan Roese tmp = in_be32(sd + FSL_SRDSCR2_OFFS);
154a47a12beSStefan Roese tmp &= ~FSL_SRDSCR2_EICA_MASK;
155a47a12beSStefan Roese tmp |= FSL_SRDSCR2_EICA_SATA;
156a47a12beSStefan Roese out_be32(sd + FSL_SRDSCR2_OFFS, tmp);
157a47a12beSStefan Roese /* CR 3 */
158a47a12beSStefan Roese tmp = in_be32(sd + FSL_SRDSCR3_OFFS);
159a47a12beSStefan Roese tmp &= ~FSL_SRDSCR3_LANEA_MASK;
160a47a12beSStefan Roese tmp |= FSL_SRDSCR3_LANEA_SATA;
161a47a12beSStefan Roese out_be32(sd + FSL_SRDSCR3_OFFS, tmp);
162a47a12beSStefan Roese break;
163a47a12beSStefan Roese case 4: /* Lane A - eTSEC1 SGMII, Lane E - eTSEC3 SGMII */
164a47a12beSStefan Roese /* CR 0 */
165a47a12beSStefan Roese tmp = in_be32(sd + FSL_SRDSCR0_OFFS);
166a47a12beSStefan Roese tmp &= ~FSL_SRDSCR0_TXEQA_MASK;
167a47a12beSStefan Roese tmp |= FSL_SRDSCR0_TXEQA_SGMII;
168a47a12beSStefan Roese tmp &= ~FSL_SRDSCR0_TXEQE_MASK;
169a47a12beSStefan Roese tmp |= FSL_SRDSCR0_TXEQE_SGMII;
170a47a12beSStefan Roese out_be32(sd + FSL_SRDSCR0_OFFS, tmp);
171a47a12beSStefan Roese /* CR 1 */
172a47a12beSStefan Roese tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
173a47a12beSStefan Roese tmp &= ~FSL_SRDSCR1_LANEA_MASK;
174a47a12beSStefan Roese tmp &= ~FSL_SRDSCR1_LANEE_MASK;
175a47a12beSStefan Roese out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
176a47a12beSStefan Roese /* CR 2 */
177a47a12beSStefan Roese tmp = in_be32(sd + FSL_SRDSCR2_OFFS);
178a47a12beSStefan Roese tmp &= ~FSL_SRDSCR2_EICA_MASK;
179a47a12beSStefan Roese tmp |= FSL_SRDSCR2_EICA_SGMII;
180a47a12beSStefan Roese tmp &= ~FSL_SRDSCR2_EICE_MASK;
181a47a12beSStefan Roese tmp |= FSL_SRDSCR2_EICE_SGMII;
182a47a12beSStefan Roese out_be32(sd + FSL_SRDSCR2_OFFS, tmp);
183a47a12beSStefan Roese /* CR 3 */
184a47a12beSStefan Roese tmp = in_be32(sd + FSL_SRDSCR3_OFFS);
185a47a12beSStefan Roese tmp &= ~FSL_SRDSCR3_LANEA_MASK;
186a47a12beSStefan Roese tmp |= FSL_SRDSCR3_LANEA_SGMII;
187a47a12beSStefan Roese tmp &= ~FSL_SRDSCR3_LANEE_MASK;
188a47a12beSStefan Roese tmp |= FSL_SRDSCR3_LANEE_SGMII;
189a47a12beSStefan Roese out_be32(sd + FSL_SRDSCR3_OFFS, tmp);
190a47a12beSStefan Roese break;
191a47a12beSStefan Roese case 6: /* Lane A - eTSEC1 SGMII, Lane E - disabled */
192a47a12beSStefan Roese /* CR 0 */
193a47a12beSStefan Roese tmp = in_be32(sd + FSL_SRDSCR0_OFFS);
194a47a12beSStefan Roese tmp &= ~FSL_SRDSCR0_TXEQA_MASK;
195a47a12beSStefan Roese tmp |= FSL_SRDSCR0_TXEQA_SGMII;
196a47a12beSStefan Roese out_be32(sd + FSL_SRDSCR0_OFFS, tmp);
197a47a12beSStefan Roese /* CR 1 */
198a47a12beSStefan Roese tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
199a47a12beSStefan Roese tmp &= ~FSL_SRDSCR1_LANEE_MASK;
200a47a12beSStefan Roese tmp |= FSL_SRDSCR1_LANEE_OFF;
201a47a12beSStefan Roese out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
202a47a12beSStefan Roese /* CR 2 */
203a47a12beSStefan Roese tmp = in_be32(sd + FSL_SRDSCR2_OFFS);
204a47a12beSStefan Roese tmp &= ~FSL_SRDSCR2_EICA_MASK;
205a47a12beSStefan Roese tmp |= FSL_SRDSCR2_EICA_SGMII;
206a47a12beSStefan Roese out_be32(sd + FSL_SRDSCR2_OFFS, tmp);
207a47a12beSStefan Roese /* CR 3 */
208a47a12beSStefan Roese tmp = in_be32(sd + FSL_SRDSCR3_OFFS);
209a47a12beSStefan Roese tmp &= ~FSL_SRDSCR3_LANEA_MASK;
210a47a12beSStefan Roese tmp |= FSL_SRDSCR3_LANEA_SGMII;
211a47a12beSStefan Roese out_be32(sd + FSL_SRDSCR3_OFFS, tmp);
212a47a12beSStefan Roese break;
213a47a12beSStefan Roese case 7: /* Lane A - disabled, Lane E - disabled */
214a47a12beSStefan Roese /* CR 1 */
215a47a12beSStefan Roese tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
216a47a12beSStefan Roese tmp &= ~FSL_SRDSCR1_LANEA_MASK;
217a47a12beSStefan Roese tmp |= FSL_SRDSCR1_LANEA_OFF;
218a47a12beSStefan Roese tmp &= ~FSL_SRDSCR1_LANEE_MASK;
219a47a12beSStefan Roese tmp |= FSL_SRDSCR1_LANEE_OFF;
220a47a12beSStefan Roese out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
221a47a12beSStefan Roese break;
222a47a12beSStefan Roese default:
223a47a12beSStefan Roese break;
224a47a12beSStefan Roese }
225af025065SKumar Gala
226e51e47d3SAxel Lin if (srds1_io_sel >= ARRAY_SIZE(serdes1_cfg_tbl)) {
227af025065SKumar Gala printf("Invalid PORDEVSR[SRDS1_IO_SEL] = %d\n", srds1_io_sel);
228af025065SKumar Gala return;
229af025065SKumar Gala }
230af025065SKumar Gala for (lane = 0; lane < SRDS1_MAX_LANES; lane++) {
231af025065SKumar Gala enum srds_prtcl lane_prtcl = serdes1_cfg_tbl[srds1_io_sel][lane];
232af025065SKumar Gala serdes1_prtcl_map |= (1 << lane_prtcl);
233af025065SKumar Gala }
234af025065SKumar Gala
23571fe2225SHou Zhiqiang /* Set the first bit to indicate serdes has been initialized */
23671fe2225SHou Zhiqiang serdes1_prtcl_map |= (1 << NONE);
23771fe2225SHou Zhiqiang
238e51e47d3SAxel Lin if (srds2_io_sel >= ARRAY_SIZE(serdes2_cfg_tbl)) {
239af025065SKumar Gala printf("Invalid PORDEVSR[SRDS2_IO_SEL] = %d\n", srds2_io_sel);
240af025065SKumar Gala return;
241af025065SKumar Gala }
242af025065SKumar Gala
243af025065SKumar Gala for (lane = 0; lane < SRDS2_MAX_LANES; lane++) {
244af025065SKumar Gala enum srds_prtcl lane_prtcl = serdes2_cfg_tbl[srds2_io_sel][lane];
245af025065SKumar Gala serdes2_prtcl_map |= (1 << lane_prtcl);
246af025065SKumar Gala }
24771fe2225SHou Zhiqiang
24871fe2225SHou Zhiqiang /* Set the first bit to indicate serdes has been initialized */
24971fe2225SHou Zhiqiang serdes2_prtcl_map |= (1 << NONE);
250a47a12beSStefan Roese }
251