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