1 /* $NetBSD: tx39sib.c,v 1.24 2023/09/10 20:55:30 andvar Exp $ */
2
3 /*-
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by UCHIYAMA Yasushi.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * TX39 SIB (Serial Interface Bus) module.
34 */
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: tx39sib.c,v 1.24 2023/09/10 20:55:30 andvar Exp $");
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/device.h>
42
43 #include <machine/bus.h>
44 #include <machine/intr.h>
45
46 #include <hpcmips/tx/tx39var.h>
47 #include <hpcmips/tx/tx39icureg.h>
48 #include <hpcmips/tx/tx39sibvar.h>
49 #include <hpcmips/tx/tx39sibreg.h>
50
51 #include "locators.h"
52
53 #ifdef TX39SIBDEBUG
54 #define DPRINTF_ENABLE
55 #define DPRINTF_DEBUG tx39sibdebug
56 #endif
57 #include <machine/debug.h>
58
59 int tx39sib_match(device_t, cfdata_t, void *);
60 void tx39sib_attach(device_t, device_t, void *);
61 int tx39sib_print(void *, const char *);
62 int tx39sib_search(device_t, cfdata_t, const int *, void *);
63
64 #define TX39_CLK2X 18432000
65 const int sibsclk_divide_table[8] = {
66 2, 3, 4, 5, 6, 8, 10, 12
67 };
68
69 struct tx39sib_param {
70 /* SIB clock rate */
71 int sp_clock;
72 /*
73 * SIBMCLK = 18.432MHz = (CLK2X /4)
74 * SIBSCLK = SIBMCLK / sp_clock
75 * sp_clock start end divide module
76 * 0 7 8 2
77 * 1 6 8 3
78 * 2 6 9 4
79 * 3 5 9 5
80 * 4 5 10 6
81 * 5 4 11 8
82 * 6 3 12 10
83 * 7 2 13 12
84 */
85 /* sampling rate */
86 int sp_snd_rate; /* SNDFSDIV + 1 */
87 int sp_tel_rate; /* TELFSDIV + 1 */
88 /*
89 * Fs = (SIBSCLK * 2) / ((FSDIV + 1) * 64)
90 * FSDIV + 1 sampling rate
91 * 15 19.2k (1.6% error vs. CD-XA)
92 * 13 22.154k (0.47% error vs. CD-Audio)
93 * 22 7.85k (1.8% error vs. 8k)
94 */
95 /* data format 16/8bit */
96 int sp_sf0sndmode;
97 int sp_sf0telmode;
98 };
99
100 struct tx39sib_param tx39sib_param_default_3912 = {
101 0, /* SIBSCLK = 9.216MHz (div2) */
102 #if 0 /* setting sample */
103 40, /* audio: 7.2kHz */
104 26, /* audio: CD-Audio(/4) 11.077kHz*/
105 6, /* audio: 48kHz */
106 #endif
107 13, /* audio: CD-Audio(/2 = 22.050) 22.154kHz*/
108 40, /* telecom: 7.2kHz */
109 TX39_SIBCTRL_SND16, /* Audio 16bit mono */
110 TX39_SIBCTRL_TEL16 /* Telecom 16bit mono */
111 };
112
113 struct tx39sib_param tx39sib_param_default_3922 = {
114 7, /* SIBSCLK = 9.216MHz (div1) */
115 13, /* audio: CD-Audio(/2 = 22.050) 22.154kHz*/
116 40, /* telecom: 7.2kHz */
117 TX39_SIBCTRL_SND16, /* Audio 16bit mono */
118 TX39_SIBCTRL_TEL16 /* Telecom 16bit mono */
119 };
120
121 struct tx39sib_softc {
122 tx_chipset_tag_t sc_tc;
123
124 struct tx39sib_param sc_param;
125 int sc_attached;
126 };
127
128 inline int __txsibsf0_ready(tx_chipset_tag_t);
129 #ifdef TX39SIBDEBUG
130 void tx39sib_dump(struct tx39sib_softc *);
131 #endif
132
133 CFATTACH_DECL_NEW(tx39sib, sizeof(struct tx39sib_softc),
134 tx39sib_match, tx39sib_attach, NULL, NULL);
135
136 int
tx39sib_match(device_t parent,cfdata_t cf,void * aux)137 tx39sib_match(device_t parent, cfdata_t cf, void *aux)
138 {
139 return (ATTACH_FIRST);
140 }
141
142 void
tx39sib_attach(device_t parent,device_t self,void * aux)143 tx39sib_attach(device_t parent, device_t self, void *aux)
144 {
145 struct txsim_attach_args *ta = aux;
146 struct tx39sib_softc *sc = device_private(self);
147 tx_chipset_tag_t tc;
148
149 sc->sc_tc = tc = ta->ta_tc;
150
151 /* set default param */
152 #ifdef TX391X
153 sc->sc_param = tx39sib_param_default_3912;
154 #endif /* TX391X */
155 #ifdef TX392X
156 sc->sc_param = tx39sib_param_default_3922;
157 #endif /* TX392X */
158
159 #define MHZ(a) ((a) / 1000000), (((a) % 1000000) / 1000)
160 printf(": %d.%03d MHz", MHZ(tx39sib_clock(self)));
161
162 printf("\n");
163 #ifdef TX39SIBDEBUG
164 if (tx39sibdebug)
165 tx39sib_dump(sc);
166 #endif
167 /* enable subframe0 */
168 tx39sib_enable1(self);
169 /* enable SIB */
170 tx39sib_enable2(self);
171
172 #ifdef TX39SIBDEBUG
173 if (tx39sibdebug)
174 tx39sib_dump(sc);
175 #endif
176
177 config_search(self, NULL,
178 CFARGS(.search = tx39sib_search));
179 }
180
181 void
tx39sib_enable1(device_t dev)182 tx39sib_enable1(device_t dev)
183 {
184 struct tx39sib_softc *sc = device_private(dev);
185 struct tx39sib_param *param = &sc->sc_param;
186 tx_chipset_tag_t tc = sc->sc_tc;
187
188 txreg_t reg;
189
190 /* disable SIB */
191 tx39sib_disable(dev);
192
193 /* setup */
194 reg = 0;
195 /* SIB clock rate */
196 reg = TX39_SIBCTRL_SCLKDIV_SET(reg, param->sp_clock);
197 /* sampling rate (sound) */
198 reg = TX39_SIBCTRL_SNDFSDIV_SET(reg, param->sp_snd_rate - 1);
199 /* sampling rate (telecom) */
200 reg = TX39_SIBCTRL_TELFSDIV_SET(reg, param->sp_tel_rate - 1);
201 /* data format (8/16bit) */
202 reg |= param->sp_sf0sndmode;
203 reg |= param->sp_sf0telmode;
204 tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
205
206 /* DMA */
207 reg = tx_conf_read(tc, TX39_SIBDMACTRL_REG);
208 reg &= ~(TX39_SIBDMACTRL_ENDMARXSND |
209 TX39_SIBDMACTRL_ENDMATXSND |
210 TX39_SIBDMACTRL_ENDMARXTEL |
211 TX39_SIBDMACTRL_ENDMATXTEL);
212 tx_conf_write(tc, TX39_SIBDMACTRL_REG, reg);
213
214 /*
215 * Enable subframe0 (BETTY)
216 */
217 reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
218 reg |= TX39_SIBCTRL_ENSF0;
219 tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
220 }
221
222 void
tx39sib_enable2(device_t dev)223 tx39sib_enable2(device_t dev)
224 {
225 struct tx39sib_softc *sc = device_private(dev);
226 tx_chipset_tag_t tc = sc->sc_tc;
227 txreg_t reg;
228
229 reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
230 reg |= TX39_SIBCTRL_ENSIB;
231 tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
232 }
233
234 void
tx39sib_disable(device_t dev)235 tx39sib_disable(device_t dev)
236 {
237 struct tx39sib_softc *sc = device_private(dev);
238 tx_chipset_tag_t tc = sc->sc_tc;
239 txreg_t reg;
240 /* disable codec side */
241 /* notyet */
242
243 /* disable TX39 side */
244 reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
245 reg &= ~(TX39_SIBCTRL_ENTEL | TX39_SIBCTRL_ENSND);
246 tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
247
248 /*
249 * Disable subframe0/1 (BETTY/external codec)
250 */
251 reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
252 reg &= ~TX39_SIBCTRL_ENSF0;
253 reg &= ~(TX39_SIBCTRL_ENSF1 | TX39_SIBCTRL_SELTELSF1 |
254 TX39_SIBCTRL_SELSNDSF1);
255 tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
256
257 /* disable TX39SIB module */
258 reg &= ~TX39_SIBCTRL_ENSIB;
259 tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
260 }
261
262 int
tx39sib_clock(device_t dev)263 tx39sib_clock(device_t dev)
264 {
265 struct tx39sib_softc *sc = device_private(dev);
266
267 return (TX39_CLK2X / sibsclk_divide_table[sc->sc_param.sp_clock]);
268 }
269
270 int
tx39sib_search(device_t parent,cfdata_t cf,const int * ldesc,void * aux)271 tx39sib_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
272 {
273 struct tx39sib_softc *sc = device_private(parent);
274 struct txsib_attach_args sa;
275
276 sa.sa_tc = sc->sc_tc;
277 sa.sa_slot = cf->cf_loc[TXSIBIFCF_SLOT];
278 sa.sa_snd_rate = sc->sc_param.sp_snd_rate;
279 sa.sa_tel_rate = sc->sc_param.sp_tel_rate;
280
281 if (sa.sa_slot == TXSIBIFCF_SLOT_DEFAULT) {
282 printf("tx39sib_search: wildcarded slot, skipping\n");
283 return (0);
284 }
285
286 if (!(sc->sc_attached & (1 << sa.sa_slot)) &&/* not attached slot */
287 config_probe(parent, cf, &sa)) {
288 config_attach(parent, cf, &sa, tx39sib_print, CFARGS_NONE);
289 sc->sc_attached |= (1 << sa.sa_slot);
290 }
291
292 return (0);
293 }
294
295 int
tx39sib_print(void * aux,const char * pnp)296 tx39sib_print(void *aux, const char *pnp)
297 {
298 struct txsib_attach_args *sa = aux;
299
300 aprint_normal(" slot %d", sa->sa_slot);
301
302 return (QUIET);
303 }
304
305 /*
306 * sync access method. don't use runtime.
307 */
308
309 inline int
__txsibsf0_ready(tx_chipset_tag_t tc)310 __txsibsf0_ready(tx_chipset_tag_t tc)
311 {
312 int i;
313
314 tx_conf_write(tc, TX39_INTRSTATUS1_REG, TX39_INTRSTATUS1_SIBSF0INT);
315 for (i = 0; (!(tx_conf_read(tc, TX39_INTRSTATUS1_REG) &
316 TX39_INTRSTATUS1_SIBSF0INT)) && i < 1000; i++) {
317 if (i > 100 && !(i % 100)) {
318 printf("sf0 busy loop: retry count %d\n", i);
319 }
320 }
321
322 if (i >= 1000) {
323 printf("sf0 busy\n");
324 return (0);
325 }
326
327 return (1);
328 }
329
330 void
txsibsf0_reg_write(tx_chipset_tag_t tc,int addr,u_int16_t val)331 txsibsf0_reg_write(tx_chipset_tag_t tc, int addr, u_int16_t val)
332 {
333 txreg_t reg;
334
335 reg = txsibsf0_read(tc, addr);
336 reg |= TX39_SIBSF0_WRITE;
337 TX39_SIBSF0_REGDATA_CLR(reg);
338 reg = TX39_SIBSF0_REGDATA_SET(reg, val);
339
340 __txsibsf0_ready(tc);
341 tx_conf_write(tc, TX39_SIBSF0CTRL_REG, reg);
342 }
343
344 u_int16_t
txsibsf0_reg_read(tx_chipset_tag_t tc,int addr)345 txsibsf0_reg_read(tx_chipset_tag_t tc, int addr)
346 {
347 return (TX39_SIBSF0_REGDATA(txsibsf0_read(tc, addr)));
348 }
349
350 u_int32_t
txsibsf0_read(tx_chipset_tag_t tc,int addr)351 txsibsf0_read(tx_chipset_tag_t tc, int addr)
352 {
353 txreg_t reg;
354 int retry = 3;
355
356 do {
357 reg = TX39_SIBSF0_REGADDR_SET(0, addr);
358 __txsibsf0_ready(tc);
359 tx_conf_write(tc, TX39_SIBSF0CTRL_REG, reg);
360
361 __txsibsf0_ready(tc);
362 reg = tx_conf_read(tc, TX39_SIBSF0STAT_REG);
363
364 } while ((TX39_SIBSF0_REGADDR(reg) != addr) && --retry > 0);
365
366 if (retry <= 0)
367 printf("txsibsf0_read: command failed\n");
368
369 return (reg);
370 }
371
372 #ifdef TX39SIBDEBUG
373 #define ISSETPRINT_CTRL(r, m) \
374 dbg_bitmask_print(r, TX39_SIBCTRL_##m, #m)
375 #define ISSETPRINT_DMACTRL(r, m) \
376 dbg_bitmask_print(r, TX39_SIBDMACTRL_##m, #m)
377
378 void
tx39sib_dump(struct tx39sib_softc * sc)379 tx39sib_dump(struct tx39sib_softc *sc)
380 {
381 tx_chipset_tag_t tc = sc->sc_tc;
382 txreg_t reg;
383
384 reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
385 ISSETPRINT_CTRL(reg, SIBIRQ);
386 ISSETPRINT_CTRL(reg, ENCNTTEST);
387 ISSETPRINT_CTRL(reg, ENDMATEST);
388 ISSETPRINT_CTRL(reg, SNDMONO);
389 ISSETPRINT_CTRL(reg, RMONOSNDIN);
390 ISSETPRINT_CTRL(reg, TEL16);
391 ISSETPRINT_CTRL(reg, SND16);
392 ISSETPRINT_CTRL(reg, SELTELSF1);
393 ISSETPRINT_CTRL(reg, SELSNDSF1);
394 ISSETPRINT_CTRL(reg, ENTEL);
395 ISSETPRINT_CTRL(reg, ENSND);
396 ISSETPRINT_CTRL(reg, SIBLOOP);
397 ISSETPRINT_CTRL(reg, ENSF1);
398 ISSETPRINT_CTRL(reg, ENSF0);
399 ISSETPRINT_CTRL(reg, ENSIB);
400 printf("\n");
401 printf("SCLKDIV %d\n", TX39_SIBCTRL_SCLKDIV(reg));
402 printf("TELFSDIV %d\n", TX39_SIBCTRL_TELFSDIV(reg));
403 printf("SNDFSDIV %d\n", TX39_SIBCTRL_SNDFSDIV(reg));
404
405 reg = tx_conf_read(tc, TX39_SIBDMACTRL_REG);
406 ISSETPRINT_DMACTRL(reg, SNDBUFF1TIME);
407 ISSETPRINT_DMACTRL(reg, SNDDMALOOP);
408 ISSETPRINT_DMACTRL(reg, ENDMARXSND);
409 ISSETPRINT_DMACTRL(reg, ENDMATXSND);
410 ISSETPRINT_DMACTRL(reg, TELBUFF1TIME);
411 ISSETPRINT_DMACTRL(reg, TELDMALOOP);
412 ISSETPRINT_DMACTRL(reg, ENDMARXTEL);
413 ISSETPRINT_DMACTRL(reg, ENDMATXTEL);
414 printf("\n");
415 printf("SNDDMAPTR %d\n", TX39_SIBDMACTRL_TELDMAPTR(reg));
416 printf("TELDMAPTR %d\n", TX39_SIBDMACTRL_SNDDMAPTR(reg));
417
418 }
419 #endif /* TX39SIBDEBUG */
420