tx39sib.c revision 1.2 1 /* $NetBSD: tx39sib.c,v 1.2 2000/01/12 14:56:19 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 tx39sib_debug = 0;
51 #define DPRINTF(arg) if (vrpiu_debug) 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 = {
98 0, /* SIBSCLK = 9.216MHz */
99 13, /* audio: CD-Audio */
100 40, /* telecom: 7.2kHz */
101 TX39_SIBCTRL_SND16, /* Audio 16bit mono */
102 TX39_SIBCTRL_TEL16 /* Telecom 16bit mono */
103 };
104
105 struct tx39sib_softc {
106 struct device sc_dev;
107 tx_chipset_tag_t sc_tc;
108
109 struct tx39sib_param sc_param;
110 int sc_attached;
111 };
112
113 __inline int __txsibsf0_ready __P((tx_chipset_tag_t));
114 void tx39sib_dump __P((struct tx39sib_softc*));
115
116 struct cfattach tx39sib_ca = {
117 sizeof(struct tx39sib_softc), tx39sib_match, tx39sib_attach
118 };
119
120 int
121 tx39sib_match(parent, cf, aux)
122 struct device *parent;
123 struct cfdata *cf;
124 void *aux;
125 {
126 return 1;
127 }
128
129 void
130 tx39sib_attach(parent, self, aux)
131 struct device *parent;
132 struct device *self;
133 void *aux;
134 {
135 struct txsim_attach_args *ta = aux;
136 struct tx39sib_softc *sc = (void*)self;
137 tx_chipset_tag_t tc;
138
139 sc->sc_tc = tc = ta->ta_tc;
140
141 /* set default param */
142 sc->sc_param = tx39sib_param_default;
143 #define MHZ(a) ((a) / 1000000), (((a) % 1000000) / 1000)
144 printf(": %d.%03d MHz", MHZ(tx39sib_clock(self)));
145
146 printf("\n");
147 #ifdef TX39SIBDEBUG
148 tx39sib_dump(sc);
149 #endif
150 /* enable subframe0 */
151 tx39sib_enable1(self);
152 /* enable SIB */
153 tx39sib_enable2(self);
154
155 #ifdef TX39SIBDEBUG
156 tx39sib_dump(sc);
157 #endif
158
159 config_search(tx39sib_search, self, tx39sib_print);
160 }
161
162 void
163 tx39sib_enable1(dev)
164 struct device *dev;
165 {
166 struct tx39sib_softc *sc = (void*)dev;
167 struct tx39sib_param *param = &sc->sc_param;
168 tx_chipset_tag_t tc = sc->sc_tc;
169
170 txreg_t reg;
171
172 /* disable SIB */
173 tx39sib_disable(dev);
174
175 /* setup */
176 reg = 0;
177 /* SIB clock rate */
178 reg = TX39_SIBCTRL_SCLKDIV_SET(reg, param->sp_clock);
179 /* sampling rate (sound) */
180 reg = TX39_SIBCTRL_SNDFSDIV_SET(reg, param->sp_snd_rate - 1);
181 /* sampling rate (telecom) */
182 reg = TX39_SIBCTRL_TELFSDIV_SET(reg, param->sp_tel_rate - 1);
183 /* data format (8/16bit) */
184 reg |= param->sp_sf0sndmode;
185 reg |= param->sp_sf0telmode;
186 tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
187
188 /* DMA */
189 reg = tx_conf_read(tc, TX39_SIBDMACTRL_REG);
190 reg &= ~(TX39_SIBDMACTRL_ENDMARXSND |
191 TX39_SIBDMACTRL_ENDMATXSND |
192 TX39_SIBDMACTRL_ENDMARXTEL |
193 TX39_SIBDMACTRL_ENDMATXTEL);
194 tx_conf_write(tc, TX39_SIBDMACTRL_REG, reg);
195
196 /*
197 * Enable subframe0 (BETTY)
198 */
199 reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
200 reg |= TX39_SIBCTRL_ENSF0;
201 tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
202 }
203
204 void
205 tx39sib_enable2(dev)
206 struct device *dev;
207 {
208 struct tx39sib_softc *sc = (void*)dev;
209 tx_chipset_tag_t tc = sc->sc_tc;
210 txreg_t reg;
211
212 reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
213 reg |= TX39_SIBCTRL_ENSIB;
214 tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
215 }
216
217 void
218 tx39sib_disable(dev)
219 struct device *dev;
220 {
221 struct tx39sib_softc *sc = (void*)dev;
222 tx_chipset_tag_t tc = sc->sc_tc;
223 txreg_t reg;
224 /* disable codec side */
225 /* notyet */
226
227 /* disable TX39 side */
228 reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
229 reg &= ~(TX39_SIBCTRL_ENTEL | TX39_SIBCTRL_ENSND);
230 tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
231
232 /*
233 * Disable subframe0/1 (BETTY/external codec)
234 */
235 reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
236 reg &= ~TX39_SIBCTRL_ENSF0;
237 reg &= ~(TX39_SIBCTRL_ENSF1 | TX39_SIBCTRL_SELTELSF1 |
238 TX39_SIBCTRL_SELSNDSF1);
239 tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
240
241 /* disable TX39SIB module */
242 reg &= ~TX39_SIBCTRL_ENSIB;
243 tx_conf_write(tc, TX39_SIBCTRL_REG, reg);
244 }
245
246 int
247 tx39sib_clock(dev)
248 struct device *dev;
249 {
250 struct tx39sib_softc *sc = (void*)dev;
251
252 return TX39_CLK2X / sibsclk_divide_table[sc->sc_param.sp_clock];
253 }
254
255 int
256 tx39sib_search(parent, cf, aux)
257 struct device *parent;
258 struct cfdata *cf;
259 void *aux;
260 {
261 struct tx39sib_softc *sc = (void*)parent;
262 struct txsib_attach_args sa;
263
264 sa.sa_tc = sc->sc_tc;
265 sa.sa_slot = cf->cf_loc[TXSIBIFCF_SLOT];
266 sa.sa_snd_rate = sc->sc_param.sp_snd_rate;
267 sa.sa_tel_rate = sc->sc_param.sp_tel_rate;
268
269 if (sa.sa_slot == TXSIBIFCF_SLOT_DEFAULT) {
270 printf("tx39sib_search: wildcarded slot, skipping\n");
271 return 0;
272 }
273
274 if (!(sc->sc_attached & (1 << sa.sa_slot)) &&/* not attached slot */
275 (*cf->cf_attach->ca_match)(parent, cf, &sa)) {
276 config_attach(parent, cf, &sa, tx39sib_print);
277 sc->sc_attached |= (1 << sa.sa_slot);
278 }
279
280 return 0;
281 }
282
283 int
284 tx39sib_print(aux, pnp)
285 void *aux;
286 const char *pnp;
287 {
288 struct txsib_attach_args *sa = aux;
289
290 printf(" slot %d", sa->sa_slot);
291
292 return QUIET;
293 }
294
295 /*
296 * sync access method. don't use runtime.
297 */
298
299 __inline int
300 __txsibsf0_ready(tc)
301 tx_chipset_tag_t tc;
302 {
303 int i;
304
305 tx_conf_write(tc, TX39_INTRSTATUS1_REG, TX39_INTRSTATUS1_SIBSF0INT);
306 for (i = 0; (!(tx_conf_read(tc, TX39_INTRSTATUS1_REG) &
307 TX39_INTRSTATUS1_SIBSF0INT)) && i < 100; i++)
308 ;
309 if (i == 100) {
310 printf("sf0 busy\n");
311 return 0;
312 } else if (i > 50) {
313 printf("sf0 busy loop:%d\n", i);
314 return 0;
315 }
316
317 return 1;
318 }
319
320 void
321 txsibsf0_reg_write(tc, addr, val)
322 tx_chipset_tag_t tc;
323 int addr;
324 u_int16_t val;
325 {
326 txreg_t reg;
327
328 reg = txsibsf0_read(tc, addr);
329 reg |= TX39_SIBSF0_WRITE;
330 TX39_SIBSF0_REGDATA_CLR(reg);
331 reg = TX39_SIBSF0_REGDATA_SET(reg, val);
332
333 __txsibsf0_ready(tc);
334 tx_conf_write(tc, TX39_SIBSF0CTRL_REG, reg);
335 }
336
337 u_int16_t
338 txsibsf0_reg_read(tc, addr)
339 tx_chipset_tag_t tc;
340 int addr;
341 {
342 return TX39_SIBSF0_REGDATA(txsibsf0_read(tc, addr));
343 }
344
345 u_int32_t
346 txsibsf0_read(tc, addr)
347 tx_chipset_tag_t tc;
348 int addr;
349 {
350 txreg_t reg;
351 int retry = 3;
352
353 do {
354 reg = TX39_SIBSF0_REGADDR_SET(0, addr);
355 __txsibsf0_ready(tc);
356 tx_conf_write(tc, TX39_SIBSF0CTRL_REG, reg);
357
358 __txsibsf0_ready(tc);
359 reg = tx_conf_read(tc, TX39_SIBSF0STAT_REG);
360
361 } while ((TX39_SIBSF0_REGADDR(reg) != addr) && --retry > 0);
362
363 if (retry <= 0)
364 printf("txsibsf0_read: command failed\n");
365
366 return reg;
367 }
368
369 /*
370 * debug functions.
371 */
372
373 #define ISSETPRINT_CTRL(r, m) \
374 __is_set_print(r, TX39_SIBCTRL_##m, #m)
375 #define ISSETPRINT_DMACTRL(r, m) \
376 __is_set_print(r, TX39_SIBDMACTRL_##m, #m)
377
378 void
379 tx39sib_dump(sc)
380 struct tx39sib_softc *sc;
381 {
382 tx_chipset_tag_t tc = sc->sc_tc;
383 txreg_t reg;
384
385 reg = tx_conf_read(tc, TX39_SIBCTRL_REG);
386 ISSETPRINT_CTRL(reg, SIBIRQ);
387 ISSETPRINT_CTRL(reg, ENCNTTEST);
388 ISSETPRINT_CTRL(reg, ENDMATEST);
389 ISSETPRINT_CTRL(reg, SNDMONO);
390 ISSETPRINT_CTRL(reg, RMONOSNDIN);
391 ISSETPRINT_CTRL(reg, TEL16);
392 ISSETPRINT_CTRL(reg, SND16);
393 ISSETPRINT_CTRL(reg, SELTELSF1);
394 ISSETPRINT_CTRL(reg, SELSNDSF1);
395 ISSETPRINT_CTRL(reg, ENTEL);
396 ISSETPRINT_CTRL(reg, ENSND);
397 ISSETPRINT_CTRL(reg, SIBLOOP);
398 ISSETPRINT_CTRL(reg, ENSF1);
399 ISSETPRINT_CTRL(reg, ENSF0);
400 ISSETPRINT_CTRL(reg, ENSIB);
401 printf("\n");
402 printf("SCLKDIV %d\n", TX39_SIBCTRL_SCLKDIV(reg));
403 printf("TELFSDIV %d\n", TX39_SIBCTRL_TELFSDIV(reg));
404 printf("SNDFSDIV %d\n", TX39_SIBCTRL_SNDFSDIV(reg));
405
406 reg = tx_conf_read(tc, TX39_SIBDMACTRL_REG);
407 ISSETPRINT_DMACTRL(reg, SNDBUFF1TIME);
408 ISSETPRINT_DMACTRL(reg, SNDDMALOOP);
409 ISSETPRINT_DMACTRL(reg, ENDMARXSND);
410 ISSETPRINT_DMACTRL(reg, ENDMATXSND);
411 ISSETPRINT_DMACTRL(reg, TELBUFF1TIME);
412 ISSETPRINT_DMACTRL(reg, TELDMALOOP);
413 ISSETPRINT_DMACTRL(reg, ENDMARXTEL);
414 ISSETPRINT_DMACTRL(reg, ENDMATXTEL);
415 printf("\n");
416 printf("SNDDMAPTR %d\n", TX39_SIBDMACTRL_TELDMAPTR(reg));
417 printf("TELDMAPTR %d\n", TX39_SIBDMACTRL_SNDDMAPTR(reg));
418
419 }
420