1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2015 Freescale Semiconductor, Inc. All rights reserved. |
4 | * |
5 | * Authors: Zhao Qiang <qiang.zhao@nxp.com> |
6 | * |
7 | * Description: |
8 | * QE TDM API Set - TDM specific routines implementations. |
9 | */ |
10 | #include <linux/io.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/of.h> |
13 | #include <soc/fsl/qe/qe_tdm.h> |
14 | |
15 | static int set_tdm_framer(const char *tdm_framer_type) |
16 | { |
17 | if (strcmp(tdm_framer_type, "e1" ) == 0) |
18 | return TDM_FRAMER_E1; |
19 | else if (strcmp(tdm_framer_type, "t1" ) == 0) |
20 | return TDM_FRAMER_T1; |
21 | else |
22 | return -EINVAL; |
23 | } |
24 | |
25 | static void set_si_param(struct ucc_tdm *utdm, struct ucc_tdm_info *ut_info) |
26 | { |
27 | struct si_mode_info *si_info = &ut_info->si_info; |
28 | |
29 | if (utdm->tdm_mode == TDM_INTERNAL_LOOPBACK) { |
30 | si_info->simr_crt = 1; |
31 | si_info->simr_rfsd = 0; |
32 | } |
33 | } |
34 | |
35 | int ucc_of_parse_tdm(struct device_node *np, struct ucc_tdm *utdm, |
36 | struct ucc_tdm_info *ut_info) |
37 | { |
38 | const char *sprop; |
39 | int ret = 0; |
40 | u32 val; |
41 | |
42 | sprop = of_get_property(node: np, name: "fsl,rx-sync-clock" , NULL); |
43 | if (sprop) { |
44 | ut_info->uf_info.rx_sync = qe_clock_source(source: sprop); |
45 | if ((ut_info->uf_info.rx_sync < QE_CLK_NONE) || |
46 | (ut_info->uf_info.rx_sync > QE_RSYNC_PIN)) { |
47 | pr_err("QE-TDM: Invalid rx-sync-clock property\n" ); |
48 | return -EINVAL; |
49 | } |
50 | } else { |
51 | pr_err("QE-TDM: Invalid rx-sync-clock property\n" ); |
52 | return -EINVAL; |
53 | } |
54 | |
55 | sprop = of_get_property(node: np, name: "fsl,tx-sync-clock" , NULL); |
56 | if (sprop) { |
57 | ut_info->uf_info.tx_sync = qe_clock_source(source: sprop); |
58 | if ((ut_info->uf_info.tx_sync < QE_CLK_NONE) || |
59 | (ut_info->uf_info.tx_sync > QE_TSYNC_PIN)) { |
60 | pr_err("QE-TDM: Invalid tx-sync-clock property\n" ); |
61 | return -EINVAL; |
62 | } |
63 | } else { |
64 | pr_err("QE-TDM: Invalid tx-sync-clock property\n" ); |
65 | return -EINVAL; |
66 | } |
67 | |
68 | ret = of_property_read_u32_index(np, propname: "fsl,tx-timeslot-mask" , index: 0, out_value: &val); |
69 | if (ret) { |
70 | pr_err("QE-TDM: Invalid tx-timeslot-mask property\n" ); |
71 | return -EINVAL; |
72 | } |
73 | utdm->tx_ts_mask = val; |
74 | |
75 | ret = of_property_read_u32_index(np, propname: "fsl,rx-timeslot-mask" , index: 0, out_value: &val); |
76 | if (ret) { |
77 | ret = -EINVAL; |
78 | pr_err("QE-TDM: Invalid rx-timeslot-mask property\n" ); |
79 | return ret; |
80 | } |
81 | utdm->rx_ts_mask = val; |
82 | |
83 | ret = of_property_read_u32_index(np, propname: "fsl,tdm-id" , index: 0, out_value: &val); |
84 | if (ret) { |
85 | ret = -EINVAL; |
86 | pr_err("QE-TDM: No fsl,tdm-id property for this UCC\n" ); |
87 | return ret; |
88 | } |
89 | utdm->tdm_port = val; |
90 | ut_info->uf_info.tdm_num = utdm->tdm_port; |
91 | |
92 | if (of_property_read_bool(np, propname: "fsl,tdm-internal-loopback" )) |
93 | utdm->tdm_mode = TDM_INTERNAL_LOOPBACK; |
94 | else |
95 | utdm->tdm_mode = TDM_NORMAL; |
96 | |
97 | sprop = of_get_property(node: np, name: "fsl,tdm-framer-type" , NULL); |
98 | if (!sprop) { |
99 | ret = -EINVAL; |
100 | pr_err("QE-TDM: No tdm-framer-type property for UCC\n" ); |
101 | return ret; |
102 | } |
103 | ret = set_tdm_framer(sprop); |
104 | if (ret < 0) |
105 | return -EINVAL; |
106 | utdm->tdm_framer_type = ret; |
107 | |
108 | ret = of_property_read_u32_index(np, propname: "fsl,siram-entry-id" , index: 0, out_value: &val); |
109 | if (ret) { |
110 | ret = -EINVAL; |
111 | pr_err("QE-TDM: No siram entry id for UCC\n" ); |
112 | return ret; |
113 | } |
114 | utdm->siram_entry_id = val; |
115 | |
116 | set_si_param(utdm, ut_info); |
117 | return ret; |
118 | } |
119 | EXPORT_SYMBOL(ucc_of_parse_tdm); |
120 | |
121 | void ucc_tdm_init(struct ucc_tdm *utdm, struct ucc_tdm_info *ut_info) |
122 | { |
123 | struct si1 __iomem *si_regs; |
124 | u16 __iomem *siram; |
125 | u16 siram_entry_valid; |
126 | u16 siram_entry_closed; |
127 | u16 ucc_num; |
128 | u8 csel; |
129 | u16 sixmr; |
130 | u16 tdm_port; |
131 | u32 siram_entry_id; |
132 | u32 mask; |
133 | int i; |
134 | |
135 | si_regs = utdm->si_regs; |
136 | siram = utdm->siram; |
137 | ucc_num = ut_info->uf_info.ucc_num; |
138 | tdm_port = utdm->tdm_port; |
139 | siram_entry_id = utdm->siram_entry_id; |
140 | |
141 | if (utdm->tdm_framer_type == TDM_FRAMER_T1) |
142 | utdm->num_of_ts = 24; |
143 | if (utdm->tdm_framer_type == TDM_FRAMER_E1) |
144 | utdm->num_of_ts = 32; |
145 | |
146 | /* set siram table */ |
147 | csel = (ucc_num < 4) ? ucc_num + 9 : ucc_num - 3; |
148 | |
149 | siram_entry_valid = SIR_CSEL(csel) | SIR_BYTE | SIR_CNT(0); |
150 | siram_entry_closed = SIR_IDLE | SIR_BYTE | SIR_CNT(0); |
151 | |
152 | for (i = 0; i < utdm->num_of_ts; i++) { |
153 | mask = 0x01 << i; |
154 | |
155 | if (utdm->tx_ts_mask & mask) |
156 | iowrite16be(siram_entry_valid, |
157 | &siram[siram_entry_id * 32 + i]); |
158 | else |
159 | iowrite16be(siram_entry_closed, |
160 | &siram[siram_entry_id * 32 + i]); |
161 | |
162 | if (utdm->rx_ts_mask & mask) |
163 | iowrite16be(siram_entry_valid, |
164 | &siram[siram_entry_id * 32 + 0x200 + i]); |
165 | else |
166 | iowrite16be(siram_entry_closed, |
167 | &siram[siram_entry_id * 32 + 0x200 + i]); |
168 | } |
169 | |
170 | qe_setbits_be16(&siram[(siram_entry_id * 32) + (utdm->num_of_ts - 1)], |
171 | SIR_LAST); |
172 | qe_setbits_be16(&siram[(siram_entry_id * 32) + 0x200 + (utdm->num_of_ts - 1)], |
173 | SIR_LAST); |
174 | |
175 | /* Set SIxMR register */ |
176 | sixmr = SIMR_SAD(siram_entry_id); |
177 | |
178 | sixmr &= ~SIMR_SDM_MASK; |
179 | |
180 | if (utdm->tdm_mode == TDM_INTERNAL_LOOPBACK) |
181 | sixmr |= SIMR_SDM_INTERNAL_LOOPBACK; |
182 | else |
183 | sixmr |= SIMR_SDM_NORMAL; |
184 | |
185 | sixmr |= SIMR_RFSD(ut_info->si_info.simr_rfsd) | |
186 | SIMR_TFSD(ut_info->si_info.simr_tfsd); |
187 | |
188 | if (ut_info->si_info.simr_crt) |
189 | sixmr |= SIMR_CRT; |
190 | if (ut_info->si_info.simr_sl) |
191 | sixmr |= SIMR_SL; |
192 | if (ut_info->si_info.simr_ce) |
193 | sixmr |= SIMR_CE; |
194 | if (ut_info->si_info.simr_fe) |
195 | sixmr |= SIMR_FE; |
196 | if (ut_info->si_info.simr_gm) |
197 | sixmr |= SIMR_GM; |
198 | |
199 | switch (tdm_port) { |
200 | case 0: |
201 | iowrite16be(sixmr, &si_regs->sixmr1[0]); |
202 | break; |
203 | case 1: |
204 | iowrite16be(sixmr, &si_regs->sixmr1[1]); |
205 | break; |
206 | case 2: |
207 | iowrite16be(sixmr, &si_regs->sixmr1[2]); |
208 | break; |
209 | case 3: |
210 | iowrite16be(sixmr, &si_regs->sixmr1[3]); |
211 | break; |
212 | default: |
213 | pr_err("QE-TDM: can not find tdm sixmr reg\n" ); |
214 | break; |
215 | } |
216 | } |
217 | EXPORT_SYMBOL(ucc_tdm_init); |
218 | |