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 <linux/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 } 132