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