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