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