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