1/* $NetBSD: tspld.c,v 1.27 2023/12/20 13:55:18 thorpej Exp $ */ 2 3/*- 4 * Copyright (c) 2004 Jesse Off 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. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 * 28 */ 29 30#include <sys/cdefs.h> 31__KERNEL_RCSID(0, "$NetBSD: tspld.c,v 1.27 2023/12/20 13:55:18 thorpej Exp $"); 32 33#include <sys/param.h> 34#include <sys/callout.h> 35#include <sys/kernel.h> 36#include <sys/sysctl.h> 37#include <sys/systm.h> 38#include <sys/device.h> 39#include <sys/wdog.h> 40 41#include <sys/bus.h> 42#include <machine/cpu.h> 43#include <machine/autoconf.h> 44#include "isa.h" 45#if NISA > 0 46#include <dev/isa/isavar.h> 47#include <machine/isa_machdep.h> 48#endif 49 50#include <evbarm/tsarm/tsarmreg.h> 51#include <evbarm/tsarm/tspldvar.h> 52#include <arm/ep93xx/ep93xxvar.h> 53#include <arm/ep93xx/ep93xxreg.h> 54#include <arm/ep93xx/epgpioreg.h> 55#include <arm/arm32/machdep.h> 56#include <arm/cpufunc.h> 57#include <dev/sysmon/sysmonvar.h> 58 59int tspldmatch (device_t, cfdata_t, void *); 60void tspldattach (device_t, device_t, void *); 61static int tspld_wdog_setmode (struct sysmon_wdog *); 62static int tspld_wdog_tickle (struct sysmon_wdog *); 63int tspld_search (device_t, cfdata_t, const int *, void *); 64int tspld_print (void *, const char *); 65void boardtemp_poll (void *); 66 67struct tspld_softc { 68 bus_space_tag_t sc_iot; 69 bus_space_handle_t sc_wdogfeed_ioh; 70 bus_space_handle_t sc_wdogctrl_ioh; 71 struct sysmon_wdog sc_wdog; 72 bus_space_handle_t sc_ssph; 73 bus_space_handle_t sc_gpioh; 74 unsigned const char * sc_com2mode; 75 unsigned const char * sc_model; 76 unsigned char sc_pldrev[4]; 77 uint32_t sc_rs485; 78 uint32_t sc_adc; 79 uint32_t sc_jp[6]; 80 uint32_t sc_blaster_present; 81 uint32_t sc_blaster_boot; 82 uint32_t boardtemp; 83 uint32_t boardtemp_5s; 84 uint32_t boardtemp_30s; 85 struct callout boardtemp_callout; 86}; 87 88CFATTACH_DECL_NEW(tspld, sizeof(struct tspld_softc), 89 tspldmatch, tspldattach, NULL, NULL); 90 91void tspld_callback(device_t); 92 93#define GPIO_GET(x) bus_space_read_4(sc->sc_iot, sc->sc_gpioh, \ 94 (EP93XX_GPIO_ ## x)) 95 96#define GPIO_SET(x, y) bus_space_write_4(sc->sc_iot, sc->sc_gpioh, \ 97 (EP93XX_GPIO_ ## x), (y)) 98 99#define GPIO_SETBITS(x, y) bus_space_write_4(sc->sc_iot, sc->sc_gpioh, \ 100 (EP93XX_GPIO_ ## x), GPIO_GET(x) | (y)) 101 102#define GPIO_CLEARBITS(x, y) bus_space_write_4(sc->sc_iot, sc->sc_gpioh, \ 103 (EP93XX_GPIO_ ## x), GPIO_GET(x) & (~(y))) 104 105#define SSP_GET(x) bus_space_read_4(sc->sc_iot, sc->sc_ssph, \ 106 (EP93XX_SSP_ ## x)) 107 108#define SSP_SET(x, y) bus_space_write_4(sc->sc_iot, sc->sc_ssph, \ 109 (EP93XX_SSP_ ## x), (y)) 110 111#define SSP_SETBITS(x, y) bus_space_write_4(sc->sc_iot, sc->sc_ssph, \ 112 (EP93XX_SSP_ ## x), SSP_GET(x) | (y)) 113 114#define SSP_CLEARBITS(x, y) bus_space_write_4(sc->sc_iot, sc->sc_ssph, \ 115 (EP93XX_SSP_ ## x), SSP_GET(x) & (~(y))) 116 117int 118tspldmatch(device_t parent, cfdata_t match, void *aux) 119{ 120 121 return 1; 122} 123 124void 125boardtemp_poll(void *arg) 126{ 127 struct tspld_softc *sc = arg; 128 uint16_t val; 129 130 /* Disable chip select */ 131 GPIO_SET(PFDDR, 0x0); 132 133 val = SSP_GET(SSPDR) & 0xffff; 134 sc->boardtemp = ((int16_t)val >> 3) * 62500; 135 sc->boardtemp_5s = sc->boardtemp_5s / 20 * 19 + sc->boardtemp / 20; 136 sc->boardtemp_30s = sc->boardtemp_30s / 120 * 119 + sc->boardtemp / 120; 137 138 callout_schedule(&sc->boardtemp_callout, hz / 4); 139 140 /* Enable chip select */ 141 GPIO_SET(PFDDR, 0x4); 142 143 /* Send read command */ 144 SSP_SET(SSPDR, 0x8000); 145} 146 147void 148tspldattach(device_t parent, device_t self, void *aux) 149{ 150 int i, rev, features, jp, model; 151 struct tspld_softc *sc = device_private(self); 152 bus_space_handle_t ioh; 153 const struct sysctlnode *node; 154 155 if (sysctl_createv(NULL, 0, NULL, &node, 156 0, CTLTYPE_NODE, device_xname(self), 157 NULL, 158 NULL, 0, NULL, 0, 159 CTL_HW, CTL_CREATE, CTL_EOL) != 0) { 160 printf("%s: could not create sysctl\n", 161 device_xname(self)); 162 return; 163 } 164 165 sc->sc_iot = &ep93xx_bs_tag; 166 bus_space_map(sc->sc_iot, TS7XXX_IO16_HWBASE + TS7XXX_MODEL, 2, 0, 167 &ioh); 168 model = bus_space_read_2(sc->sc_iot, ioh, 0) & 0x7; 169 sc->sc_model = (model ? "TS-7250" : "TS-7200"); 170 if ((i = sysctl_createv(NULL, 0, NULL, NULL, 171 0, CTLTYPE_STRING, "boardmodel", 172 SYSCTL_DESCR("Technologic Systems board model"), 173 NULL, 0, __UNCONST(sc->sc_model), 0, 174 CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL)) 175 != 0) { 176 printf("%s: could not create sysctl\n", 177 device_xname(self)); 178 return; 179 } 180 bus_space_unmap(sc->sc_iot, ioh, 2); 181 182 bus_space_map(sc->sc_iot, TS7XXX_IO16_HWBASE + TS7XXX_PLDREV, 2, 0, 183 &ioh); 184 rev = bus_space_read_2(sc->sc_iot, ioh, 0) & 0x7; 185 rev = 'A' + rev - 1; 186 sc->sc_pldrev[0] = rev; 187 sc->sc_pldrev[1] = 0; 188 if ((i = sysctl_createv(NULL, 0, NULL, NULL, 189 0, CTLTYPE_STRING, "pldrev", 190 SYSCTL_DESCR("CPLD revision"), 191 NULL, 0, sc->sc_pldrev, 0, 192 CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL)) 193 != 0) { 194 printf("%s: could not create sysctl\n", 195 device_xname(self)); 196 return; 197 } 198 bus_space_unmap(sc->sc_iot, ioh, 2); 199 200 bus_space_map(sc->sc_iot, TS7XXX_IO16_HWBASE + TS7XXX_FEATURES, 2, 0, 201 &ioh); 202 features = bus_space_read_2(sc->sc_iot, ioh, 0) & 0x7; 203 bus_space_unmap(sc->sc_iot, ioh, 2); 204 205 bus_space_map(sc->sc_iot, TS7XXX_IO8_HWBASE + TS7XXX_STATUS1, 1, 0, 206 &ioh); 207 i = bus_space_read_1(sc->sc_iot, ioh, 0) & 0x1f; 208 jp = (~((i & 0x18) >> 1) & 0xc) | (i & 0x3); 209 bus_space_unmap(sc->sc_iot, ioh, 1); 210 211 if ((i = sysctl_createv(NULL, 0, NULL, NULL, 212 0, CTLTYPE_INT, "blaster_present", 213 SYSCTL_DESCR("Whether or not a TS-9420/TS-9202 blaster board is connected"), 214 NULL, 0, &sc->sc_blaster_present, 0, 215 CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL)) 216 != 0) { 217 printf("%s: could not create sysctl\n", 218 device_xname(self)); 219 return; 220 } 221 if ((i = sysctl_createv(NULL, 0, NULL, NULL, 222 0, CTLTYPE_INT, "blaster_boot", 223 SYSCTL_DESCR("Whether or not a blast board was used to boot"), 224 NULL, 0, &sc->sc_blaster_boot, 0, 225 CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL)) 226 != 0) { 227 printf("%s: could not create sysctl\n", 228 device_xname(self)); 229 return; 230 } 231 bus_space_map(sc->sc_iot, TS7XXX_IO16_HWBASE + TS7XXX_STATUS2, 2, 0, 232 &ioh); 233 i = bus_space_read_2(sc->sc_iot, ioh, 0) & 0x6; 234 sc->sc_blaster_boot = sc->sc_blaster_present = 0; 235 if (i & 0x2) 236 sc->sc_blaster_boot = 1; 237 if (i & 0x4) 238 sc->sc_blaster_present = 1; 239 jp |= (i << 4); 240 bus_space_unmap(sc->sc_iot, ioh, 1); 241 242 if ((i = sysctl_createv(NULL, 0, NULL, NULL, 243 0, CTLTYPE_INT, "rs485_avail", 244 SYSCTL_DESCR("RS485 level driver for COM2 available"), 245 NULL, 0, &sc->sc_rs485, 0, 246 CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL)) 247 != 0) { 248 printf("%s: could not create sysctl\n", 249 device_xname(self)); 250 return; 251 } 252 sc->sc_com2mode = "rs232"; 253 if ((i = sysctl_createv(NULL, 0, NULL, NULL, 254 0, CTLTYPE_STRING, "com2_mode", 255 SYSCTL_DESCR("line driver type for COM2"), 256 NULL, 0, __UNCONST(sc->sc_com2mode), 0, 257 CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL)) 258 != 0) { 259 printf("%s: could not create sysctl\n", 260 device_xname(self)); 261 return; 262 } 263 if ((i = sysctl_createv(NULL, 0, NULL, NULL, 264 0, CTLTYPE_INT, "max197adc_avail", 265 SYSCTL_DESCR("Maxim 197 Analog to Digital Converter available"), 266 NULL, 0, &sc->sc_adc, 0, 267 CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL)) 268 != 0) { 269 printf("%s: could not create sysctl\n", 270 device_xname(self)); 271 return; 272 } 273 printf(": Technologic Systems %s rev %c, features 0x%x", 274 sc->sc_model, rev, features); 275 sc->sc_adc = sc->sc_rs485 = 0; 276 if (features == 0x1) { 277 printf("<MAX197-ADC>"); 278 sc->sc_adc = 1; 279 } else if (features == 0x2) { 280 printf("<RS485>"); 281 sc->sc_rs485 = 1; 282 } else if (features == 0x3) { 283 printf("<MAX197-ADC,RS485>"); 284 sc->sc_adc = sc->sc_rs485 = 1; 285 } 286 printf("\n"); 287 if ((i = sysctl_createv(NULL, 0, NULL, NULL, 288 0, CTLTYPE_INT, "jp1", 289 SYSCTL_DESCR("onboard jumper setting"), 290 NULL, 0, &sc->sc_jp[0], 0, 291 CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL)) 292 != 0) { 293 printf("%s: could not create sysctl\n", 294 device_xname(self)); 295 return; 296 } 297 if ((i = sysctl_createv(NULL, 0, NULL, NULL, 298 0, CTLTYPE_INT, "jp2", 299 SYSCTL_DESCR("onboard jumper setting"), 300 NULL, 0, &sc->sc_jp[1], 0, 301 CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL)) 302 != 0) { 303 printf("%s: could not create sysctl\n", 304 device_xname(self)); 305 return; 306 } 307 if ((i = sysctl_createv(NULL, 0, NULL, NULL, 308 0, CTLTYPE_INT, "jp3", 309 SYSCTL_DESCR("onboard jumper setting"), 310 NULL, 0, &sc->sc_jp[2], 0, 311 CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL)) 312 != 0) { 313 printf("%s: could not create sysctl\n", 314 device_xname(self)); 315 return; 316 } 317 if ((i = sysctl_createv(NULL, 0, NULL, NULL, 318 0, CTLTYPE_INT, "jp4", 319 SYSCTL_DESCR("onboard jumper setting"), 320 NULL, 0, &sc->sc_jp[3], 0, 321 CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL)) 322 != 0) { 323 printf("%s: could not create sysctl\n", 324 device_xname(self)); 325 return; 326 } 327 if ((i = sysctl_createv(NULL, 0, NULL, NULL, 328 0, CTLTYPE_INT, "jp5", 329 SYSCTL_DESCR("onboard jumper setting"), 330 NULL, 0, &sc->sc_jp[4], 0, 331 CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL)) 332 != 0) { 333 printf("%s: could not create sysctl\n", 334 device_xname(self)); 335 return; 336 } 337 if ((i = sysctl_createv(NULL, 0, NULL, NULL, 338 0, CTLTYPE_INT, "jp6", 339 SYSCTL_DESCR("onboard jumper setting"), 340 NULL, 0, &sc->sc_jp[5], 0, 341 CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL)) 342 != 0) { 343 printf("%s: could not create sysctl\n", 344 device_xname(self)); 345 return; 346 } 347 printf("%s: jumpers 0x%x", device_xname(self), jp); 348 if (jp) { 349 printf("<"); 350 for(i = 0; i < 5; i++) { 351 if (jp & (1 << i)) { 352 sc->sc_jp[i + 1] = 1; 353 printf("JP%d", i + 2); 354 jp &= ~(1 << i); 355 if (jp) printf(","); 356 } else { 357 sc->sc_jp[i + 2] = 0; 358 } 359 } 360 printf(">"); 361 } 362 printf("\n"); 363 364 365 bus_space_map(sc->sc_iot, EP93XX_APB_HWBASE + EP93XX_APB_SSP, 366 EP93XX_APB_SSP_SIZE, 0, &sc->sc_ssph); 367 bus_space_map(sc->sc_iot, EP93XX_APB_HWBASE + EP93XX_APB_GPIO, 368 EP93XX_APB_GPIO_SIZE, 0, &sc->sc_gpioh); 369 SSP_SETBITS(SSPCR1, 0x10); 370 SSP_SET(SSPCR0, 0xf); 371 SSP_SET(SSPCPSR, 0xfe); 372 SSP_CLEARBITS(SSPCR1, 0x10); 373 SSP_SETBITS(SSPCR1, 0x10); 374 GPIO_SET(PFDR, 0x0); 375 callout_init(&sc->boardtemp_callout, 0); 376 callout_setfunc(&sc->boardtemp_callout, boardtemp_poll, sc); 377 boardtemp_poll(sc); 378 delay(1000); 379 boardtemp_poll(sc); 380 sc->boardtemp_5s = sc->boardtemp_30s = sc->boardtemp; 381#define DEGF(c) ((c) * 9 / 5 + 32000000) 382 printf("%s: board temperature %d.%02d degC (%d.%02d degF)\n", 383 device_xname(self), 384 sc->boardtemp / 1000000, sc->boardtemp / 10000 % 100, 385 DEGF(sc->boardtemp) / 1000000, DEGF(sc->boardtemp) / 10000 % 100); 386#undef DEGF 387 if ((i = sysctl_createv(NULL, 0, NULL, NULL, 388 0, CTLTYPE_INT, "board_temp", 389 SYSCTL_DESCR("board temperature in micro degrees Celsius"), 390 NULL, 0, &sc->boardtemp, 0, 391 CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL)) 392 != 0) { 393 printf("%s: could not create sysctl\n", 394 device_xname(self)); 395 return; 396 } 397 398 if ((i = sysctl_createv(NULL, 0, NULL, NULL, 399 0, CTLTYPE_INT, "board_temp_5s", 400 SYSCTL_DESCR("5 second average board temperature in micro degrees Celsius"), 401 NULL, 0, &sc->boardtemp_5s, 0, 402 CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL)) 403 != 0) { 404 printf("%s: could not create sysctl\n", 405 device_xname(self)); 406 return; 407 } 408 409 if ((i = sysctl_createv(NULL, 0, NULL, NULL, 410 0, CTLTYPE_INT, "board_temp_30s", 411 SYSCTL_DESCR("30 second average board temperature in micro degrees Celsius"), 412 NULL, 0, &sc->boardtemp_30s, 0, 413 CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL)) 414 != 0) { 415 printf("%s: could not create sysctl\n", 416 device_xname(self)); 417 return; 418 } 419 420 bus_space_map(sc->sc_iot, TS7XXX_IO16_HWBASE + TS7XXX_WDOGCTRL, 2, 0, 421 &sc->sc_wdogctrl_ioh); 422 bus_space_map(sc->sc_iot, TS7XXX_IO16_HWBASE + TS7XXX_WDOGFEED, 2, 0, 423 &sc->sc_wdogfeed_ioh); 424 425 sc->sc_wdog.smw_name = device_xname(self); 426 sc->sc_wdog.smw_cookie = sc; 427 sc->sc_wdog.smw_setmode = tspld_wdog_setmode; 428 sc->sc_wdog.smw_tickle = tspld_wdog_tickle; 429 sc->sc_wdog.smw_period = 8; 430 sysmon_wdog_register(&sc->sc_wdog); 431 tspld_wdog_setmode(&sc->sc_wdog); 432 433 /* Set the on board peripherals bus callback */ 434 config_defer(self, tspld_callback); 435} 436 437int 438tspld_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux) 439{ 440 struct tspld_softc *sc = device_private(parent); 441 struct tspld_attach_args sa; 442 443 sa.ta_iot = sc->sc_iot; 444 445 if (config_probe(parent, cf, &sa)) 446 config_attach(parent, cf, &sa, tspld_print, CFARGS_NONE); 447 448 return (0); 449} 450 451int 452tspld_print(void *aux, const char *name) 453{ 454 455 return (UNCONF); 456} 457 458void 459tspld_callback(device_t self) 460{ 461#if NISA > 0 462 struct isabus_attach_args iba; 463 464 /* 465 * Attach the ISA bus behind this bridge. 466 */ 467 memset(&iba, 0, sizeof(iba)); 468 iba.iba_iot = &isa_io_bs_tag; 469 iba.iba_memt = &isa_mem_bs_tag; 470 config_found(self, &iba, isabusprint, 471 CFARGS(.iattr = "isabus")); 472#endif 473 /* 474 * Attach each devices 475 */ 476 config_search(self, NULL, 477 CFARGS(.search = tspld_search, 478 .iattr = "tspldbus")); 479} 480 481static int 482tspld_wdog_tickle(struct sysmon_wdog *smw) 483{ 484 struct tspld_softc *sc = (struct tspld_softc *)smw->smw_cookie; 485 486 bus_space_write_2(sc->sc_iot, sc->sc_wdogfeed_ioh, 0, 0x5); 487 return 0; 488} 489 490static int 491tspld_wdog_setmode(struct sysmon_wdog *smw) 492{ 493 int i, ret = 0; 494 struct tspld_softc *sc = (struct tspld_softc *)smw->smw_cookie; 495 496 i = disable_interrupts(I32_bit|F32_bit); 497 if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) { 498 bus_space_write_2(sc->sc_iot, sc->sc_wdogfeed_ioh, 0, 0x5); 499 bus_space_write_2(sc->sc_iot, sc->sc_wdogctrl_ioh, 0, 0); 500 } else { 501 if (smw->smw_period == WDOG_PERIOD_DEFAULT) { 502 smw->smw_period = 8; 503 } 504 505 bus_space_write_2(sc->sc_iot, sc->sc_wdogfeed_ioh, 0, 0x5); 506 switch (smw->smw_period) { 507 case 1: 508 bus_space_write_2(sc->sc_iot, sc->sc_wdogctrl_ioh, 0, 509 0x3); 510 break; 511 case 2: 512 bus_space_write_2(sc->sc_iot, sc->sc_wdogctrl_ioh, 0, 513 0x5); 514 break; 515 case 4: 516 bus_space_write_2(sc->sc_iot, sc->sc_wdogctrl_ioh, 0, 517 0x6); 518 break; 519 case 8: 520 bus_space_write_2(sc->sc_iot, sc->sc_wdogctrl_ioh, 0, 521 0x7); 522 break; 523 default: 524 ret = EINVAL; 525 } 526 } 527 restore_interrupts(i); 528 return ret; 529} 530