Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / drivers / soc / fsl / qe / qe_tdm.c
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 }