xref: /netbsd-src/sys/arch/hpcmips/tx/tx39sib.c (revision 63aea4bd5b445e491ff0389fe27ec78b3099dba3)
1 /*	$NetBSD: tx39sib.c,v 1.21 2012/10/27 17:17:54 chs 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.21 2012/10/27 17:17:54 chs 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
140 tx39sib_match(device_t parent, cfdata_t cf, void *aux)
141 {
142 	return (ATTACH_FIRST);
143 }
144 
145 void
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_ia(tx39sib_search, self, "txsibif", tx39sib_print);
181 }
182 
183 void
184 tx39sib_enable1(device_t dev)
185 {
186 	struct tx39sib_softc *sc = device_private(dev);
187 	struct tx39sib_param *param = &sc->sc_param;
188 	tx_chipset_tag_t tc = sc->sc_tc;
189 
190 	txreg_t reg;
191 
192 	/* disable SIB */
193 	tx39sib_disable(dev);
194 
195 	/* setup */
196 	reg = 0;
197 	/*  SIB clock rate */
198 	reg = TX39_SIBCTRL_SCLKDIV_SET(reg, param->sp_clock);
199 	/*  sampling rate (sound) */
200 	reg = TX39_SIBCTRL_SNDFSDIV_SET(reg, param->sp_snd_rate - 1);
201 	/*  sampling rate (telecom) */
202 	reg = TX39_SIBCTRL_TELFSDIV_SET(reg, param->sp_tel_rate - 1);
203 	/*  data format (8/16bit) */
204 	reg |= param->sp_sf0sndmode;
205 	reg |= param->sp_sf0telmode;
206 	tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
207 
208 	/* DMA */
209 	reg = tx_conf_read(tc, TX39_SIBDMACTRL_REG);
210 	reg &= ~(TX39_SIBDMACTRL_ENDMARXSND |
211 	    TX39_SIBDMACTRL_ENDMATXSND |
212 	    TX39_SIBDMACTRL_ENDMARXTEL |
213 	    TX39_SIBDMACTRL_ENDMATXTEL);
214 	tx_conf_write(tc, TX39_SIBDMACTRL_REG, reg);
215 
216 	/*
217 	 * Enable subframe0 (BETTY)
218 	 */
219 	reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
220 	reg |= TX39_SIBCTRL_ENSF0;
221 	tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
222 }
223 
224 void
225 tx39sib_enable2(device_t dev)
226 {
227 	struct tx39sib_softc *sc = device_private(dev);
228 	tx_chipset_tag_t tc = sc->sc_tc;
229 	txreg_t reg;
230 
231 	reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
232 	reg |= TX39_SIBCTRL_ENSIB;
233 	tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
234 }
235 
236 void
237 tx39sib_disable(device_t dev)
238 {
239 	struct tx39sib_softc *sc = device_private(dev);
240 	tx_chipset_tag_t tc = sc->sc_tc;
241 	txreg_t reg;
242 	/* disable codec side */
243 	/* notyet */
244 
245 	/* disable TX39 side */
246 	reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
247 	reg &= ~(TX39_SIBCTRL_ENTEL | TX39_SIBCTRL_ENSND);
248 	tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
249 
250 	/*
251 	 * Disable subframe0/1 (BETTY/external codec)
252 	 */
253 	reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
254 	reg &= ~TX39_SIBCTRL_ENSF0;
255 	reg &= ~(TX39_SIBCTRL_ENSF1 | TX39_SIBCTRL_SELTELSF1 |
256 	    TX39_SIBCTRL_SELSNDSF1);
257 	tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
258 
259 	/* disable TX39SIB module */
260 	reg &= ~TX39_SIBCTRL_ENSIB;
261 	tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
262 }
263 
264 int
265 tx39sib_clock(device_t dev)
266 {
267 	struct tx39sib_softc *sc = device_private(dev);
268 
269 	return (TX39_CLK2X / sibsclk_divide_table[sc->sc_param.sp_clock]);
270 }
271 
272 int
273 tx39sib_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
274 {
275 	struct tx39sib_softc *sc = device_private(parent);
276 	struct txsib_attach_args sa;
277 
278 	sa.sa_tc	= sc->sc_tc;
279 	sa.sa_slot	= cf->cf_loc[TXSIBIFCF_SLOT];
280 	sa.sa_snd_rate	= sc->sc_param.sp_snd_rate;
281 	sa.sa_tel_rate	= sc->sc_param.sp_tel_rate;
282 
283 	if (sa.sa_slot == TXSIBIFCF_SLOT_DEFAULT) {
284 		printf("tx39sib_search: wildcarded slot, skipping\n");
285 		return (0);
286 	}
287 
288 	if (!(sc->sc_attached & (1 << sa.sa_slot)) &&/* not attached slot */
289 	    config_match(parent, cf, &sa)) {
290 		config_attach(parent, cf, &sa, tx39sib_print);
291 		sc->sc_attached |= (1 << sa.sa_slot);
292 	}
293 
294 	return (0);
295 }
296 
297 int
298 tx39sib_print(void *aux, const char *pnp)
299 {
300 	struct txsib_attach_args *sa = aux;
301 
302 	aprint_normal(" slot %d", sa->sa_slot);
303 
304 	return (QUIET);
305 }
306 
307 /*
308  * sync access method. don't use runtime.
309  */
310 
311 inline int
312 __txsibsf0_ready(tx_chipset_tag_t tc)
313 {
314 	int i;
315 
316 	tx_conf_write(tc, TX39_INTRSTATUS1_REG, TX39_INTRSTATUS1_SIBSF0INT);
317 	for (i = 0; (!(tx_conf_read(tc, TX39_INTRSTATUS1_REG) &
318 	    TX39_INTRSTATUS1_SIBSF0INT)) && i < 1000; i++) {
319 		if (i > 100 && !(i % 100)) {
320 			printf("sf0 busy loop: retry count %d\n", i);
321 		}
322 	}
323 
324 	if (i >= 1000) {
325 		printf("sf0 busy\n");
326 		return (0);
327 	}
328 
329 	return (1);
330 }
331 
332 void
333 txsibsf0_reg_write(tx_chipset_tag_t tc, int addr, u_int16_t val)
334 {
335 	txreg_t reg;
336 
337 	reg = txsibsf0_read(tc, addr);
338 	reg |= TX39_SIBSF0_WRITE;
339 	TX39_SIBSF0_REGDATA_CLR(reg);
340 	reg = TX39_SIBSF0_REGDATA_SET(reg, val);
341 
342 	__txsibsf0_ready(tc);
343 	tx_conf_write(tc, TX39_SIBSF0CTRL_REG, reg);
344 }
345 
346 u_int16_t
347 txsibsf0_reg_read(tx_chipset_tag_t tc, int addr)
348 {
349 	return (TX39_SIBSF0_REGDATA(txsibsf0_read(tc, addr)));
350 }
351 
352 u_int32_t
353 txsibsf0_read(tx_chipset_tag_t tc, int addr)
354 {
355 	txreg_t reg;
356 	int retry = 3;
357 
358 	do {
359 		reg = TX39_SIBSF0_REGADDR_SET(0, addr);
360 		__txsibsf0_ready(tc);
361 		tx_conf_write(tc, TX39_SIBSF0CTRL_REG, reg);
362 
363 		__txsibsf0_ready(tc);
364 		reg = tx_conf_read(tc, TX39_SIBSF0STAT_REG);
365 
366 	} while ((TX39_SIBSF0_REGADDR(reg) != addr) && --retry > 0);
367 
368 	if (retry <= 0)
369 		printf("txsibsf0_read: command failed\n");
370 
371 	return (reg);
372 }
373 
374 #ifdef TX39SIBDEBUG
375 #define ISSETPRINT_CTRL(r, m)						\
376 	dbg_bitmask_print(r, TX39_SIBCTRL_##m, #m)
377 #define ISSETPRINT_DMACTRL(r, m)					\
378 	dbg_bitmask_print(r, TX39_SIBDMACTRL_##m, #m)
379 
380 void
381 tx39sib_dump(struct tx39sib_softc *sc)
382 {
383 	tx_chipset_tag_t tc = sc->sc_tc;
384 	txreg_t reg;
385 
386 	reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
387 	ISSETPRINT_CTRL(reg, SIBIRQ);
388 	ISSETPRINT_CTRL(reg, ENCNTTEST);
389 	ISSETPRINT_CTRL(reg, ENDMATEST);
390 	ISSETPRINT_CTRL(reg, SNDMONO);
391 	ISSETPRINT_CTRL(reg, RMONOSNDIN);
392 	ISSETPRINT_CTRL(reg, TEL16);
393 	ISSETPRINT_CTRL(reg, SND16);
394 	ISSETPRINT_CTRL(reg, SELTELSF1);
395 	ISSETPRINT_CTRL(reg, SELSNDSF1);
396 	ISSETPRINT_CTRL(reg, ENTEL);
397 	ISSETPRINT_CTRL(reg, ENSND);
398 	ISSETPRINT_CTRL(reg, SIBLOOP);
399 	ISSETPRINT_CTRL(reg, ENSF1);
400 	ISSETPRINT_CTRL(reg, ENSF0);
401 	ISSETPRINT_CTRL(reg, ENSIB);
402 	printf("\n");
403 	printf("SCLKDIV %d\n", TX39_SIBCTRL_SCLKDIV(reg));
404 	printf("TELFSDIV %d\n", TX39_SIBCTRL_TELFSDIV(reg));
405 	printf("SNDFSDIV %d\n", TX39_SIBCTRL_SNDFSDIV(reg));
406 
407 	reg = tx_conf_read(tc, TX39_SIBDMACTRL_REG);
408 	ISSETPRINT_DMACTRL(reg, SNDBUFF1TIME);
409 	ISSETPRINT_DMACTRL(reg, SNDDMALOOP);
410 	ISSETPRINT_DMACTRL(reg, ENDMARXSND);
411 	ISSETPRINT_DMACTRL(reg, ENDMATXSND);
412 	ISSETPRINT_DMACTRL(reg, TELBUFF1TIME);
413 	ISSETPRINT_DMACTRL(reg, TELDMALOOP);
414 	ISSETPRINT_DMACTRL(reg, ENDMARXTEL);
415 	ISSETPRINT_DMACTRL(reg, ENDMATXTEL);
416 	printf("\n");
417 	printf("SNDDMAPTR %d\n", TX39_SIBDMACTRL_TELDMAPTR(reg));
418 	printf("TELDMAPTR %d\n", TX39_SIBDMACTRL_SNDDMAPTR(reg));
419 
420 }
421 #endif /* TX39SIBDEBUG */
422