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