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