fsl: serdes: ensure accessing the initialized maps of serdes protocol
[platform/kernel/u-boot.git] / arch / arm / cpu / armv7 / ls102xa / fsl_ls1_serdes.c
1 /*
2  * Copyright 2014 Freescale Semiconductor, Inc.
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6
7 #include <common.h>
8 #include <asm/arch/fsl_serdes.h>
9 #include <asm/arch/immap_ls102xa.h>
10 #include <asm/errno.h>
11 #include <asm/io.h>
12 #include "fsl_ls1_serdes.h"
13
14 #ifdef CONFIG_SYS_FSL_SRDS_1
15 static u64 serdes1_prtcl_map;
16 #endif
17 #ifdef CONFIG_SYS_FSL_SRDS_2
18 static u64 serdes2_prtcl_map;
19 #endif
20
21 int is_serdes_configured(enum srds_prtcl device)
22 {
23         u64 ret = 0;
24
25 #ifdef CONFIG_SYS_FSL_SRDS_1
26         if (!(serdes1_prtcl_map & (1ULL << NONE)))
27                 fsl_serdes_init();
28
29         ret |= (1ULL << device) & serdes1_prtcl_map;
30 #endif
31 #ifdef CONFIG_SYS_FSL_SRDS_2
32         if (!(serdes2_prtcl_map & (1ULL << NONE)))
33                 fsl_serdes_init();
34
35         ret |= (1ULL << device) & serdes2_prtcl_map;
36 #endif
37
38         return !!ret;
39 }
40
41 int serdes_get_first_lane(u32 sd, enum srds_prtcl device)
42 {
43         struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
44         u32 cfg = in_be32(&gur->rcwsr[4]);
45         int i;
46
47         switch (sd) {
48 #ifdef CONFIG_SYS_FSL_SRDS_1
49         case FSL_SRDS_1:
50                 cfg &= RCWSR4_SRDS1_PRTCL_MASK;
51                 cfg >>= RCWSR4_SRDS1_PRTCL_SHIFT;
52                 break;
53 #endif
54 #ifdef CONFIG_SYS_FSL_SRDS_2
55         case FSL_SRDS_2:
56                 cfg &= RCWSR4_SRDS2_PRTCL_MASK;
57                 cfg >>= RCWSR4_SRDS2_PRTCL_SHIFT;
58                 break;
59 #endif
60         default:
61                 printf("invalid SerDes%d\n", sd);
62                 break;
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 u64 serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift)
77 {
78         struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
79         u64 serdes_prtcl_map = 0;
80         u32 cfg;
81         int lane;
82
83         cfg = in_be32(&gur->rcwsr[4]) & sd_prctl_mask;
84         cfg >>= sd_prctl_shift;
85         printf("Using SERDES%d Protocol: %d (0x%x)\n", sd + 1, cfg, cfg);
86
87         if (!is_serdes_prtcl_valid(sd, cfg))
88                 printf("SERDES%d[PRTCL] = 0x%x is not valid\n", sd + 1, cfg);
89
90         for (lane = 0; lane < SRDS_MAX_LANES; lane++) {
91                 enum srds_prtcl lane_prtcl = serdes_get_prtcl(sd, cfg, lane);
92
93                 serdes_prtcl_map |= (1ULL << lane_prtcl);
94         }
95
96         /* Set the first bit to indicate serdes has been initialized */
97         serdes_prtcl_map |= (1ULL << NONE);
98
99         return serdes_prtcl_map;
100 }
101
102 void fsl_serdes_init(void)
103 {
104 #ifdef CONFIG_SYS_FSL_SRDS_1
105         if (!(serdes1_prtcl_map & (1ULL << NONE)))
106                 serdes1_prtcl_map = serdes_init(FSL_SRDS_1,
107                                         CONFIG_SYS_FSL_SERDES_ADDR,
108                                         RCWSR4_SRDS1_PRTCL_MASK,
109                                         RCWSR4_SRDS1_PRTCL_SHIFT);
110 #endif
111 #ifdef CONFIG_SYS_FSL_SRDS_2
112         if (!(serdes2_prtcl_map & (1ULL << NONE)))
113                 serdes2_prtcl_map = serdes_init(FSL_SRDS_2,
114                                         CONFIG_SYS_FSL_SERDES_ADDR +
115                                         FSL_SRDS_2 * 0x1000,
116                                         RCWSR4_SRDS2_PRTCL_MASK,
117                                         RCWSR4_SRDS2_PRTCL_SHIFT);
118 #endif
119 }
120
121 const char *serdes_clock_to_string(u32 clock)
122 {
123         switch (clock) {
124         case SRDS_PLLCR0_RFCK_SEL_100:
125                 return "100";
126         case SRDS_PLLCR0_RFCK_SEL_125:
127                 return "125";
128         default:
129                 return "100";
130         }
131 }