135ef1c20SZhao Qiang /* 235ef1c20SZhao Qiang * Copyright (C) 2015 Freescale Semiconductor, Inc. All rights reserved. 335ef1c20SZhao Qiang * 435ef1c20SZhao Qiang * Authors: Zhao Qiang <qiang.zhao@nxp.com> 535ef1c20SZhao Qiang * 635ef1c20SZhao Qiang * Description: 735ef1c20SZhao Qiang * QE TDM API Set - TDM specific routines implementations. 835ef1c20SZhao Qiang * 935ef1c20SZhao Qiang * This program is free software; you can redistribute it and/or modify it 1035ef1c20SZhao Qiang * under the terms of the GNU General Public License as published by the 1135ef1c20SZhao Qiang * Free Software Foundation; either version 2 of the License, or (at your 1235ef1c20SZhao Qiang * option) any later version. 1335ef1c20SZhao Qiang */ 1435ef1c20SZhao Qiang #include <linux/io.h> 1535ef1c20SZhao Qiang #include <linux/kernel.h> 1635ef1c20SZhao Qiang #include <linux/of_address.h> 1735ef1c20SZhao Qiang #include <linux/of_irq.h> 1835ef1c20SZhao Qiang #include <linux/of_platform.h> 1935ef1c20SZhao Qiang #include <soc/fsl/qe/qe_tdm.h> 2035ef1c20SZhao Qiang 2135ef1c20SZhao Qiang static int set_tdm_framer(const char *tdm_framer_type) 2235ef1c20SZhao Qiang { 2335ef1c20SZhao Qiang if (strcmp(tdm_framer_type, "e1") == 0) 2435ef1c20SZhao Qiang return TDM_FRAMER_E1; 2535ef1c20SZhao Qiang else if (strcmp(tdm_framer_type, "t1") == 0) 2635ef1c20SZhao Qiang return TDM_FRAMER_T1; 2735ef1c20SZhao Qiang else 2835ef1c20SZhao Qiang return -EINVAL; 2935ef1c20SZhao Qiang } 3035ef1c20SZhao Qiang 3135ef1c20SZhao Qiang static void set_si_param(struct ucc_tdm *utdm, struct ucc_tdm_info *ut_info) 3235ef1c20SZhao Qiang { 3335ef1c20SZhao Qiang struct si_mode_info *si_info = &ut_info->si_info; 3435ef1c20SZhao Qiang 3535ef1c20SZhao Qiang if (utdm->tdm_mode == TDM_INTERNAL_LOOPBACK) { 3635ef1c20SZhao Qiang si_info->simr_crt = 1; 3735ef1c20SZhao Qiang si_info->simr_rfsd = 0; 3835ef1c20SZhao Qiang } 3935ef1c20SZhao Qiang } 4035ef1c20SZhao Qiang 4135ef1c20SZhao Qiang int ucc_of_parse_tdm(struct device_node *np, struct ucc_tdm *utdm, 4235ef1c20SZhao Qiang struct ucc_tdm_info *ut_info) 4335ef1c20SZhao Qiang { 4435ef1c20SZhao Qiang const char *sprop; 4535ef1c20SZhao Qiang int ret = 0; 4635ef1c20SZhao Qiang u32 val; 4735ef1c20SZhao Qiang struct resource *res; 4835ef1c20SZhao Qiang struct device_node *np2; 4935ef1c20SZhao Qiang static int siram_init_flag; 5035ef1c20SZhao Qiang struct platform_device *pdev; 5135ef1c20SZhao Qiang 5235ef1c20SZhao Qiang sprop = of_get_property(np, "fsl,rx-sync-clock", NULL); 5335ef1c20SZhao Qiang if (sprop) { 5435ef1c20SZhao Qiang ut_info->uf_info.rx_sync = qe_clock_source(sprop); 5535ef1c20SZhao Qiang if ((ut_info->uf_info.rx_sync < QE_CLK_NONE) || 5635ef1c20SZhao Qiang (ut_info->uf_info.rx_sync > QE_RSYNC_PIN)) { 5735ef1c20SZhao Qiang pr_err("QE-TDM: Invalid rx-sync-clock property\n"); 5835ef1c20SZhao Qiang return -EINVAL; 5935ef1c20SZhao Qiang } 6035ef1c20SZhao Qiang } else { 6135ef1c20SZhao Qiang pr_err("QE-TDM: Invalid rx-sync-clock property\n"); 6235ef1c20SZhao Qiang return -EINVAL; 6335ef1c20SZhao Qiang } 6435ef1c20SZhao Qiang 6535ef1c20SZhao Qiang sprop = of_get_property(np, "fsl,tx-sync-clock", NULL); 6635ef1c20SZhao Qiang if (sprop) { 6735ef1c20SZhao Qiang ut_info->uf_info.tx_sync = qe_clock_source(sprop); 6835ef1c20SZhao Qiang if ((ut_info->uf_info.tx_sync < QE_CLK_NONE) || 6935ef1c20SZhao Qiang (ut_info->uf_info.tx_sync > QE_TSYNC_PIN)) { 7035ef1c20SZhao Qiang pr_err("QE-TDM: Invalid tx-sync-clock property\n"); 7135ef1c20SZhao Qiang return -EINVAL; 7235ef1c20SZhao Qiang } 7335ef1c20SZhao Qiang } else { 7435ef1c20SZhao Qiang pr_err("QE-TDM: Invalid tx-sync-clock property\n"); 7535ef1c20SZhao Qiang return -EINVAL; 7635ef1c20SZhao Qiang } 7735ef1c20SZhao Qiang 7835ef1c20SZhao Qiang ret = of_property_read_u32_index(np, "fsl,tx-timeslot-mask", 0, &val); 7935ef1c20SZhao Qiang if (ret) { 8035ef1c20SZhao Qiang pr_err("QE-TDM: Invalid tx-timeslot-mask property\n"); 8135ef1c20SZhao Qiang return -EINVAL; 8235ef1c20SZhao Qiang } 8335ef1c20SZhao Qiang utdm->tx_ts_mask = val; 8435ef1c20SZhao Qiang 8535ef1c20SZhao Qiang ret = of_property_read_u32_index(np, "fsl,rx-timeslot-mask", 0, &val); 8635ef1c20SZhao Qiang if (ret) { 8735ef1c20SZhao Qiang ret = -EINVAL; 8835ef1c20SZhao Qiang pr_err("QE-TDM: Invalid rx-timeslot-mask property\n"); 8935ef1c20SZhao Qiang return ret; 9035ef1c20SZhao Qiang } 9135ef1c20SZhao Qiang utdm->rx_ts_mask = val; 9235ef1c20SZhao Qiang 9335ef1c20SZhao Qiang ret = of_property_read_u32_index(np, "fsl,tdm-id", 0, &val); 9435ef1c20SZhao Qiang if (ret) { 9535ef1c20SZhao Qiang ret = -EINVAL; 9635ef1c20SZhao Qiang pr_err("QE-TDM: No fsl,tdm-id property for this UCC\n"); 9735ef1c20SZhao Qiang return ret; 9835ef1c20SZhao Qiang } 9935ef1c20SZhao Qiang utdm->tdm_port = val; 10035ef1c20SZhao Qiang ut_info->uf_info.tdm_num = utdm->tdm_port; 10135ef1c20SZhao Qiang 10274c269f6SJulia Lawall if (of_property_read_bool(np, "fsl,tdm-internal-loopback")) 10335ef1c20SZhao Qiang utdm->tdm_mode = TDM_INTERNAL_LOOPBACK; 10435ef1c20SZhao Qiang else 10535ef1c20SZhao Qiang utdm->tdm_mode = TDM_NORMAL; 10635ef1c20SZhao Qiang 10735ef1c20SZhao Qiang sprop = of_get_property(np, "fsl,tdm-framer-type", NULL); 10835ef1c20SZhao Qiang if (!sprop) { 10935ef1c20SZhao Qiang ret = -EINVAL; 11035ef1c20SZhao Qiang pr_err("QE-TDM: No tdm-framer-type property for UCC\n"); 11135ef1c20SZhao Qiang return ret; 11235ef1c20SZhao Qiang } 11335ef1c20SZhao Qiang ret = set_tdm_framer(sprop); 11435ef1c20SZhao Qiang if (ret < 0) 11535ef1c20SZhao Qiang return -EINVAL; 11635ef1c20SZhao Qiang utdm->tdm_framer_type = ret; 11735ef1c20SZhao Qiang 11835ef1c20SZhao Qiang ret = of_property_read_u32_index(np, "fsl,siram-entry-id", 0, &val); 11935ef1c20SZhao Qiang if (ret) { 12035ef1c20SZhao Qiang ret = -EINVAL; 12135ef1c20SZhao Qiang pr_err("QE-TDM: No siram entry id for UCC\n"); 12235ef1c20SZhao Qiang return ret; 12335ef1c20SZhao Qiang } 12435ef1c20SZhao Qiang utdm->siram_entry_id = val; 12535ef1c20SZhao Qiang 12635ef1c20SZhao Qiang set_si_param(utdm, ut_info); 12735ef1c20SZhao Qiang 12835ef1c20SZhao Qiang np2 = of_find_compatible_node(NULL, NULL, "fsl,t1040-qe-si"); 12935ef1c20SZhao Qiang if (!np2) 13035ef1c20SZhao Qiang return -EINVAL; 13135ef1c20SZhao Qiang 13235ef1c20SZhao Qiang pdev = of_find_device_by_node(np2); 13335ef1c20SZhao Qiang if (!pdev) { 13435ef1c20SZhao Qiang pr_err("%s: failed to lookup pdev\n", np2->name); 13535ef1c20SZhao Qiang of_node_put(np2); 13635ef1c20SZhao Qiang return -EINVAL; 13735ef1c20SZhao Qiang } 13835ef1c20SZhao Qiang 13935ef1c20SZhao Qiang of_node_put(np2); 14035ef1c20SZhao Qiang res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 14135ef1c20SZhao Qiang utdm->si_regs = devm_ioremap_resource(&pdev->dev, res); 14235ef1c20SZhao Qiang if (IS_ERR(utdm->si_regs)) { 14335ef1c20SZhao Qiang ret = PTR_ERR(utdm->si_regs); 14435ef1c20SZhao Qiang goto err_miss_siram_property; 14535ef1c20SZhao Qiang } 14635ef1c20SZhao Qiang 14735ef1c20SZhao Qiang np2 = of_find_compatible_node(NULL, NULL, "fsl,t1040-qe-siram"); 14835ef1c20SZhao Qiang if (!np2) { 14935ef1c20SZhao Qiang ret = -EINVAL; 15035ef1c20SZhao Qiang goto err_miss_siram_property; 15135ef1c20SZhao Qiang } 15235ef1c20SZhao Qiang 15335ef1c20SZhao Qiang pdev = of_find_device_by_node(np2); 15435ef1c20SZhao Qiang if (!pdev) { 15535ef1c20SZhao Qiang ret = -EINVAL; 15635ef1c20SZhao Qiang pr_err("%s: failed to lookup pdev\n", np2->name); 15735ef1c20SZhao Qiang of_node_put(np2); 15835ef1c20SZhao Qiang goto err_miss_siram_property; 15935ef1c20SZhao Qiang } 16035ef1c20SZhao Qiang 16135ef1c20SZhao Qiang of_node_put(np2); 16235ef1c20SZhao Qiang res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 16335ef1c20SZhao Qiang utdm->siram = devm_ioremap_resource(&pdev->dev, res); 16435ef1c20SZhao Qiang if (IS_ERR(utdm->siram)) { 16535ef1c20SZhao Qiang ret = PTR_ERR(utdm->siram); 16635ef1c20SZhao Qiang goto err_miss_siram_property; 16735ef1c20SZhao Qiang } 16835ef1c20SZhao Qiang 16935ef1c20SZhao Qiang if (siram_init_flag == 0) { 17040f1ebd4SVaishali Thakkar memset_io(utdm->siram, 0, resource_size(res)); 17135ef1c20SZhao Qiang siram_init_flag = 1; 17235ef1c20SZhao Qiang } 17335ef1c20SZhao Qiang 17435ef1c20SZhao Qiang return ret; 17535ef1c20SZhao Qiang 17635ef1c20SZhao Qiang err_miss_siram_property: 17735ef1c20SZhao Qiang devm_iounmap(&pdev->dev, utdm->si_regs); 17835ef1c20SZhao Qiang return ret; 17935ef1c20SZhao Qiang } 180*4ba25162SValentin Longchamp EXPORT_SYMBOL(ucc_of_parse_tdm); 18135ef1c20SZhao Qiang 18235ef1c20SZhao Qiang void ucc_tdm_init(struct ucc_tdm *utdm, struct ucc_tdm_info *ut_info) 18335ef1c20SZhao Qiang { 18435ef1c20SZhao Qiang struct si1 __iomem *si_regs; 18535ef1c20SZhao Qiang u16 __iomem *siram; 18635ef1c20SZhao Qiang u16 siram_entry_valid; 18735ef1c20SZhao Qiang u16 siram_entry_closed; 18835ef1c20SZhao Qiang u16 ucc_num; 18935ef1c20SZhao Qiang u8 csel; 19035ef1c20SZhao Qiang u16 sixmr; 19135ef1c20SZhao Qiang u16 tdm_port; 19235ef1c20SZhao Qiang u32 siram_entry_id; 19335ef1c20SZhao Qiang u32 mask; 19435ef1c20SZhao Qiang int i; 19535ef1c20SZhao Qiang 19635ef1c20SZhao Qiang si_regs = utdm->si_regs; 19735ef1c20SZhao Qiang siram = utdm->siram; 19835ef1c20SZhao Qiang ucc_num = ut_info->uf_info.ucc_num; 19935ef1c20SZhao Qiang tdm_port = utdm->tdm_port; 20035ef1c20SZhao Qiang siram_entry_id = utdm->siram_entry_id; 20135ef1c20SZhao Qiang 20235ef1c20SZhao Qiang if (utdm->tdm_framer_type == TDM_FRAMER_T1) 20335ef1c20SZhao Qiang utdm->num_of_ts = 24; 20435ef1c20SZhao Qiang if (utdm->tdm_framer_type == TDM_FRAMER_E1) 20535ef1c20SZhao Qiang utdm->num_of_ts = 32; 20635ef1c20SZhao Qiang 20735ef1c20SZhao Qiang /* set siram table */ 20835ef1c20SZhao Qiang csel = (ucc_num < 4) ? ucc_num + 9 : ucc_num - 3; 20935ef1c20SZhao Qiang 21035ef1c20SZhao Qiang siram_entry_valid = SIR_CSEL(csel) | SIR_BYTE | SIR_CNT(0); 21135ef1c20SZhao Qiang siram_entry_closed = SIR_IDLE | SIR_BYTE | SIR_CNT(0); 21235ef1c20SZhao Qiang 21335ef1c20SZhao Qiang for (i = 0; i < utdm->num_of_ts; i++) { 21435ef1c20SZhao Qiang mask = 0x01 << i; 21535ef1c20SZhao Qiang 21635ef1c20SZhao Qiang if (utdm->tx_ts_mask & mask) 21735ef1c20SZhao Qiang iowrite16be(siram_entry_valid, 21835ef1c20SZhao Qiang &siram[siram_entry_id * 32 + i]); 21935ef1c20SZhao Qiang else 22035ef1c20SZhao Qiang iowrite16be(siram_entry_closed, 22135ef1c20SZhao Qiang &siram[siram_entry_id * 32 + i]); 22235ef1c20SZhao Qiang 22335ef1c20SZhao Qiang if (utdm->rx_ts_mask & mask) 22435ef1c20SZhao Qiang iowrite16be(siram_entry_valid, 22535ef1c20SZhao Qiang &siram[siram_entry_id * 32 + 0x200 + i]); 22635ef1c20SZhao Qiang else 22735ef1c20SZhao Qiang iowrite16be(siram_entry_closed, 22835ef1c20SZhao Qiang &siram[siram_entry_id * 32 + 0x200 + i]); 22935ef1c20SZhao Qiang } 23035ef1c20SZhao Qiang 23135ef1c20SZhao Qiang setbits16(&siram[(siram_entry_id * 32) + (utdm->num_of_ts - 1)], 23235ef1c20SZhao Qiang SIR_LAST); 23335ef1c20SZhao Qiang setbits16(&siram[(siram_entry_id * 32) + 0x200 + (utdm->num_of_ts - 1)], 23435ef1c20SZhao Qiang SIR_LAST); 23535ef1c20SZhao Qiang 23635ef1c20SZhao Qiang /* Set SIxMR register */ 23735ef1c20SZhao Qiang sixmr = SIMR_SAD(siram_entry_id); 23835ef1c20SZhao Qiang 23935ef1c20SZhao Qiang sixmr &= ~SIMR_SDM_MASK; 24035ef1c20SZhao Qiang 24135ef1c20SZhao Qiang if (utdm->tdm_mode == TDM_INTERNAL_LOOPBACK) 24235ef1c20SZhao Qiang sixmr |= SIMR_SDM_INTERNAL_LOOPBACK; 24335ef1c20SZhao Qiang else 24435ef1c20SZhao Qiang sixmr |= SIMR_SDM_NORMAL; 24535ef1c20SZhao Qiang 24635ef1c20SZhao Qiang sixmr |= SIMR_RFSD(ut_info->si_info.simr_rfsd) | 24735ef1c20SZhao Qiang SIMR_TFSD(ut_info->si_info.simr_tfsd); 24835ef1c20SZhao Qiang 24935ef1c20SZhao Qiang if (ut_info->si_info.simr_crt) 25035ef1c20SZhao Qiang sixmr |= SIMR_CRT; 25135ef1c20SZhao Qiang if (ut_info->si_info.simr_sl) 25235ef1c20SZhao Qiang sixmr |= SIMR_SL; 25335ef1c20SZhao Qiang if (ut_info->si_info.simr_ce) 25435ef1c20SZhao Qiang sixmr |= SIMR_CE; 25535ef1c20SZhao Qiang if (ut_info->si_info.simr_fe) 25635ef1c20SZhao Qiang sixmr |= SIMR_FE; 25735ef1c20SZhao Qiang if (ut_info->si_info.simr_gm) 25835ef1c20SZhao Qiang sixmr |= SIMR_GM; 25935ef1c20SZhao Qiang 26035ef1c20SZhao Qiang switch (tdm_port) { 26135ef1c20SZhao Qiang case 0: 26235ef1c20SZhao Qiang iowrite16be(sixmr, &si_regs->sixmr1[0]); 26335ef1c20SZhao Qiang break; 26435ef1c20SZhao Qiang case 1: 26535ef1c20SZhao Qiang iowrite16be(sixmr, &si_regs->sixmr1[1]); 26635ef1c20SZhao Qiang break; 26735ef1c20SZhao Qiang case 2: 26835ef1c20SZhao Qiang iowrite16be(sixmr, &si_regs->sixmr1[2]); 26935ef1c20SZhao Qiang break; 27035ef1c20SZhao Qiang case 3: 27135ef1c20SZhao Qiang iowrite16be(sixmr, &si_regs->sixmr1[3]); 27235ef1c20SZhao Qiang break; 27335ef1c20SZhao Qiang default: 27435ef1c20SZhao Qiang pr_err("QE-TDM: can not find tdm sixmr reg\n"); 27535ef1c20SZhao Qiang break; 27635ef1c20SZhao Qiang } 27735ef1c20SZhao Qiang } 278*4ba25162SValentin Longchamp EXPORT_SYMBOL(ucc_tdm_init); 279