1 /* 2 * Copyright (C) 2015 Freescale Semiconductor, Inc. All rights reserved. 3 * 4 * Authors: Zhao Qiang <qiang.zhao@nxp.com> 5 * 6 * Description: 7 * QE TDM API Set - TDM specific routines implementations. 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the 11 * Free Software Foundation; either version 2 of the License, or (at your 12 * option) any later version. 13 */ 14 #include <linux/io.h> 15 #include <linux/kernel.h> 16 #include <linux/of_address.h> 17 #include <linux/of_irq.h> 18 #include <linux/of_platform.h> 19 #include <soc/fsl/qe/qe_tdm.h> 20 21 static int set_tdm_framer(const char *tdm_framer_type) 22 { 23 if (strcmp(tdm_framer_type, "e1") == 0) 24 return TDM_FRAMER_E1; 25 else if (strcmp(tdm_framer_type, "t1") == 0) 26 return TDM_FRAMER_T1; 27 else 28 return -EINVAL; 29 } 30 31 static void set_si_param(struct ucc_tdm *utdm, struct ucc_tdm_info *ut_info) 32 { 33 struct si_mode_info *si_info = &ut_info->si_info; 34 35 if (utdm->tdm_mode == TDM_INTERNAL_LOOPBACK) { 36 si_info->simr_crt = 1; 37 si_info->simr_rfsd = 0; 38 } 39 } 40 41 int ucc_of_parse_tdm(struct device_node *np, struct ucc_tdm *utdm, 42 struct ucc_tdm_info *ut_info) 43 { 44 const char *sprop; 45 int ret = 0; 46 u32 val; 47 struct resource *res; 48 struct device_node *np2; 49 static int siram_init_flag; 50 struct platform_device *pdev; 51 52 sprop = of_get_property(np, "fsl,rx-sync-clock", NULL); 53 if (sprop) { 54 ut_info->uf_info.rx_sync = qe_clock_source(sprop); 55 if ((ut_info->uf_info.rx_sync < QE_CLK_NONE) || 56 (ut_info->uf_info.rx_sync > QE_RSYNC_PIN)) { 57 pr_err("QE-TDM: Invalid rx-sync-clock property\n"); 58 return -EINVAL; 59 } 60 } else { 61 pr_err("QE-TDM: Invalid rx-sync-clock property\n"); 62 return -EINVAL; 63 } 64 65 sprop = of_get_property(np, "fsl,tx-sync-clock", NULL); 66 if (sprop) { 67 ut_info->uf_info.tx_sync = qe_clock_source(sprop); 68 if ((ut_info->uf_info.tx_sync < QE_CLK_NONE) || 69 (ut_info->uf_info.tx_sync > QE_TSYNC_PIN)) { 70 pr_err("QE-TDM: Invalid tx-sync-clock property\n"); 71 return -EINVAL; 72 } 73 } else { 74 pr_err("QE-TDM: Invalid tx-sync-clock property\n"); 75 return -EINVAL; 76 } 77 78 ret = of_property_read_u32_index(np, "fsl,tx-timeslot-mask", 0, &val); 79 if (ret) { 80 pr_err("QE-TDM: Invalid tx-timeslot-mask property\n"); 81 return -EINVAL; 82 } 83 utdm->tx_ts_mask = val; 84 85 ret = of_property_read_u32_index(np, "fsl,rx-timeslot-mask", 0, &val); 86 if (ret) { 87 ret = -EINVAL; 88 pr_err("QE-TDM: Invalid rx-timeslot-mask property\n"); 89 return ret; 90 } 91 utdm->rx_ts_mask = val; 92 93 ret = of_property_read_u32_index(np, "fsl,tdm-id", 0, &val); 94 if (ret) { 95 ret = -EINVAL; 96 pr_err("QE-TDM: No fsl,tdm-id property for this UCC\n"); 97 return ret; 98 } 99 utdm->tdm_port = val; 100 ut_info->uf_info.tdm_num = utdm->tdm_port; 101 102 if (of_property_read_bool(np, "fsl,tdm-internal-loopback")) 103 utdm->tdm_mode = TDM_INTERNAL_LOOPBACK; 104 else 105 utdm->tdm_mode = TDM_NORMAL; 106 107 sprop = of_get_property(np, "fsl,tdm-framer-type", NULL); 108 if (!sprop) { 109 ret = -EINVAL; 110 pr_err("QE-TDM: No tdm-framer-type property for UCC\n"); 111 return ret; 112 } 113 ret = set_tdm_framer(sprop); 114 if (ret < 0) 115 return -EINVAL; 116 utdm->tdm_framer_type = ret; 117 118 ret = of_property_read_u32_index(np, "fsl,siram-entry-id", 0, &val); 119 if (ret) { 120 ret = -EINVAL; 121 pr_err("QE-TDM: No siram entry id for UCC\n"); 122 return ret; 123 } 124 utdm->siram_entry_id = val; 125 126 set_si_param(utdm, ut_info); 127 128 np2 = of_find_compatible_node(NULL, NULL, "fsl,t1040-qe-si"); 129 if (!np2) 130 return -EINVAL; 131 132 pdev = of_find_device_by_node(np2); 133 if (!pdev) { 134 pr_err("%s: failed to lookup pdev\n", np2->name); 135 of_node_put(np2); 136 return -EINVAL; 137 } 138 139 of_node_put(np2); 140 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 141 utdm->si_regs = devm_ioremap_resource(&pdev->dev, res); 142 if (IS_ERR(utdm->si_regs)) { 143 ret = PTR_ERR(utdm->si_regs); 144 goto err_miss_siram_property; 145 } 146 147 np2 = of_find_compatible_node(NULL, NULL, "fsl,t1040-qe-siram"); 148 if (!np2) { 149 ret = -EINVAL; 150 goto err_miss_siram_property; 151 } 152 153 pdev = of_find_device_by_node(np2); 154 if (!pdev) { 155 ret = -EINVAL; 156 pr_err("%s: failed to lookup pdev\n", np2->name); 157 of_node_put(np2); 158 goto err_miss_siram_property; 159 } 160 161 of_node_put(np2); 162 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 163 utdm->siram = devm_ioremap_resource(&pdev->dev, res); 164 if (IS_ERR(utdm->siram)) { 165 ret = PTR_ERR(utdm->siram); 166 goto err_miss_siram_property; 167 } 168 169 if (siram_init_flag == 0) { 170 memset_io(utdm->siram, 0, resource_size(res)); 171 siram_init_flag = 1; 172 } 173 174 return ret; 175 176 err_miss_siram_property: 177 devm_iounmap(&pdev->dev, utdm->si_regs); 178 return ret; 179 } 180 181 void ucc_tdm_init(struct ucc_tdm *utdm, struct ucc_tdm_info *ut_info) 182 { 183 struct si1 __iomem *si_regs; 184 u16 __iomem *siram; 185 u16 siram_entry_valid; 186 u16 siram_entry_closed; 187 u16 ucc_num; 188 u8 csel; 189 u16 sixmr; 190 u16 tdm_port; 191 u32 siram_entry_id; 192 u32 mask; 193 int i; 194 195 si_regs = utdm->si_regs; 196 siram = utdm->siram; 197 ucc_num = ut_info->uf_info.ucc_num; 198 tdm_port = utdm->tdm_port; 199 siram_entry_id = utdm->siram_entry_id; 200 201 if (utdm->tdm_framer_type == TDM_FRAMER_T1) 202 utdm->num_of_ts = 24; 203 if (utdm->tdm_framer_type == TDM_FRAMER_E1) 204 utdm->num_of_ts = 32; 205 206 /* set siram table */ 207 csel = (ucc_num < 4) ? ucc_num + 9 : ucc_num - 3; 208 209 siram_entry_valid = SIR_CSEL(csel) | SIR_BYTE | SIR_CNT(0); 210 siram_entry_closed = SIR_IDLE | SIR_BYTE | SIR_CNT(0); 211 212 for (i = 0; i < utdm->num_of_ts; i++) { 213 mask = 0x01 << i; 214 215 if (utdm->tx_ts_mask & mask) 216 iowrite16be(siram_entry_valid, 217 &siram[siram_entry_id * 32 + i]); 218 else 219 iowrite16be(siram_entry_closed, 220 &siram[siram_entry_id * 32 + i]); 221 222 if (utdm->rx_ts_mask & mask) 223 iowrite16be(siram_entry_valid, 224 &siram[siram_entry_id * 32 + 0x200 + i]); 225 else 226 iowrite16be(siram_entry_closed, 227 &siram[siram_entry_id * 32 + 0x200 + i]); 228 } 229 230 setbits16(&siram[(siram_entry_id * 32) + (utdm->num_of_ts - 1)], 231 SIR_LAST); 232 setbits16(&siram[(siram_entry_id * 32) + 0x200 + (utdm->num_of_ts - 1)], 233 SIR_LAST); 234 235 /* Set SIxMR register */ 236 sixmr = SIMR_SAD(siram_entry_id); 237 238 sixmr &= ~SIMR_SDM_MASK; 239 240 if (utdm->tdm_mode == TDM_INTERNAL_LOOPBACK) 241 sixmr |= SIMR_SDM_INTERNAL_LOOPBACK; 242 else 243 sixmr |= SIMR_SDM_NORMAL; 244 245 sixmr |= SIMR_RFSD(ut_info->si_info.simr_rfsd) | 246 SIMR_TFSD(ut_info->si_info.simr_tfsd); 247 248 if (ut_info->si_info.simr_crt) 249 sixmr |= SIMR_CRT; 250 if (ut_info->si_info.simr_sl) 251 sixmr |= SIMR_SL; 252 if (ut_info->si_info.simr_ce) 253 sixmr |= SIMR_CE; 254 if (ut_info->si_info.simr_fe) 255 sixmr |= SIMR_FE; 256 if (ut_info->si_info.simr_gm) 257 sixmr |= SIMR_GM; 258 259 switch (tdm_port) { 260 case 0: 261 iowrite16be(sixmr, &si_regs->sixmr1[0]); 262 break; 263 case 1: 264 iowrite16be(sixmr, &si_regs->sixmr1[1]); 265 break; 266 case 2: 267 iowrite16be(sixmr, &si_regs->sixmr1[2]); 268 break; 269 case 3: 270 iowrite16be(sixmr, &si_regs->sixmr1[3]); 271 break; 272 default: 273 pr_err("QE-TDM: can not find tdm sixmr reg\n"); 274 break; 275 } 276 } 277