xref: /netbsd/sys/arch/hpcmips/tx/tx39sib.c (revision beecddb6)
1 /*	$NetBSD: tx39sib.c,v 1.23 2021/08/07 16:18:54 thorpej 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.23 2021/08/07 16:18:54 thorpej Exp $");
38 
39 #undef TX39SIBDEBUG
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/device.h>
44 
45 #include <machine/bus.h>
46 #include <machine/intr.h>
47 
48 #include <hpcmips/tx/tx39var.h>
49 #include <hpcmips/tx/tx39icureg.h>
50 #include <hpcmips/tx/tx39sibvar.h>
51 #include <hpcmips/tx/tx39sibreg.h>
52 
53 #include "locators.h"
54 
55 #ifdef TX39SIBDEBUG
56 int	tx39sibdebug = 0;
57 #define	DPRINTF(arg) if (tx39sibdebug) printf arg;
58 #else
59 #define	DPRINTF(arg)
60 #endif
61 
62 int	tx39sib_match(device_t, cfdata_t, void *);
63 void	tx39sib_attach(device_t, device_t, void *);
64 int	tx39sib_print(void *, const char *);
65 int	tx39sib_search(device_t, cfdata_t, const int *, void *);
66 
67 #define TX39_CLK2X	18432000
68 const int sibsclk_divide_table[8] = {
69 	2, 3, 4, 5, 6, 8, 10, 12
70 };
71 
72 struct tx39sib_param {
73 	/* SIB clock rate */
74 	int sp_clock;
75 /*
76  *	SIBMCLK = 18.432MHz = (CLK2X /4)
77  *	SIBSCLK = SIBMCLK / sp_clock
78  *	sp_clock	start	end	divide module
79  *	0		7	8	2
80  *	1		6	8	3
81  *	2		6	9	4
82  *	3		5	9	5
83  *	4		5	10	6
84  *	5		4	11	8
85  *	6		3	12	10
86  *	7		2	13	12
87  */
88 	/* sampling rate */
89 	int sp_snd_rate; /* SNDFSDIV + 1 */
90 	int sp_tel_rate; /* TELFSDIV + 1 */
91 /*
92  *	Fs = (SIBSCLK * 2) / ((FSDIV + 1) * 64)
93  *	FSDIV + 1	sampling rate
94  *	15		19.2k		(1.6% error vs. CD-XA)
95  *	13		22.154k		(0.47% error vs. CD-Audio)
96  *	22		7.85k		(1.8% error vs. 8k)
97  */
98 	/* data format 16/8bit */
99 	int sp_sf0sndmode;
100 	int sp_sf0telmode;
101 };
102 
103 struct tx39sib_param tx39sib_param_default_3912 = {
104 	0,			/* SIBSCLK = 9.216MHz (div2) */
105 #if 0 /* setting sample */
106 	40,			/* audio: 7.2kHz */
107 	26,			/* audio: CD-Audio(/4) 11.077kHz*/
108 	6,			/* audio: 48kHz */
109 #endif
110 	13,			/* audio: CD-Audio(/2 = 22.050) 22.154kHz*/
111 	40,			/* telecom: 7.2kHz */
112 	TX39_SIBCTRL_SND16,	/* Audio 16bit mono */
113 	TX39_SIBCTRL_TEL16	/* Telecom 16bit mono */
114 };
115 
116 struct tx39sib_param tx39sib_param_default_3922 = {
117 	7,			/* SIBSCLK = 9.216MHz (div1) */
118 	13,			/* audio: CD-Audio(/2 = 22.050) 22.154kHz*/
119 	40,			/* telecom: 7.2kHz */
120 	TX39_SIBCTRL_SND16,	/* Audio 16bit mono */
121 	TX39_SIBCTRL_TEL16	/* Telecom 16bit mono */
122 };
123 
124 struct tx39sib_softc {
125 	tx_chipset_tag_t sc_tc;
126 
127 	struct tx39sib_param sc_param;
128 	int sc_attached;
129 };
130 
131 inline int	__txsibsf0_ready(tx_chipset_tag_t);
132 #ifdef TX39SIBDEBUG
133 void	tx39sib_dump(struct tx39sib_softc *);
134 #endif
135 
136 CFATTACH_DECL_NEW(tx39sib, sizeof(struct tx39sib_softc),
137     tx39sib_match, tx39sib_attach, NULL, NULL);
138 
139 int
tx39sib_match(device_t parent,cfdata_t cf,void * aux)140 tx39sib_match(device_t parent, cfdata_t cf, void *aux)
141 {
142 	return (ATTACH_FIRST);
143 }
144 
145 void
tx39sib_attach(device_t parent,device_t self,void * aux)146 tx39sib_attach(device_t parent, device_t self, void *aux)
147 {
148 	struct txsim_attach_args *ta = aux;
149 	struct tx39sib_softc *sc = device_private(self);
150 	tx_chipset_tag_t tc;
151 
152 	sc->sc_tc = tc = ta->ta_tc;
153 
154 	/* set default param */
155 #ifdef TX391X
156 	sc->sc_param = tx39sib_param_default_3912;
157 #endif /* TX391X */
158 #ifdef TX392X
159 	sc->sc_param = tx39sib_param_default_3922;
160 #endif /* TX392X */
161 
162 #define MHZ(a) ((a) / 1000000), (((a) % 1000000) / 1000)
163 	printf(": %d.%03d MHz", MHZ(tx39sib_clock(self)));
164 
165 	printf("\n");
166 #ifdef TX39SIBDEBUG
167 	if (tx39sibdebug)
168 		tx39sib_dump(sc);
169 #endif
170 	/* enable subframe0 */
171 	tx39sib_enable1(self);
172 	/* enable SIB */
173 	tx39sib_enable2(self);
174 
175 #ifdef TX39SIBDEBUG
176 	if (tx39sibdebug)
177 		tx39sib_dump(sc);
178 #endif
179 
180 	config_search(self, NULL,
181 	    CFARGS(.search = tx39sib_search));
182 }
183 
184 void
tx39sib_enable1(device_t dev)185 tx39sib_enable1(device_t dev)
186 {
187 	struct tx39sib_softc *sc = device_private(dev);
188 	struct tx39sib_param *param = &sc->sc_param;
189 	tx_chipset_tag_t tc = sc->sc_tc;
190 
191 	txreg_t reg;
192 
193 	/* disable SIB */
194 	tx39sib_disable(dev);
195 
196 	/* setup */
197 	reg = 0;
198 	/*  SIB clock rate */
199 	reg = TX39_SIBCTRL_SCLKDIV_SET(reg, param->sp_clock);
200 	/*  sampling rate (sound) */
201 	reg = TX39_SIBCTRL_SNDFSDIV_SET(reg, param->sp_snd_rate - 1);
202 	/*  sampling rate (telecom) */
203 	reg = TX39_SIBCTRL_TELFSDIV_SET(reg, param->sp_tel_rate - 1);
204 	/*  data format (8/16bit) */
205 	reg |= param->sp_sf0sndmode;
206 	reg |= param->sp_sf0telmode;
207 	tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
208 
209 	/* DMA */
210 	reg = tx_conf_read(tc, TX39_SIBDMACTRL_REG);
211 	reg &= ~(TX39_SIBDMACTRL_ENDMARXSND |
212 	    TX39_SIBDMACTRL_ENDMATXSND |
213 	    TX39_SIBDMACTRL_ENDMARXTEL |
214 	    TX39_SIBDMACTRL_ENDMATXTEL);
215 	tx_conf_write(tc, TX39_SIBDMACTRL_REG, reg);
216 
217 	/*
218 	 * Enable subframe0 (BETTY)
219 	 */
220 	reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
221 	reg |= TX39_SIBCTRL_ENSF0;
222 	tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
223 }
224 
225 void
tx39sib_enable2(device_t dev)226 tx39sib_enable2(device_t dev)
227 {
228 	struct tx39sib_softc *sc = device_private(dev);
229 	tx_chipset_tag_t tc = sc->sc_tc;
230 	txreg_t reg;
231 
232 	reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
233 	reg |= TX39_SIBCTRL_ENSIB;
234 	tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
235 }
236 
237 void
tx39sib_disable(device_t dev)238 tx39sib_disable(device_t dev)
239 {
240 	struct tx39sib_softc *sc = device_private(dev);
241 	tx_chipset_tag_t tc = sc->sc_tc;
242 	txreg_t reg;
243 	/* disable codec side */
244 	/* notyet */
245 
246 	/* disable TX39 side */
247 	reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
248 	reg &= ~(TX39_SIBCTRL_ENTEL | TX39_SIBCTRL_ENSND);
249 	tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
250 
251 	/*
252 	 * Disable subframe0/1 (BETTY/external codec)
253 	 */
254 	reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
255 	reg &= ~TX39_SIBCTRL_ENSF0;
256 	reg &= ~(TX39_SIBCTRL_ENSF1 | TX39_SIBCTRL_SELTELSF1 |
257 	    TX39_SIBCTRL_SELSNDSF1);
258 	tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
259 
260 	/* disable TX39SIB module */
261 	reg &= ~TX39_SIBCTRL_ENSIB;
262 	tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
263 }
264 
265 int
tx39sib_clock(device_t dev)266 tx39sib_clock(device_t dev)
267 {
268 	struct tx39sib_softc *sc = device_private(dev);
269 
270 	return (TX39_CLK2X / sibsclk_divide_table[sc->sc_param.sp_clock]);
271 }
272 
273 int
tx39sib_search(device_t parent,cfdata_t cf,const int * ldesc,void * aux)274 tx39sib_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
275 {
276 	struct tx39sib_softc *sc = device_private(parent);
277 	struct txsib_attach_args sa;
278 
279 	sa.sa_tc	= sc->sc_tc;
280 	sa.sa_slot	= cf->cf_loc[TXSIBIFCF_SLOT];
281 	sa.sa_snd_rate	= sc->sc_param.sp_snd_rate;
282 	sa.sa_tel_rate	= sc->sc_param.sp_tel_rate;
283 
284 	if (sa.sa_slot == TXSIBIFCF_SLOT_DEFAULT) {
285 		printf("tx39sib_search: wildcarded slot, skipping\n");
286 		return (0);
287 	}
288 
289 	if (!(sc->sc_attached & (1 << sa.sa_slot)) &&/* not attached slot */
290 	    config_probe(parent, cf, &sa)) {
291 		config_attach(parent, cf, &sa, tx39sib_print, CFARGS_NONE);
292 		sc->sc_attached |= (1 << sa.sa_slot);
293 	}
294 
295 	return (0);
296 }
297 
298 int
tx39sib_print(void * aux,const char * pnp)299 tx39sib_print(void *aux, const char *pnp)
300 {
301 	struct txsib_attach_args *sa = aux;
302 
303 	aprint_normal(" slot %d", sa->sa_slot);
304 
305 	return (QUIET);
306 }
307 
308 /*
309  * sync access method. don't use runtime.
310  */
311 
312 inline int
__txsibsf0_ready(tx_chipset_tag_t tc)313 __txsibsf0_ready(tx_chipset_tag_t tc)
314 {
315 	int i;
316 
317 	tx_conf_write(tc, TX39_INTRSTATUS1_REG, TX39_INTRSTATUS1_SIBSF0INT);
318 	for (i = 0; (!(tx_conf_read(tc, TX39_INTRSTATUS1_REG) &
319 	    TX39_INTRSTATUS1_SIBSF0INT)) && i < 1000; i++) {
320 		if (i > 100 && !(i % 100)) {
321 			printf("sf0 busy loop: retry count %d\n", i);
322 		}
323 	}
324 
325 	if (i >= 1000) {
326 		printf("sf0 busy\n");
327 		return (0);
328 	}
329 
330 	return (1);
331 }
332 
333 void
txsibsf0_reg_write(tx_chipset_tag_t tc,int addr,u_int16_t val)334 txsibsf0_reg_write(tx_chipset_tag_t tc, int addr, u_int16_t val)
335 {
336 	txreg_t reg;
337 
338 	reg = txsibsf0_read(tc, addr);
339 	reg |= TX39_SIBSF0_WRITE;
340 	TX39_SIBSF0_REGDATA_CLR(reg);
341 	reg = TX39_SIBSF0_REGDATA_SET(reg, val);
342 
343 	__txsibsf0_ready(tc);
344 	tx_conf_write(tc, TX39_SIBSF0CTRL_REG, reg);
345 }
346 
347 u_int16_t
txsibsf0_reg_read(tx_chipset_tag_t tc,int addr)348 txsibsf0_reg_read(tx_chipset_tag_t tc, int addr)
349 {
350 	return (TX39_SIBSF0_REGDATA(txsibsf0_read(tc, addr)));
351 }
352 
353 u_int32_t
txsibsf0_read(tx_chipset_tag_t tc,int addr)354 txsibsf0_read(tx_chipset_tag_t tc, int addr)
355 {
356 	txreg_t reg;
357 	int retry = 3;
358 
359 	do {
360 		reg = TX39_SIBSF0_REGADDR_SET(0, addr);
361 		__txsibsf0_ready(tc);
362 		tx_conf_write(tc, TX39_SIBSF0CTRL_REG, reg);
363 
364 		__txsibsf0_ready(tc);
365 		reg = tx_conf_read(tc, TX39_SIBSF0STAT_REG);
366 
367 	} while ((TX39_SIBSF0_REGADDR(reg) != addr) && --retry > 0);
368 
369 	if (retry <= 0)
370 		printf("txsibsf0_read: command failed\n");
371 
372 	return (reg);
373 }
374 
375 #ifdef TX39SIBDEBUG
376 #define ISSETPRINT_CTRL(r, m)						\
377 	dbg_bitmask_print(r, TX39_SIBCTRL_##m, #m)
378 #define ISSETPRINT_DMACTRL(r, m)					\
379 	dbg_bitmask_print(r, TX39_SIBDMACTRL_##m, #m)
380 
381 void
tx39sib_dump(struct tx39sib_softc * sc)382 tx39sib_dump(struct tx39sib_softc *sc)
383 {
384 	tx_chipset_tag_t tc = sc->sc_tc;
385 	txreg_t reg;
386 
387 	reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
388 	ISSETPRINT_CTRL(reg, SIBIRQ);
389 	ISSETPRINT_CTRL(reg, ENCNTTEST);
390 	ISSETPRINT_CTRL(reg, ENDMATEST);
391 	ISSETPRINT_CTRL(reg, SNDMONO);
392 	ISSETPRINT_CTRL(reg, RMONOSNDIN);
393 	ISSETPRINT_CTRL(reg, TEL16);
394 	ISSETPRINT_CTRL(reg, SND16);
395 	ISSETPRINT_CTRL(reg, SELTELSF1);
396 	ISSETPRINT_CTRL(reg, SELSNDSF1);
397 	ISSETPRINT_CTRL(reg, ENTEL);
398 	ISSETPRINT_CTRL(reg, ENSND);
399 	ISSETPRINT_CTRL(reg, SIBLOOP);
400 	ISSETPRINT_CTRL(reg, ENSF1);
401 	ISSETPRINT_CTRL(reg, ENSF0);
402 	ISSETPRINT_CTRL(reg, ENSIB);
403 	printf("\n");
404 	printf("SCLKDIV %d\n", TX39_SIBCTRL_SCLKDIV(reg));
405 	printf("TELFSDIV %d\n", TX39_SIBCTRL_TELFSDIV(reg));
406 	printf("SNDFSDIV %d\n", TX39_SIBCTRL_SNDFSDIV(reg));
407 
408 	reg = tx_conf_read(tc, TX39_SIBDMACTRL_REG);
409 	ISSETPRINT_DMACTRL(reg, SNDBUFF1TIME);
410 	ISSETPRINT_DMACTRL(reg, SNDDMALOOP);
411 	ISSETPRINT_DMACTRL(reg, ENDMARXSND);
412 	ISSETPRINT_DMACTRL(reg, ENDMATXSND);
413 	ISSETPRINT_DMACTRL(reg, TELBUFF1TIME);
414 	ISSETPRINT_DMACTRL(reg, TELDMALOOP);
415 	ISSETPRINT_DMACTRL(reg, ENDMARXTEL);
416 	ISSETPRINT_DMACTRL(reg, ENDMATXTEL);
417 	printf("\n");
418 	printf("SNDDMAPTR %d\n", TX39_SIBDMACTRL_TELDMAPTR(reg));
419 	printf("TELDMAPTR %d\n", TX39_SIBDMACTRL_SNDDMAPTR(reg));
420 
421 }
422 #endif /* TX39SIBDEBUG */
423