pm_direct.c revision 1.10
1/* $NetBSD: pm_direct.c,v 1.10 2001/02/27 07:33:18 matt Exp $ */ 2 3/* 4 * Copyright (C) 1997 Takashi Hamada 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 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Takashi Hamada 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32/* From: pm_direct.c 1.3 03/18/98 Takashi Hamada */ 33 34#ifdef DEBUG 35#ifndef ADB_DEBUG 36#define ADB_DEBUG 37#endif 38#endif 39 40/* #define PM_GRAB_SI 1 */ 41 42#include <sys/param.h> 43#include <sys/cdefs.h> 44#include <sys/device.h> 45#include <sys/systm.h> 46 47#include <machine/adbsys.h> 48#include <machine/cpu.h> 49 50#include <macppc/dev/adbvar.h> 51#include <macppc/dev/pm_direct.h> 52#include <macppc/dev/viareg.h> 53 54extern int adb_polling; /* Are we polling? (Debugger mode) */ 55 56/* hardware dependent values */ 57#define ADBDelay 100 /* XXX */ 58#define HwCfgFlags3 0x20000 /* XXX */ 59 60/* define the types of the Power Manager */ 61#define PM_HW_UNKNOWN 0x00 /* don't know */ 62#define PM_HW_PB1XX 0x01 /* PowerBook 1XX series */ 63#define PM_HW_PB5XX 0x02 /* PowerBook Duo and 5XX series */ 64 65/* useful macros */ 66#define PM_SR() read_via_reg(VIA1, vSR) 67#define PM_VIA_INTR_ENABLE() write_via_reg(VIA1, vIER, 0x90) 68#define PM_VIA_INTR_DISABLE() write_via_reg(VIA1, vIER, 0x10) 69#define PM_VIA_CLR_INTR() write_via_reg(VIA1, vIFR, 0x90) 70#if 0 71#define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x04) 72#define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x04) 73#define PM_IS_ON (0x02 == (read_via_reg(VIA2, vBufB) & 0x02)) 74#define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x02)) 75#else 76#define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x10) 77#define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x10) 78#define PM_IS_ON (0x08 == (read_via_reg(VIA2, vBufB) & 0x08)) 79#define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x08)) 80#endif 81 82/* 83 * Variables for internal use 84 */ 85int pmHardware = PM_HW_UNKNOWN; 86u_short pm_existent_ADB_devices = 0x0; /* each bit expresses the existent ADB device */ 87u_int pm_LCD_brightness = 0x0; 88u_int pm_LCD_contrast = 0x0; 89u_int pm_counter = 0; /* clock count */ 90 91/* these values shows that number of data returned after 'send' cmd is sent */ 92signed char pm_send_cmd_type[] = { 93 -1, -1, -1, -1, -1, -1, -1, -1, 94 -1, -1, -1, -1, -1, -1, -1, -1, 95 0x01, 0x01, -1, -1, -1, -1, -1, -1, 96 0x00, 0x00, -1, -1, -1, -1, -1, 0x00, 97 -1, 0x00, 0x02, 0x01, 0x01, -1, -1, -1, 98 0x00, -1, -1, -1, -1, -1, -1, -1, 99 0x04, 0x14, -1, 0x03, -1, -1, -1, -1, 100 0x00, 0x00, 0x02, 0x02, -1, -1, -1, -1, 101 0x01, 0x01, -1, -1, -1, -1, -1, -1, 102 0x00, 0x00, -1, -1, 0x01, -1, -1, -1, 103 0x01, 0x00, 0x02, 0x02, -1, 0x01, 0x03, 0x01, 104 0x00, 0x01, 0x00, 0x00, 0x00, -1, -1, -1, 105 0x02, -1, -1, -1, -1, -1, -1, -1, 106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -1, -1, 107 0x01, 0x01, 0x01, -1, -1, -1, -1, -1, 108 0x00, 0x00, -1, -1, -1, -1, 0x04, 0x04, 109 0x04, -1, 0x00, -1, -1, -1, -1, -1, 110 0x00, -1, -1, -1, -1, -1, -1, -1, 111 0x01, 0x02, -1, -1, -1, -1, -1, -1, 112 0x00, 0x00, -1, -1, -1, -1, -1, -1, 113 0x02, 0x02, 0x02, 0x04, -1, 0x00, -1, -1, 114 0x01, 0x01, 0x03, 0x02, -1, -1, -1, -1, 115 -1, -1, -1, -1, -1, -1, -1, -1, 116 -1, -1, -1, -1, -1, -1, -1, -1, 117 -1, -1, -1, -1, -1, -1, -1, -1, 118 -1, -1, -1, -1, -1, -1, -1, -1, 119 0x00, -1, -1, -1, -1, -1, -1, -1, 120 0x01, 0x01, -1, -1, 0x00, 0x00, -1, -1, 121 -1, 0x04, 0x00, -1, -1, -1, -1, -1, 122 0x03, -1, 0x00, -1, 0x00, -1, -1, 0x00, 123 -1, -1, -1, -1, -1, -1, -1, -1, 124 -1, -1, -1, -1, -1, -1, -1, -1 125}; 126 127/* these values shows that number of data returned after 'receive' cmd is sent */ 128signed char pm_receive_cmd_type[] = { 129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 130 -1, -1, -1, -1, -1, -1, -1, -1, 131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 132 0x02, 0x02, -1, -1, -1, -1, -1, 0x00, 133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 134 -1, -1, -1, -1, -1, -1, -1, -1, 135 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 136 0x05, 0x15, -1, 0x02, -1, -1, -1, -1, 137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 138 0x02, 0x02, -1, -1, -1, -1, -1, -1, 139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 140 0x02, 0x00, 0x03, 0x03, -1, -1, -1, -1, 141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 142 0x04, 0x04, 0x03, 0x09, -1, -1, -1, -1, 143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 144 -1, -1, -1, -1, -1, -1, 0x01, 0x01, 145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 146 0x06, -1, -1, -1, -1, -1, -1, -1, 147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 148 0x02, 0x02, -1, -1, -1, -1, -1, -1, 149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 150 0x02, 0x00, 0x00, 0x00, -1, -1, -1, -1, 151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 152 -1, -1, -1, -1, -1, -1, -1, -1, 153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 154 -1, -1, -1, -1, -1, -1, -1, -1, 155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 156 0x02, 0x02, -1, -1, 0x02, -1, -1, -1, 157 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 158 -1, -1, 0x02, -1, -1, -1, -1, 0x00, 159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 160 -1, -1, -1, -1, -1, -1, -1, -1, 161}; 162 163 164/* 165 * Define the private functions 166 */ 167 168/* for debugging */ 169#ifdef ADB_DEBUG 170void pm_printerr __P((char *, int, int, char *)); 171#endif 172 173int pm_wait_busy __P((int)); 174int pm_wait_free __P((int)); 175 176/* these functions are for the PB1XX series */ 177int pm_receive_pm1 __P((u_char *)); 178int pm_send_pm1 __P((u_char,int)); 179int pm_pmgrop_pm1 __P((PMData *)); 180void pm_intr_pm1 __P((void)); 181 182/* these functions are for the PB Duo series and the PB 5XX series */ 183int pm_receive_pm2 __P((u_char *)); 184int pm_send_pm2 __P((u_char)); 185int pm_pmgrop_pm2 __P((PMData *)); 186void pm_intr_pm2 __P((void)); 187 188/* this function is MRG-Based (for testing) */ 189int pm_pmgrop_mrg __P((PMData *)); 190 191/* these functions are called from adb_direct.c */ 192void pm_setup_adb __P((void)); 193void pm_check_adb_devices __P((int)); 194void pm_intr __P((void)); 195int pm_adb_op __P((u_char *, void *, void *, int)); 196 197/* these functions also use the variables of adb_direct.c */ 198void pm_adb_get_TALK_result __P((PMData *)); 199void pm_adb_get_ADB_data __P((PMData *)); 200void pm_adb_poll_next_device_pm1 __P((PMData *)); 201 202 203/* 204 * These variables are in adb_direct.c. 205 */ 206extern u_char *adbBuffer; /* pointer to user data area */ 207extern void *adbCompRout; /* pointer to the completion routine */ 208extern void *adbCompData; /* pointer to the completion routine data */ 209extern int adbWaiting; /* waiting for return data from the device */ 210extern int adbWaitingCmd; /* ADB command we are waiting for */ 211extern int adbStarting; /* doing ADB reinit, so do "polling" differently */ 212 213#define ADB_MAX_MSG_LENGTH 16 214#define ADB_MAX_HDR_LENGTH 8 215struct adbCommand { 216 u_char header[ADB_MAX_HDR_LENGTH]; /* not used yet */ 217 u_char data[ADB_MAX_MSG_LENGTH]; /* packet data only */ 218 u_char *saveBuf; /* where to save result */ 219 u_char *compRout; /* completion routine pointer */ 220 u_char *compData; /* completion routine data pointer */ 221 u_int cmd; /* the original command for this data */ 222 u_int unsol; /* 1 if packet was unsolicited */ 223 u_int ack_only; /* 1 for no special processing */ 224}; 225extern void adb_pass_up __P((struct adbCommand *)); 226 227#if 0 228/* 229 * Define the external functions 230 */ 231extern int zshard __P((int)); /* from zs.c */ 232#endif 233 234#ifdef ADB_DEBUG 235/* 236 * This function dumps contents of the PMData 237 */ 238void 239pm_printerr(ttl, rval, num, data) 240 char *ttl; 241 int rval; 242 int num; 243 char *data; 244{ 245 int i; 246 247 printf("pm: %s:%04x %02x ", ttl, rval, num); 248 for (i = 0; i < num; i++) 249 printf("%02x ", data[i]); 250 printf("\n"); 251} 252#endif 253 254 255 256/* 257 * Check the hardware type of the Power Manager 258 */ 259void 260pm_setup_adb() 261{ 262 pmHardware = PM_HW_PB5XX; /* XXX */ 263} 264 265 266/* 267 * Check the existent ADB devices 268 */ 269void 270pm_check_adb_devices(id) 271 int id; 272{ 273 u_short ed = 0x1; 274 275 ed <<= id; 276 pm_existent_ADB_devices |= ed; 277} 278 279 280/* 281 * Wait until PM IC is busy 282 */ 283int 284pm_wait_busy(delay) 285 int delay; 286{ 287 while (PM_IS_ON) { 288#ifdef PM_GRAB_SI 289#if 0 290 zshard(0); /* grab any serial interrupts */ 291#else 292 (void)intr_dispatch(0x70); 293#endif 294#endif 295 if ((--delay) < 0) 296 return 1; /* timeout */ 297 } 298 return 0; 299} 300 301 302/* 303 * Wait until PM IC is free 304 */ 305int 306pm_wait_free(delay) 307 int delay; 308{ 309 while (PM_IS_OFF) { 310#ifdef PM_GRAB_SI 311#if 0 312 zshard(0); /* grab any serial interrupts */ 313#else 314 (void)intr_dispatch(0x70); 315#endif 316#endif 317 if ((--delay) < 0) 318 return 0; /* timeout */ 319 } 320 return 1; 321} 322 323 324 325/* 326 * Functions for the PB1XX series 327 */ 328 329/* 330 * Receive data from PM for the PB1XX series 331 */ 332int 333pm_receive_pm1(data) 334 u_char *data; 335{ 336#if 0 337 int rval = 0xffffcd34; 338 339 via_reg(VIA2, vDirA) = 0x00; 340 341 switch (1) { 342 default: 343 if (pm_wait_busy(0x40) != 0) 344 break; /* timeout */ 345 346 PM_SET_STATE_ACKOFF(); 347 *data = via_reg(VIA2, 0x200); 348 349 rval = 0xffffcd33; 350 if (pm_wait_free(0x40) == 0) 351 break; /* timeout */ 352 353 rval = 0x00; 354 break; 355 } 356 357 PM_SET_STATE_ACKON(); 358 via_reg(VIA2, vDirA) = 0x00; 359 360 return rval; 361#else 362 panic("pm_receive_pm1"); 363#endif 364} 365 366 367 368/* 369 * Send data to PM for the PB1XX series 370 */ 371int 372pm_send_pm1(data, delay) 373 u_char data; 374 int delay; 375{ 376#if 0 377 int rval; 378 379 via_reg(VIA2, vDirA) = 0xff; 380 via_reg(VIA2, 0x200) = data; 381 382 PM_SET_STATE_ACKOFF(); 383 if (pm_wait_busy(0x400) != 0) { 384 PM_SET_STATE_ACKON(); 385 via_reg(VIA2, vDirA) = 0x00; 386 387 return 0xffffcd36; 388 } 389 390 rval = 0x0; 391 PM_SET_STATE_ACKON(); 392 if (pm_wait_free(0x40) == 0) 393 rval = 0xffffcd35; 394 395 PM_SET_STATE_ACKON(); 396 via_reg(VIA2, vDirA) = 0x00; 397 398 return rval; 399#else 400 panic("pm_send_pm1"); 401#endif 402} 403 404 405/* 406 * My PMgrOp routine for the PB1XX series 407 */ 408int 409pm_pmgrop_pm1(pmdata) 410 PMData *pmdata; 411{ 412#if 0 413 int i; 414 int s = 0x81815963; 415 u_char via1_vIER, via1_vDirA; 416 int rval = 0; 417 int num_pm_data = 0; 418 u_char pm_cmd; 419 u_char pm_data; 420 u_char *pm_buf; 421 422 /* disable all inetrrupts but PM */ 423 via1_vIER = via_reg(VIA1, vIER); 424 PM_VIA_INTR_DISABLE(); 425 426 via1_vDirA = via_reg(VIA1, vDirA); 427 428 switch (pmdata->command) { 429 default: 430 for (i = 0; i < 7; i++) { 431 via_reg(VIA2, vDirA) = 0x00; 432 433 /* wait until PM is free */ 434 if (pm_wait_free(ADBDelay) == 0) { /* timeout */ 435 via_reg(VIA2, vDirA) = 0x00; 436 /* restore formar value */ 437 via_reg(VIA1, vDirA) = via1_vDirA; 438 via_reg(VIA1, vIER) = via1_vIER; 439 return 0xffffcd38; 440 } 441 442 switch (mac68k_machine.machineid) { 443 case MACH_MACPB160: 444 case MACH_MACPB165: 445 case MACH_MACPB165C: 446 case MACH_MACPB180: 447 case MACH_MACPB180C: 448 { 449 int delay = ADBDelay * 16; 450 451 via_reg(VIA2, vDirA) = 0x00; 452 while ((via_reg(VIA2, 0x200) == 0x7f) && (delay >= 0)) 453 delay--; 454 455 if (delay < 0) { /* timeout */ 456 via_reg(VIA2, vDirA) = 0x00; 457 /* restore formar value */ 458 via_reg(VIA1, vIER) = via1_vIER; 459 return 0xffffcd38; 460 } 461 } 462 } /* end switch */ 463 464 s = splhigh(); 465 466 via1_vDirA = via_reg(VIA1, vDirA); 467 via_reg(VIA1, vDirA) &= 0x7f; 468 469 pm_cmd = (u_char)(pmdata->command & 0xff); 470 if ((rval = pm_send_pm1(pm_cmd, ADBDelay * 8)) == 0) 471 break; /* send command succeeded */ 472 473 via_reg(VIA1, vDirA) = via1_vDirA; 474 splx(s); 475 } /* end for */ 476 477 /* failed to send a command */ 478 if (i == 7) { 479 via_reg(VIA2, vDirA) = 0x00; 480 /* restore formar value */ 481 via_reg(VIA1, vDirA) = via1_vDirA; 482 via_reg(VIA1, vIER) = via1_vIER; 483 if (s != 0x81815963) 484 splx(s); 485 return 0xffffcd38; 486 } 487 488 /* send # of PM data */ 489 num_pm_data = pmdata->num_data; 490 if ((rval = pm_send_pm1((u_char)(num_pm_data & 0xff), ADBDelay * 8)) != 0) 491 break; /* timeout */ 492 493 /* send PM data */ 494 pm_buf = (u_char *)pmdata->s_buf; 495 for (i = 0; i < num_pm_data; i++) 496 if ((rval = pm_send_pm1(pm_buf[i], ADBDelay * 8)) != 0) 497 break; /* timeout */ 498 if ((i != num_pm_data) && (num_pm_data != 0)) 499 break; /* timeout */ 500 501 /* Will PM IC return data? */ 502 if ((pm_cmd & 0x08) == 0) { 503 rval = 0; 504 break; /* no returned data */ 505 } 506 507 rval = 0xffffcd37; 508 if (pm_wait_busy(ADBDelay) != 0) 509 break; /* timeout */ 510 511 /* receive PM command */ 512 if ((rval = pm_receive_pm1(&pm_data)) != 0) 513 break; 514 515 pmdata->command = pm_data; 516 517 /* receive number of PM data */ 518 if ((rval = pm_receive_pm1(&pm_data)) != 0) 519 break; /* timeout */ 520 num_pm_data = pm_data; 521 pmdata->num_data = num_pm_data; 522 523 /* receive PM data */ 524 pm_buf = (u_char *)pmdata->r_buf; 525 for (i = 0; i < num_pm_data; i++) { 526 if ((rval = pm_receive_pm1(&pm_data)) != 0) 527 break; /* timeout */ 528 pm_buf[i] = pm_data; 529 } 530 531 rval = 0; 532 } 533 534 via_reg(VIA2, vDirA) = 0x00; 535 536 /* restore formar value */ 537 via_reg(VIA1, vDirA) = via1_vDirA; 538 via_reg(VIA1, vIER) = via1_vIER; 539 if (s != 0x81815963) 540 splx(s); 541 542 return rval; 543#else 544 panic("pm_pmgrop_pm1"); 545#endif 546} 547 548 549/* 550 * My PM interrupt routine for PB1XX series 551 */ 552void 553pm_intr_pm1() 554{ 555#if 0 556 int s; 557 int rval; 558 PMData pmdata; 559 560 s = splhigh(); 561 562 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */ 563 564 /* ask PM what happend */ 565 pmdata.command = 0x78; 566 pmdata.num_data = 0; 567 pmdata.data[0] = pmdata.data[1] = 0; 568 pmdata.s_buf = &pmdata.data[2]; 569 pmdata.r_buf = &pmdata.data[2]; 570 rval = pm_pmgrop_pm1(&pmdata); 571 if (rval != 0) { 572#ifdef ADB_DEBUG 573 if (adb_debug) 574 printf("pm: PM is not ready. error code=%08x\n", rval); 575#endif 576 splx(s); 577 } 578 579 if ((pmdata.data[2] & 0x10) == 0x10) { 580 if ((pmdata.data[2] & 0x0f) == 0) { 581 /* ADB data that were requested by TALK command */ 582 pm_adb_get_TALK_result(&pmdata); 583 } else if ((pmdata.data[2] & 0x08) == 0x8) { 584 /* PM is requesting to poll */ 585 pm_adb_poll_next_device_pm1(&pmdata); 586 } else if ((pmdata.data[2] & 0x04) == 0x4) { 587 /* ADB device event */ 588 pm_adb_get_ADB_data(&pmdata); 589 } 590 } else { 591#ifdef ADB_DEBUG 592 if (adb_debug) 593 pm_printerr("driver does not supported this event.", 594 rval, pmdata.num_data, pmdata.data); 595#endif 596 } 597 598 splx(s); 599#else 600 panic("pm_intr_pm1"); 601#endif 602} 603 604 605 606/* 607 * Functions for the PB Duo series and the PB 5XX series 608 */ 609 610/* 611 * Receive data from PM for the PB Duo series and the PB 5XX series 612 */ 613int 614pm_receive_pm2(data) 615 u_char *data; 616{ 617 int i; 618 int rval; 619 620 rval = 0xffffcd34; 621 622 switch (1) { 623 default: 624 /* set VIA SR to input mode */ 625 via_reg_or(VIA1, vACR, 0x0c); 626 via_reg_and(VIA1, vACR, ~0x10); 627 i = PM_SR(); 628 629 PM_SET_STATE_ACKOFF(); 630 if (pm_wait_busy((int)ADBDelay*32) != 0) 631 break; /* timeout */ 632 633 PM_SET_STATE_ACKON(); 634 rval = 0xffffcd33; 635 if (pm_wait_free((int)ADBDelay*32) == 0) 636 break; /* timeout */ 637 638 *data = PM_SR(); 639 rval = 0; 640 641 break; 642 } 643 644 PM_SET_STATE_ACKON(); 645 via_reg_or(VIA1, vACR, 0x1c); 646 647 return rval; 648} 649 650 651 652/* 653 * Send data to PM for the PB Duo series and the PB 5XX series 654 */ 655int 656pm_send_pm2(data) 657 u_char data; 658{ 659 int rval; 660 661 via_reg_or(VIA1, vACR, 0x1c); 662 write_via_reg(VIA1, vSR, data); /* PM_SR() = data; */ 663 664 PM_SET_STATE_ACKOFF(); 665 rval = 0xffffcd36; 666 if (pm_wait_busy((int)ADBDelay*32) != 0) { 667 PM_SET_STATE_ACKON(); 668 669 via_reg_or(VIA1, vACR, 0x1c); 670 671 return rval; 672 } 673 674 PM_SET_STATE_ACKON(); 675 rval = 0xffffcd35; 676 if (pm_wait_free((int)ADBDelay*32) != 0) 677 rval = 0; 678 679 PM_SET_STATE_ACKON(); 680 via_reg_or(VIA1, vACR, 0x1c); 681 682 return rval; 683} 684 685 686 687/* 688 * My PMgrOp routine for the PB Duo series and the PB 5XX series 689 */ 690int 691pm_pmgrop_pm2(pmdata) 692 PMData *pmdata; 693{ 694 int i; 695 int s; 696 u_char via1_vIER; 697 int rval = 0; 698 int num_pm_data = 0; 699 u_char pm_cmd; 700 short pm_num_rx_data; 701 u_char pm_data; 702 u_char *pm_buf; 703 704 s = splhigh(); 705 706 /* disable all inetrrupts but PM */ 707 via1_vIER = 0x10; 708 via1_vIER &= read_via_reg(VIA1, vIER); 709 write_via_reg(VIA1, vIER, via1_vIER); 710 if (via1_vIER != 0x0) 711 via1_vIER |= 0x80; 712 713 switch (pmdata->command) { 714 default: 715 /* wait until PM is free */ 716 pm_cmd = (u_char)(pmdata->command & 0xff); 717 rval = 0xcd38; 718 if (pm_wait_free(ADBDelay * 4) == 0) 719 break; /* timeout */ 720 721 if (HwCfgFlags3 & 0x00200000) { 722 /* PB 160, PB 165(c), PB 180(c)? */ 723 int delay = ADBDelay * 16; 724 725 write_via_reg(VIA2, vDirA, 0x00); 726 while ((read_via_reg(VIA2, 0x200) == 0x07) && 727 (delay >= 0)) 728 delay--; 729 730 if (delay < 0) { 731 rval = 0xffffcd38; 732 break; /* timeout */ 733 } 734 } 735 736 /* send PM command */ 737 if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff)))) 738 break; /* timeout */ 739 740 /* send number of PM data */ 741 num_pm_data = pmdata->num_data; 742 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */ 743 if (pm_send_cmd_type[pm_cmd] < 0) { 744 if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0) 745 break; /* timeout */ 746 pmdata->command = 0; 747 } 748 } else { /* PB 1XX series ? */ 749 if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0) 750 break; /* timeout */ 751 } 752 /* send PM data */ 753 pm_buf = (u_char *)pmdata->s_buf; 754 for (i = 0 ; i < num_pm_data; i++) 755 if ((rval = pm_send_pm2(pm_buf[i])) != 0) 756 break; /* timeout */ 757 if (i != num_pm_data) 758 break; /* timeout */ 759 760 761 /* check if PM will send me data */ 762 pm_num_rx_data = pm_receive_cmd_type[pm_cmd]; 763 pmdata->num_data = pm_num_rx_data; 764 if (pm_num_rx_data == 0) { 765 rval = 0; 766 break; /* no return data */ 767 } 768 769 /* receive PM command */ 770 pm_data = pmdata->command; 771 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */ 772 pm_num_rx_data--; 773 if (pm_num_rx_data == 0) 774 if ((rval = pm_receive_pm2(&pm_data)) != 0) { 775 rval = 0xffffcd37; 776 break; 777 } 778 pmdata->command = pm_data; 779 } else { /* PB 1XX series ? */ 780 if ((rval = pm_receive_pm2(&pm_data)) != 0) { 781 rval = 0xffffcd37; 782 break; 783 } 784 pmdata->command = pm_data; 785 } 786 787 /* receive number of PM data */ 788 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */ 789 if (pm_num_rx_data < 0) { 790 if ((rval = pm_receive_pm2(&pm_data)) != 0) 791 break; /* timeout */ 792 num_pm_data = pm_data; 793 } else 794 num_pm_data = pm_num_rx_data; 795 pmdata->num_data = num_pm_data; 796 } else { /* PB 1XX serias ? */ 797 if ((rval = pm_receive_pm2(&pm_data)) != 0) 798 break; /* timeout */ 799 num_pm_data = pm_data; 800 pmdata->num_data = num_pm_data; 801 } 802 803 /* receive PM data */ 804 pm_buf = (u_char *)pmdata->r_buf; 805 for (i = 0; i < num_pm_data; i++) { 806 if ((rval = pm_receive_pm2(&pm_data)) != 0) 807 break; /* timeout */ 808 pm_buf[i] = pm_data; 809 } 810 811 rval = 0; 812 } 813 814 /* restore former value */ 815 write_via_reg(VIA1, vIER, via1_vIER); 816 splx(s); 817 818 return rval; 819} 820 821 822/* 823 * My PM interrupt routine for the PB Duo series and the PB 5XX series 824 */ 825void 826pm_intr_pm2() 827{ 828 int s; 829 int rval; 830 PMData pmdata; 831 832 s = splhigh(); 833 834 for (;;) { 835 u_int ifr; 836 ifr = read_via_reg(VIA1, vIFR); 837 838 if (ifr == 0) 839 break; 840 841 if (ifr & V1IF_ADBRDY) { 842 write_via_reg(VIA1, vIFR, V1IF_ADBRDY); 843 ifr &= ~V1IF_ADBRDY; 844 delay(120000); /* XXX */ 845 } else if (ifr & V1IF_ADBCLK) { 846 write_via_reg(VIA1, vIFR, V1IF_ADBCLK); 847 ifr &= ~V1IF_ADBCLK; 848 } 849 850 if (ifr) 851 write_via_reg(VIA1, vIFR, ifr); 852 } 853 854#if 0 855 gpio = in8(gpio_reg + 0x9); 856 if ((gpio & 0x02) != 0) { 857 splx(s); 858 return; 859 } 860#endif 861 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */ 862 /* ask PM what happend */ 863 pmdata.command = 0x78; 864 pmdata.num_data = 0; 865 pmdata.s_buf = &pmdata.data[2]; 866 pmdata.r_buf = &pmdata.data[2]; 867 rval = pm_pmgrop_pm2(&pmdata); 868 if (rval != 0) { 869#ifdef ADB_DEBUG 870 if (adb_debug) 871 printf("pm: PM is not ready. error code: %08x\n", rval); 872#endif 873 splx(s); 874 } 875 876 switch ((u_int)(pmdata.data[2] & 0xff)) { 877 case 0x00: /* 1 sec interrupt? */ 878 break; 879 case 0x80: /* 1 sec interrupt? */ 880 pm_counter++; 881 break; 882 case 0x08: /* Brightness/Contrast button on LCD panel */ 883 /* get brightness and contrast of the LCD */ 884 pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff; 885 pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff; 886/* 887 pm_printerr("#08", rval, pmdata.num_data, pmdata.data); 888 pmdata.command = 0x33; 889 pmdata.num_data = 1; 890 pmdata.s_buf = pmdata.data; 891 pmdata.r_buf = pmdata.data; 892 pmdata.data[0] = pm_LCD_contrast; 893 rval = pm_pmgrop_pm2(&pmdata); 894 pm_printerr("#33", rval, pmdata.num_data, pmdata.data); 895*/ 896 /* this is an experimental code */ 897 pmdata.command = 0x41; 898 pmdata.num_data = 1; 899 pmdata.s_buf = pmdata.data; 900 pmdata.r_buf = pmdata.data; 901 pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2; 902 if (pm_LCD_brightness < 0x08) 903 pm_LCD_brightness = 0x08; 904 if (pm_LCD_brightness > 0x78) 905 pm_LCD_brightness = 0x78; 906 pmdata.data[0] = pm_LCD_brightness; 907 rval = pm_pmgrop_pm2(&pmdata); 908 break; 909 case 0x10: /* ADB data that were requested by TALK command */ 910 case 0x14: 911 pm_adb_get_TALK_result(&pmdata); 912 break; 913 case 0x16: /* ADB device event */ 914 case 0x18: 915 case 0x1e: 916 pm_adb_get_ADB_data(&pmdata); 917 break; 918 default: 919#ifdef ADB_DEBUG 920 if (adb_debug) 921 pm_printerr("driver does not supported this event.", 922 pmdata.data[2], pmdata.num_data, 923 pmdata.data); 924#endif 925 break; 926 } 927 928 splx(s); 929} 930 931 932#if 0 933/* 934 * MRG-based PMgrOp routine 935 */ 936int 937pm_pmgrop_mrg(pmdata) 938 PMData *pmdata; 939{ 940 u_int32_t rval=0; 941 942 asm(" 943 movl %1, a0 944 .word 0xa085 945 movl d0, %0" 946 : "=g" (rval) 947 : "g" (pmdata) 948 : "a0", "d0" ); 949 950 return rval; 951} 952#endif 953 954 955/* 956 * My PMgrOp routine 957 */ 958int 959pmgrop(pmdata) 960 PMData *pmdata; 961{ 962 switch (pmHardware) { 963 case PM_HW_PB1XX: 964 return (pm_pmgrop_pm1(pmdata)); 965 break; 966 case PM_HW_PB5XX: 967 return (pm_pmgrop_pm2(pmdata)); 968 break; 969 default: 970 /* return (pmgrop_mrg(pmdata)); */ 971 return 1; 972 } 973} 974 975 976/* 977 * My PM interrupt routine 978 */ 979void 980pm_intr() 981{ 982 switch (pmHardware) { 983 case PM_HW_PB1XX: 984 pm_intr_pm1(); 985 break; 986 case PM_HW_PB5XX: 987 pm_intr_pm2(); 988 break; 989 default: 990 break; 991 } 992} 993 994 995 996/* 997 * Synchronous ADBOp routine for the Power Manager 998 */ 999int 1000pm_adb_op(buffer, compRout, data, command) 1001 u_char *buffer; 1002 void *compRout; 1003 void *data; 1004 int command; 1005{ 1006 int i; 1007 int s; 1008 int rval; 1009 int delay; 1010 PMData pmdata; 1011 struct adbCommand packet; 1012 1013 if (adbWaiting == 1) 1014 return 1; 1015 1016 s = splhigh(); 1017 write_via_reg(VIA1, vIER, 0x10); 1018 1019 adbBuffer = buffer; 1020 adbCompRout = compRout; 1021 adbCompData = data; 1022 1023 pmdata.command = 0x20; 1024 pmdata.s_buf = pmdata.data; 1025 pmdata.r_buf = pmdata.data; 1026 1027 /* if the command is LISTEN, add number of ADB data to number of PM data */ 1028 if ((command & 0xc) == 0x8) { 1029 if (buffer != (u_char *)0) 1030 pmdata.num_data = buffer[0] + 3; 1031 } else { 1032 pmdata.num_data = 3; 1033 } 1034 1035 pmdata.data[0] = (u_char)(command & 0xff); 1036 pmdata.data[1] = 0; 1037 if ((command & 0xc) == 0x8) { /* if the command is LISTEN, copy ADB data to PM buffer */ 1038 if ((buffer != (u_char *)0) && (buffer[0] <= 24)) { 1039 pmdata.data[2] = buffer[0]; /* number of data */ 1040 for (i = 0; i < buffer[0]; i++) 1041 pmdata.data[3 + i] = buffer[1 + i]; 1042 } else 1043 pmdata.data[2] = 0; 1044 } else 1045 pmdata.data[2] = 0; 1046 1047 if ((command & 0xc) != 0xc) { /* if the command is not TALK */ 1048 /* set up stuff for adb_pass_up */ 1049 packet.data[0] = 1 + pmdata.data[2]; 1050 packet.data[1] = command; 1051 for (i = 0; i < pmdata.data[2]; i++) 1052 packet.data[i+2] = pmdata.data[i+3]; 1053 packet.saveBuf = adbBuffer; 1054 packet.compRout = adbCompRout; 1055 packet.compData = adbCompData; 1056 packet.cmd = command; 1057 packet.unsol = 0; 1058 packet.ack_only = 1; 1059 adb_polling = 1; 1060 adb_pass_up(&packet); 1061 adb_polling = 0; 1062 } 1063 1064 rval = pmgrop(&pmdata); 1065 if (rval != 0) { 1066 splx(s); 1067 return 1; 1068 } 1069 1070 adbWaiting = 1; 1071 adbWaitingCmd = command; 1072 1073 PM_VIA_INTR_ENABLE(); 1074 1075 /* wait until the PM interrupt is occured */ 1076 delay = 0x80000; 1077 while (adbWaiting == 1) { 1078 if (read_via_reg(VIA1, vIFR) & 0x14) 1079 pm_intr(); 1080#ifdef PM_GRAB_SI 1081#if 0 1082 zshard(0); /* grab any serial interrupts */ 1083#else 1084 (void)intr_dispatch(0x70); 1085#endif 1086#endif 1087 if ((--delay) < 0) { 1088 splx(s); 1089 return 1; 1090 } 1091 } 1092 1093 /* this command enables the interrupt by operating ADB devices */ 1094 if (HwCfgFlags3 & 0x00020000) { /* PB Duo series, PB 5XX series */ 1095 pmdata.command = 0x20; 1096 pmdata.num_data = 4; 1097 pmdata.s_buf = pmdata.data; 1098 pmdata.r_buf = pmdata.data; 1099 pmdata.data[0] = 0x00; 1100 pmdata.data[1] = 0x86; /* magic spell for awaking the PM */ 1101 pmdata.data[2] = 0x00; 1102 pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */ 1103 } else { /* PB 1XX series */ 1104 pmdata.command = 0x20; 1105 pmdata.num_data = 3; 1106 pmdata.s_buf = pmdata.data; 1107 pmdata.r_buf = pmdata.data; 1108 pmdata.data[0] = (u_char)(command & 0xf0) | 0xc; 1109 pmdata.data[1] = 0x04; 1110 pmdata.data[2] = 0x00; 1111 } 1112 rval = pmgrop(&pmdata); 1113 1114 splx(s); 1115 return rval; 1116} 1117 1118 1119void 1120pm_adb_get_TALK_result(pmdata) 1121 PMData *pmdata; 1122{ 1123 int i; 1124 struct adbCommand packet; 1125 1126 /* set up data for adb_pass_up */ 1127 packet.data[0] = pmdata->num_data-1; 1128 packet.data[1] = pmdata->data[3]; 1129 for (i = 0; i <packet.data[0]-1; i++) 1130 packet.data[i+2] = pmdata->data[i+4]; 1131 1132 packet.saveBuf = adbBuffer; 1133 packet.compRout = adbCompRout; 1134 packet.compData = adbCompData; 1135 packet.unsol = 0; 1136 packet.ack_only = 0; 1137 adb_polling = 1; 1138 adb_pass_up(&packet); 1139 adb_polling = 0; 1140 1141 adbWaiting = 0; 1142 adbBuffer = (long)0; 1143 adbCompRout = (long)0; 1144 adbCompData = (long)0; 1145} 1146 1147 1148void 1149pm_adb_get_ADB_data(pmdata) 1150 PMData *pmdata; 1151{ 1152 int i; 1153 struct adbCommand packet; 1154 1155 /* set up data for adb_pass_up */ 1156 packet.data[0] = pmdata->num_data-1; /* number of raw data */ 1157 packet.data[1] = pmdata->data[3]; /* ADB command */ 1158 for (i = 0; i <packet.data[0]-1; i++) 1159 packet.data[i+2] = pmdata->data[i+4]; 1160 packet.unsol = 1; 1161 packet.ack_only = 0; 1162 adb_pass_up(&packet); 1163} 1164 1165 1166void 1167pm_adb_poll_next_device_pm1(pmdata) 1168 PMData *pmdata; 1169{ 1170 int i; 1171 int ndid; 1172 u_short bendid = 0x1; 1173 int rval; 1174 PMData tmp_pmdata; 1175 1176 /* find another existent ADB device to poll */ 1177 for (i = 1; i < 16; i++) { 1178 ndid = (ADB_CMDADDR(pmdata->data[3]) + i) & 0xf; 1179 bendid <<= ndid; 1180 if ((pm_existent_ADB_devices & bendid) != 0) 1181 break; 1182 } 1183 1184 /* poll the other device */ 1185 tmp_pmdata.command = 0x20; 1186 tmp_pmdata.num_data = 3; 1187 tmp_pmdata.s_buf = tmp_pmdata.data; 1188 tmp_pmdata.r_buf = tmp_pmdata.data; 1189 tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc; 1190 tmp_pmdata.data[1] = 0x04; /* magic spell for awaking the PM */ 1191 tmp_pmdata.data[2] = 0x00; 1192 rval = pmgrop(&tmp_pmdata); 1193} 1194 1195void 1196pm_adb_restart() 1197{ 1198 PMData p; 1199 1200 p.command = PMU_RESET_CPU; 1201 p.num_data = 0; 1202 p.s_buf = p.data; 1203 p.r_buf = p.data; 1204 pmgrop(&p); 1205} 1206 1207void 1208pm_adb_poweroff() 1209{ 1210 PMData p; 1211 1212 p.command = PMU_POWER_OFF; 1213 p.num_data = 4; 1214 p.s_buf = p.data; 1215 p.r_buf = p.data; 1216 strcpy(p.data, "MATT"); 1217 pmgrop(&p); 1218} 1219 1220void 1221pm_read_date_time(time) 1222 u_long *time; 1223{ 1224 PMData p; 1225 1226 p.command = PMU_READ_RTC; 1227 p.num_data = 0; 1228 p.s_buf = p.data; 1229 p.r_buf = p.data; 1230 pmgrop(&p); 1231 1232 bcopy(p.data, time, 4); 1233} 1234 1235void 1236pm_set_date_time(time) 1237 u_long time; 1238{ 1239 PMData p; 1240 1241 p.command = PMU_SET_RTC; 1242 p.num_data = 4; 1243 p.s_buf = p.r_buf = p.data; 1244 bcopy(&time, p.data, 4); 1245 pmgrop(&p); 1246} 1247 1248int 1249pm_read_brightness() 1250{ 1251 PMData p; 1252 1253 p.command = PMU_READ_BRIGHTNESS; 1254 p.num_data = 1; /* XXX why 1? */ 1255 p.s_buf = p.r_buf = p.data; 1256 p.data[0] = 0; 1257 pmgrop(&p); 1258 1259 return p.data[0]; 1260} 1261 1262void 1263pm_set_brightness(val) 1264 int val; 1265{ 1266 PMData p; 1267 1268 val = 0x7f - val / 2; 1269 if (val < 0x08) 1270 val = 0x08; 1271 if (val > 0x78) 1272 val = 0x78; 1273 1274 p.command = PMU_SET_BRIGHTNESS; 1275 p.num_data = 1; 1276 p.s_buf = p.r_buf = p.data; 1277 p.data[0] = val; 1278 pmgrop(&p); 1279} 1280 1281void 1282pm_init_brightness() 1283{ 1284 int val; 1285 1286 val = pm_read_brightness(); 1287 pm_set_brightness(val); 1288} 1289 1290void 1291pm_eject_pcmcia(slot) 1292 int slot; 1293{ 1294 PMData p; 1295 1296 if (slot != 0 && slot != 1) 1297 return; 1298 1299 p.command = PMU_EJECT_PCMCIA; 1300 p.num_data = 1; 1301 p.s_buf = p.r_buf = p.data; 1302 p.data[0] = 5 + slot; /* XXX */ 1303 pmgrop(&p); 1304} 1305 1306int 1307pm_read_nvram(addr) 1308 int addr; 1309{ 1310 PMData p; 1311 1312 p.command = PMU_READ_NVRAM; 1313 p.num_data = 2; 1314 p.s_buf = p.r_buf = p.data; 1315 p.data[0] = addr >> 8; 1316 p.data[1] = addr; 1317 pmgrop(&p); 1318 1319 return p.data[0]; 1320} 1321 1322void 1323pm_write_nvram(addr, val) 1324 int addr, val; 1325{ 1326 PMData p; 1327 1328 p.command = PMU_WRITE_NVRAM; 1329 p.num_data = 3; 1330 p.s_buf = p.r_buf = p.data; 1331 p.data[0] = addr >> 8; 1332 p.data[1] = addr; 1333 p.data[2] = val; 1334 pmgrop(&p); 1335} 1336