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