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