xref: /netbsd-src/sys/arch/hpcmips/tx/tx39sib.c (revision e4d7c2e329d54c97e0c0bd3016bbe74f550c3d5e)
1 /*	$NetBSD: tx39sib.c,v 1.5 2000/03/04 11:39:29 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 < 200; i++)
331 		;
332 	if (i >= 200) {
333 		printf("sf0 busy\n");
334 		return 0;
335 	} else 	if (i > 100) {
336 		printf("sf0 busy loop:%d\n", i);
337 		return 0;
338 	}
339 
340 	return 1;
341 }
342 
343 void
344 txsibsf0_reg_write(tc, addr, val)
345 	tx_chipset_tag_t tc;
346 	int addr;
347 	u_int16_t val;
348 {
349 	txreg_t reg;
350 
351 	reg = txsibsf0_read(tc, addr);
352 	reg |= TX39_SIBSF0_WRITE;
353 	TX39_SIBSF0_REGDATA_CLR(reg);
354 	reg = TX39_SIBSF0_REGDATA_SET(reg, val);
355 
356 	__txsibsf0_ready(tc);
357 	tx_conf_write(tc, TX39_SIBSF0CTRL_REG, reg);
358 }
359 
360 u_int16_t
361 txsibsf0_reg_read(tc, addr)
362 	tx_chipset_tag_t tc;
363 	int addr;
364 {
365 	return TX39_SIBSF0_REGDATA(txsibsf0_read(tc, addr));
366 }
367 
368 u_int32_t
369 txsibsf0_read(tc, addr)
370 	tx_chipset_tag_t tc;
371 	int addr;
372 {
373 	txreg_t reg;
374 	int retry = 3;
375 
376 	do {
377 		reg = TX39_SIBSF0_REGADDR_SET(0, addr);
378 		__txsibsf0_ready(tc);
379 		tx_conf_write(tc, TX39_SIBSF0CTRL_REG, reg);
380 
381 		__txsibsf0_ready(tc);
382 		reg = tx_conf_read(tc, TX39_SIBSF0STAT_REG);
383 
384 	} while ((TX39_SIBSF0_REGADDR(reg) != addr) && --retry > 0);
385 
386 	if (retry <= 0)
387 		printf("txsibsf0_read: command failed\n");
388 
389 	return reg;
390 }
391 
392 #ifdef TX39SIBDEBUG
393 #define ISSETPRINT_CTRL(r, m) \
394 	__is_set_print(r, TX39_SIBCTRL_##m, #m)
395 #define ISSETPRINT_DMACTRL(r, m) \
396 	__is_set_print(r, TX39_SIBDMACTRL_##m, #m)
397 
398 void
399 tx39sib_dump(sc)
400 	struct tx39sib_softc *sc;
401 {
402 	tx_chipset_tag_t tc = sc->sc_tc;
403 	txreg_t reg;
404 
405 	reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
406 	ISSETPRINT_CTRL(reg, SIBIRQ);
407 	ISSETPRINT_CTRL(reg, ENCNTTEST);
408 	ISSETPRINT_CTRL(reg, ENDMATEST);
409 	ISSETPRINT_CTRL(reg, SNDMONO);
410 	ISSETPRINT_CTRL(reg, RMONOSNDIN);
411 	ISSETPRINT_CTRL(reg, TEL16);
412 	ISSETPRINT_CTRL(reg, SND16);
413 	ISSETPRINT_CTRL(reg, SELTELSF1);
414 	ISSETPRINT_CTRL(reg, SELSNDSF1);
415 	ISSETPRINT_CTRL(reg, ENTEL);
416 	ISSETPRINT_CTRL(reg, ENSND);
417 	ISSETPRINT_CTRL(reg, SIBLOOP);
418 	ISSETPRINT_CTRL(reg, ENSF1);
419 	ISSETPRINT_CTRL(reg, ENSF0);
420 	ISSETPRINT_CTRL(reg, ENSIB);
421 	printf("\n");
422 	printf("SCLKDIV %d\n", TX39_SIBCTRL_SCLKDIV(reg));
423 	printf("TELFSDIV %d\n", TX39_SIBCTRL_TELFSDIV(reg));
424 	printf("SNDFSDIV %d\n", TX39_SIBCTRL_SNDFSDIV(reg));
425 
426 	reg = tx_conf_read(tc, TX39_SIBDMACTRL_REG);
427 	ISSETPRINT_DMACTRL(reg, SNDBUFF1TIME);
428 	ISSETPRINT_DMACTRL(reg, SNDDMALOOP);
429 	ISSETPRINT_DMACTRL(reg, ENDMARXSND);
430 	ISSETPRINT_DMACTRL(reg, ENDMATXSND);
431 	ISSETPRINT_DMACTRL(reg, TELBUFF1TIME);
432 	ISSETPRINT_DMACTRL(reg, TELDMALOOP);
433 	ISSETPRINT_DMACTRL(reg, ENDMARXTEL);
434 	ISSETPRINT_DMACTRL(reg, ENDMATXTEL);
435 	printf("\n");
436 	printf("SNDDMAPTR %d\n", TX39_SIBDMACTRL_TELDMAPTR(reg));
437 	printf("TELDMAPTR %d\n", TX39_SIBDMACTRL_SNDDMAPTR(reg));
438 
439 }
440 #endif /* TX39SIBDEBUG */
441