[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Poweron timer on iBook G3 (PPC_RTAS?)



Benjamin Herrenschmidt wrote:
[...]
> There is no general interface. If you figure out the proper command to send
> to the PMU, then we can add the option to /proc/pmu/options

An easy way to get the information is  to 'boot' into Open Firmware.

First I want to add two hints:
Apple's Technotes 'TN2004: Debugging Open Firmware Using Telnet' and
'TN2023: Open Firmware Ethernet Debugging II: Telnet downloading' are
very usefull.
There is a short Forth tutorial on Apple's pci page:
<http://developer.apple.com/hardware/pci/>

Here is a fragment of such a session:
(It is an iBook 2.2) 

| Script started on Mon Jun  7 23:43:00 2004
| frank@debian:~$ telnet 192.168.0.3
| Trying 192.168.0.3...
| Connected to 192.168.0.3.
| Escape character is '^]'.
|  ok
| 0 > dev rtc
| 0 > pwd
| 0 > /pci@f2000000/mac-io@17/via-pmu@16000/rtc ok
| 0 > words
| More [<space>,<cr>,q,a] ?
| open        set-time        get-time     oneminute      shutdowntimer 
| write-pua   disableboottimer    enableboottimer         setboottimer 
| read-boot   disablewakeup   write-wake      write-rtc   write-time 
| read-wake   read-rtc        read-time       rtc-bfr  ok

'oneminute' will set the boot timer one minute in the future and
shutdown the Mac.

| 0 > see oneminute
| : oneminute
| 3c shutdowntimer ; ok

| 0 > see shutdowntimer
| : shutdowntimer
| read-rtc + write-pua shut-down ; ok

| 0 > see write-pua
| : write-pua
| enableboottimer ; ok

The 'read-rtc' command puts the current time on the data-stack

| 0 > read-rtc . [enter]
leads to:
| 0 > read-rtc bcea937e ok

The following line would set the boot timer one minute in the 
future:
| 0 > read-rtc 3c + enableboottimer [enter]

| 0 > see enableboottimer
| : enableboottimer
|  8e rtc-bfr c! 5 rtc-bfr char+ c! 0 rtc-bfr wa1+ c! 
|  rtc-bfr 3 + 4c!-be 
|  rtc-bfr 7 " write" _pmu-ihandle $call-method drop 
|  rtc-bfr 7 + 1 " read" 
|  _pmu-ihandle $call-method drop ; ok

[Sorry for the line breaks]

In short words:
A sequence of 7 bytes is assembled somewhere in the memory 
(The position is determined by rtc-bfr) and sent to the pmu.

These 7 bytes are: '0x8e 0x05 0x00 x3 x2 x1 x0'. 
An answer of the pmu of length of one byte is then expected.
Here 'x3 x2 x1 x0' is a 32-bit value. (Which is the time of 
which the boot timer will be set.)

To read the boot timer (commando 'read-boot') the 
sequence '0x8e 0x01 0x01' is sent to the pmu and a sequence of 
6 bytes is expected as answer.

Some more commands:
| 0 > see write-wake
| : write-time 
| 80 write-time ; ok
| 0 >
| 0 > see write-time 
| : >r rtc-bfr 4c!-be 0 0 rtc-bfr 4 r> " pmu-op" 
| _pmu-ihandle $call-method drop ; ok

Here '0x80 y3 y2 y1 y0' is sent to the pmu.
(I haven't looked for the meaning of the other two
arguments '00 00'.)

| 0 > see read-wake
| :  88 read-time ; ok
| 0 >
| 0 > see read-time 
| : read-time
| >r rtc-bfr 5 0 0 r> " pmu-op" _pmu-ihandle $call-method drop
| >rtc-bfr 4c@-be ; ok

Here '0x88' is send to the pmu. 

There is also a command 'setboottimer' in this node, but it is not 
clear to me what the command will do.

One node above '/pci@f2000000/mac-io@17/via-pmu@16000' there are more 
commands, e.g

| 0 > see shutdown
| : shutdown
| 0 0 " MATT" poweroffcmd pmu-op drop 
| begin 
|   again 
| ; ok

More interesting a lot of command bytes are defined here, e.g.
'poweroffcmd'.

****************************************
There is already a program called 'pmacpow' written by Takashi 
Oe, which can set the wakeup time for cuda-based Macs. 

The idea is to write a sequence of command bytes to '/dev/adb'.

I have tested to write sequences like:
"PMU_PACKET 0x38" ('read-rtc').
[PMU_PACKET is definend in <linux/adb.h>]
And then I read back as many bytes as possible from '/dev/adb'.

"PMU_PACKET 0x38"  'read-rtc'  succesfull
"PMU_PACKET 0x88"  'read-wake' succesfull
"PMU_PACKET 0x8e 0x01 0x01"              'read-boot'  succesfull
"PMU_PACKET 0x80 y3 y2 y1 y0"  		 'write-wake' succesfull
"PMU_PACKET 0x8e 0x05 0x00 y3 y2 y1 y0 " 'enableboottimer' no luck

In '$linux/drivers/macintosh/via-pmu.c' (I'm using 2.4.22-ben2) there
is an array 'pmu_data_len[256][2]' (line 255 ff.) which says something
about the length of the data of a command and something about the 
length of the reply of the pmu.
Hence '0x8e ...' is a variable lenght command and the second byte is
the count of the bytes _after_ the second byte.
So I suppose there is a mistake in the pmu-code or I am using
'/dev/adb' in a wrong way.

Frank
****************
To be complete here is an example:

> cat pmu_read_boot.c
/*
 * pmacpow.c - set the next power up time on VIA-CUDA.
 *
 *
 * Copyright (C) 1999 Takashi Oe.  All rights reserved.
 * Parts of the code are from clock.c and bat.c
 * by Paul Mackerras.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 *
 * cc -o pmu_read_boot pmu_read_boot.c
 */

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <getopt.h>
#include <time.h>
#include <sys/time.h>

#include <linux/adb.h>
#include <linux/pmu.h>

unsigned char reqt[4] =
	{ PMU_PACKET, 0x8e, 0x01, 0x01};

unsigned char reply[32];

static char *program_name;

void dump(unsigned char *buf, int n)
{
	int i;

	for (i = 0; i < n; ++i)
		fprintf(stderr, " %.2x", buf[i]);
	fprintf(stderr, "\n");
}

void usage(void) {
	fprintf(stderr,
		"%s TBA \n", program_name);
	exit(1);
}


int  get_rtc_time(int fd)
{
	int n;

	n = write(fd, reqt, sizeof(reqt));
	if (n != sizeof(reqt)) {
		fprintf(stderr, "%s: write returned %d\n", program_name, n);
		return -1;
	}
	if ((n = read(fd, reply, sizeof(reply))) < 0) {
		perror("read");
		return -1;
	}
       
		dump(reply, n);
		fprintf(stderr, "%s: command returned\n", program_name);
		return 0;
}

int main(int argc, char **argv)
{
	int fd, arg, hour, min;
	long cur, sec, uptime;
	char *timestr, *tmp;
	extern int optind;

	program_name = (char *)basename(argv[0]);
	if (getuid()) {
		fprintf(stderr, "Sorry, must be root to set power up time\n");
		return 1;
	}

	if ((fd = open("/dev/adb", O_RDWR)) < 0) {
		perror("open");
		return 1;
	}

        get_rtc_time(fd); 

	close(fd);
	return 0;
}



Reply to: