xref: /netbsd-src/sys/arch/hpcmips/tx/tx39sib.c (revision ff2597cfa4a533ac08a5c9aec0c46b93ca984f52)
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