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 EXPORT_SYMBOL(ucc_of_parse_tdm); 181 182 void ucc_tdm_init(struct ucc_tdm *utdm, struct ucc_tdm_info *ut_info) 183 { 184 struct si1 __iomem *si_regs; 185 u16 __iomem *siram; 186 u16 siram_entry_valid; 187 u16 siram_entry_closed; 188 u16 ucc_num; 189 u8 csel; 190 u16 sixmr; 191 u16 tdm_port; 192 u32 siram_entry_id; 193 u32 mask; 194 int i; 195 196 si_regs = utdm->si_regs; 197 siram = utdm->siram; 198 ucc_num = ut_info->uf_info.ucc_num; 199 tdm_port = utdm->tdm_port; 200 siram_entry_id = utdm->siram_entry_id; 201 202 if (utdm->tdm_framer_type == TDM_FRAMER_T1) 203 utdm->num_of_ts = 24; 204 if (utdm->tdm_framer_type == TDM_FRAMER_E1) 205 utdm->num_of_ts = 32; 206 207 /* set siram table */ 208 csel = (ucc_num < 4) ? ucc_num + 9 : ucc_num - 3; 209 210 siram_entry_valid = SIR_CSEL(csel) | SIR_BYTE | SIR_CNT(0); 211 siram_entry_closed = SIR_IDLE | SIR_BYTE | SIR_CNT(0); 212 213 for (i = 0; i < utdm->num_of_ts; i++) { 214 mask = 0x01 << i; 215 216 if (utdm->tx_ts_mask & mask) 217 iowrite16be(siram_entry_valid, 218 &siram[siram_entry_id * 32 + i]); 219 else 220 iowrite16be(siram_entry_closed, 221 &siram[siram_entry_id * 32 + i]); 222 223 if (utdm->rx_ts_mask & mask) 224 iowrite16be(siram_entry_valid, 225 &siram[siram_entry_id * 32 + 0x200 + i]); 226 else 227 iowrite16be(siram_entry_closed, 228 &siram[siram_entry_id * 32 + 0x200 + i]); 229 } 230 231 setbits16(&siram[(siram_entry_id * 32) + (utdm->num_of_ts - 1)], 232 SIR_LAST); 233 setbits16(&siram[(siram_entry_id * 32) + 0x200 + (utdm->num_of_ts - 1)], 234 SIR_LAST); 235 236 /* Set SIxMR register */ 237 sixmr = SIMR_SAD(siram_entry_id); 238 239 sixmr &= ~SIMR_SDM_MASK; 240 241 if (utdm->tdm_mode == TDM_INTERNAL_LOOPBACK) 242 sixmr |= SIMR_SDM_INTERNAL_LOOPBACK; 243 else 244 sixmr |= SIMR_SDM_NORMAL; 245 246 sixmr |= SIMR_RFSD(ut_info->si_info.simr_rfsd) | 247 SIMR_TFSD(ut_info->si_info.simr_tfsd); 248 249 if (ut_info->si_info.simr_crt) 250 sixmr |= SIMR_CRT; 251 if (ut_info->si_info.simr_sl) 252 sixmr |= SIMR_SL; 253 if (ut_info->si_info.simr_ce) 254 sixmr |= SIMR_CE; 255 if (ut_info->si_info.simr_fe) 256 sixmr |= SIMR_FE; 257 if (ut_info->si_info.simr_gm) 258 sixmr |= SIMR_GM; 259 260 switch (tdm_port) { 261 case 0: 262 iowrite16be(sixmr, &si_regs->sixmr1[0]); 263 break; 264 case 1: 265 iowrite16be(sixmr, &si_regs->sixmr1[1]); 266 break; 267 case 2: 268 iowrite16be(sixmr, &si_regs->sixmr1[2]); 269 break; 270 case 3: 271 iowrite16be(sixmr, &si_regs->sixmr1[3]); 272 break; 273 default: 274 pr_err("QE-TDM: can not find tdm sixmr reg\n"); 275 break; 276 } 277 } 278 EXPORT_SYMBOL(ucc_tdm_init); 279