OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [h8.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * Hitachi H8/337 Microcontroller driver
3
 *
4
 * The H8 is used to deal with the power and thermal environment
5
 * of a system.
6
 *
7
 * Fixes:
8
 *      June 1999, AV   added releasing /proc/driver/h8
9
 *      Feb  2000, Borislav Deianov
10
 *                      changed queues to use list.h instead of lists.h
11
 */
12
 
13
#include <linux/config.h>
14
#include <linux/module.h>
15
 
16
#include <asm/system.h>
17
#include <asm/segment.h>
18
#include <asm/io.h>
19
 
20
#include <linux/types.h>
21
#include <linux/stddef.h>
22
#include <linux/timer.h>
23
#include <linux/fcntl.h>
24
#include <linux/linkage.h>
25
#include <linux/stat.h>
26
#include <linux/proc_fs.h>
27
#include <linux/miscdevice.h>
28
#include <linux/list.h>
29
#include <linux/ioport.h>
30
#include <linux/poll.h>
31
#include <linux/init.h>
32
#include <linux/slab.h>
33
 
34
#define __KERNEL_SYSCALLS__
35
#include <asm/unistd.h>
36
 
37
#include "h8.h"
38
 
39
#define DEBUG_H8
40
 
41
#ifdef DEBUG_H8
42
#define Dprintk         printk
43
#else
44
#define Dprintk
45
#endif
46
 
47
#define XDprintk if(h8_debug==-1)printk
48
 
49
/*
50
 * The h8 device is one of the misc char devices.
51
 */
52
#define H8_MINOR_DEV   140
53
 
54
/*
55
 * Forward declarations.
56
 */
57
static int  h8_init(void);
58
static int  h8_display_blank(void);
59
static int  h8_display_unblank(void);
60
 
61
static void  h8_intr(int irq, void *dev_id, struct pt_regs *regs);
62
 
63
static int   h8_get_info(char *, char **, off_t, int);
64
 
65
/*
66
 * Support Routines.
67
 */
68
static void h8_hw_init(void);
69
static void h8_start_new_cmd(void);
70
static void h8_send_next_cmd_byte(void);
71
static void h8_read_event_status(void);
72
static void h8_sync(void);
73
static void h8_q_cmd(u_char *, int, int);
74
static void h8_cmd_done(h8_cmd_q_t *qp);
75
static int  h8_alloc_queues(void);
76
 
77
static u_long h8_get_cpu_speed(void);
78
static int h8_get_curr_temp(u_char curr_temp[]);
79
static void h8_get_max_temp(void);
80
static void h8_get_upper_therm_thold(void);
81
static void h8_set_upper_therm_thold(int);
82
static int h8_get_ext_status(u_char stat_word[]);
83
 
84
static int h8_monitor_thread(void *);
85
 
86
static int h8_manage_therm(void);
87
static void h8_set_cpu_speed(int speed_divisor);
88
 
89
static void h8_start_monitor_timer(unsigned long secs);
90
static void h8_activate_monitor(unsigned long unused);
91
 
92
/* in arch/alpha/kernel/lca.c */
93
extern void lca_clock_print(void);
94
extern int  lca_get_clock(void);
95
extern void lca_clock_fiddle(int);
96
 
97
static void h8_set_event_mask(int);
98
static void h8_clear_event_mask(int);
99
 
100
/*
101
 * Driver structures
102
 */
103
 
104
static struct timer_list h8_monitor_timer;
105
static int h8_monitor_timer_active = 0;
106
 
107
static char  driver_version[] = "X0.0";/* no spaces */
108
 
109
static union    intr_buf intrbuf;
110
static int      intr_buf_ptr;
111
static union   intr_buf xx;
112
static u_char  last_temp;
113
 
114
/*
115
 * I/O Macros for register reads and writes.
116
 */
117
#define H8_READ(a)      inb((a))
118
#define H8_WRITE(d,a)   outb((d),(a))
119
 
120
#define H8_GET_STATUS   H8_READ((h8_base) + H8_STATUS_REG_OFF)
121
#define H8_READ_DATA    H8_READ((h8_base) + H8_DATA_REG_OFF)
122
#define WRITE_DATA(d)   H8_WRITE((d), h8_base + H8_DATA_REG_OFF)
123
#define WRITE_CMD(d)    H8_WRITE((d), h8_base + H8_CMD_REG_OFF)
124
 
125
static unsigned int h8_base = H8_BASE_ADDR;
126
static unsigned int h8_irq = H8_IRQ;
127
static unsigned int h8_state = H8_IDLE;
128
static unsigned int h8_index = -1;
129
static unsigned int h8_enabled = 0;
130
 
131
static LIST_HEAD(h8_actq);
132
static LIST_HEAD(h8_cmdq);
133
static LIST_HEAD(h8_freeq);
134
 
135
/*
136
 * Globals used in thermal control of Alphabook1.
137
 */
138
static int cpu_speed_divisor = -1;
139
static int h8_event_mask = 0;
140
static DECLARE_WAIT_QUEUE_HEAD(h8_monitor_wait);
141
static unsigned int h8_command_mask = 0;
142
static int h8_uthermal_threshold = DEFAULT_UTHERMAL_THRESHOLD;
143
static int h8_uthermal_window = UTH_HYSTERESIS;
144
static int h8_debug = 0xfffffdfc;
145
static int h8_ldamp = MHZ_115;
146
static int h8_udamp = MHZ_57;
147
static u_char h8_current_temp = 0;
148
static u_char h8_system_temp = 0;
149
static int h8_sync_channel = 0;
150
static DECLARE_WAIT_QUEUE_HEAD(h8_sync_wait);
151
static int h8_init_performed;
152
 
153
/* CPU speeds and clock divisor values */
154
static int speed_tab[6] = {230, 153, 115, 57, 28, 14};
155
 
156
/*
157
 * H8 interrupt handler
158
  */
159
static void h8_intr(int irq, void *dev_id, struct pt_regs *regs)
160
{
161
        u_char  stat_reg, data_reg;
162
        h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link);
163
 
164
        stat_reg = H8_GET_STATUS;
165
        data_reg = H8_READ_DATA;
166
 
167
        XDprintk("h8_intr: state %d status 0x%x data 0x%x\n", h8_state, stat_reg, data_reg);
168
 
169
        switch (h8_state) {
170
          /* Response to an asynchronous event. */
171
        case H8_IDLE: { /* H8_IDLE */
172
            if (stat_reg & H8_OFULL) {
173
                if (data_reg == H8_INTR) {
174
                    h8_state = H8_INTR_MODE;
175
                    /* Executing a command to determine what happened. */
176
                    WRITE_CMD(H8_RD_EVENT_STATUS);
177
                    intr_buf_ptr = 1;
178
                    WRITE_CMD(H8_RD_EVENT_STATUS);
179
                } else {
180
                    Dprintk("h8_intr: idle stat 0x%x data 0x%x\n",
181
                            stat_reg, data_reg);
182
                }
183
            } else {
184
                Dprintk("h8_intr: bogus interrupt\n");
185
            }
186
            break;
187
        }
188
        case H8_INTR_MODE: { /* H8_INTR_MODE */
189
            XDprintk("H8 intr/intr_mode\n");
190
            if (data_reg == H8_BYTE_LEVEL_ACK) {
191
                return;
192
            } else if (data_reg == H8_CMD_ACK) {
193
                return;
194
            } else {
195
                intrbuf.byte[intr_buf_ptr] = data_reg;
196
                if(!intr_buf_ptr) {
197
                    h8_state = H8_IDLE;
198
                    h8_read_event_status();
199
                }
200
                intr_buf_ptr--;
201
            }
202
            break;
203
        }
204
        /* Placed in this state by h8_start_new_cmd(). */
205
        case H8_XMIT: { /* H8_XMIT */
206
            XDprintk("H8 intr/xmit\n");
207
            /* If a byte level acknowledgement has been received */
208
            if (data_reg == H8_BYTE_LEVEL_ACK) {
209
                XDprintk("H8 intr/xmit BYTE ACK\n");
210
                qp->nacks++;
211
                if (qp->nacks > qp->ncmd)
212
                    if(h8_debug & 0x1)
213
                        Dprintk("h8intr: bogus # of acks!\n");
214
                /*
215
                 * If the number of bytes sent is less than the total
216
                 * number of bytes in the command.
217
                 */
218
                if (qp->cnt < qp->ncmd) {
219
                    h8_send_next_cmd_byte();
220
                }
221
                return;
222
                /* If the complete command has produced an acknowledgement. */
223
            } else if (data_reg == H8_CMD_ACK) {
224
                XDprintk("H8 intr/xmit CMD ACK\n");
225
                /* If there are response bytes */
226
                if (qp->nrsp)
227
                    h8_state = H8_RCV;
228
                else
229
                    h8_state = H8_IDLE;
230
                qp->cnt = 0;
231
                return;
232
                /* Error, need to start over with a clean slate. */
233
            } else if (data_reg == H8_NACK) {
234
                XDprintk("h8_intr: NACK received restarting command\n");
235
                qp->nacks = 0;
236
                qp->cnt = 0;
237
                h8_state = H8_IDLE;
238
                WRITE_CMD(H8_SYNC);
239
                return;
240
            } else {
241
                Dprintk ("h8intr: xmit unknown data 0x%x \n", data_reg);
242
                return;
243
            }
244
            break;
245
        }
246
        case H8_RESYNC: { /* H8_RESYNC */
247
            XDprintk("H8 intr/resync\n");
248
            if (data_reg == H8_BYTE_LEVEL_ACK) {
249
                return;
250
            } else if (data_reg == H8_SYNC_BYTE) {
251
                h8_state = H8_IDLE;
252
                if (!list_empty(&h8_actq))
253
                    h8_send_next_cmd_byte();
254
            } else {
255
                Dprintk ("h8_intr: resync unknown data 0x%x \n", data_reg);
256
                return;
257
            }
258
            break;
259
        }
260
        case H8_RCV: { /* H8_RCV */
261
            XDprintk("H8 intr/rcv\n");
262
            if (qp->cnt < qp->nrsp) {
263
                qp->rcvbuf[qp->cnt] = data_reg;
264
                qp->cnt++;
265
                /* If command reception finished. */
266
                if (qp->cnt == qp->nrsp) {
267
                    h8_state = H8_IDLE;
268
                    list_del(&qp->link);
269
                    h8_cmd_done (qp);
270
                    /* More commands to send over? */
271
                    if (!list_empty(&h8_cmdq))
272
                        h8_start_new_cmd();
273
                }
274
                return;
275
            } else {
276
                Dprintk ("h8intr: rcv overflow cmd 0x%x\n", qp->cmdbuf[0]);
277
            }
278
            break;
279
        }
280
        default: /* default */
281
            Dprintk("H8 intr/unknown\n");
282
            break;
283
        }
284
        return;
285
}
286
 
287
static void __exit h8_cleanup (void)
288
{
289
        remove_proc_entry("driver/h8", NULL);
290
        release_region(h8_base, 8);
291
        free_irq(h8_irq, NULL);
292
}
293
 
294
static int __init h8_init(void)
295
{
296
        if(request_irq(h8_irq, h8_intr, SA_INTERRUPT, "h8", NULL))
297
        {
298
                printk(KERN_ERR "H8: error: IRQ %d is not free\n", h8_irq);
299
                return -EIO;
300
        }
301
        printk(KERN_INFO "H8 at 0x%x IRQ %d\n", h8_base, h8_irq);
302
 
303
        create_proc_info_entry("driver/h8", 0, NULL, h8_get_info);
304
 
305
        request_region(h8_base, 8, "h8");
306
 
307
        h8_alloc_queues();
308
 
309
        h8_hw_init();
310
 
311
        kernel_thread(h8_monitor_thread, NULL, 0);
312
 
313
        return 0;
314
}
315
 
316
module_init(h8_init);
317
module_exit(h8_cleanup);
318
 
319
static void __init h8_hw_init(void)
320
{
321
        u_char  buf[H8_MAX_CMD_SIZE];
322
 
323
        /* set CPU speed to max for booting */
324
        h8_set_cpu_speed(MHZ_230);
325
 
326
        /*
327
         * Initialize the H8
328
         */
329
        h8_sync();  /* activate interrupts */
330
 
331
        /* To clear conditions left by console */
332
        h8_read_event_status();
333
 
334
        /* Perform a conditioning read */
335
        buf[0] = H8_DEVICE_CONTROL;
336
        buf[1] = 0xff;
337
        buf[2] = 0x0;
338
        h8_q_cmd(buf, 3, 1);
339
 
340
        /* Turn on built-in and external mice, capture power switch */
341
        buf[0] = H8_DEVICE_CONTROL;
342
        buf[1] = 0x0;
343
        buf[2] = H8_ENAB_INT_PTR | H8_ENAB_EXT_PTR |
344
               /*H8_DISAB_PWR_OFF_SW |*/ H8_ENAB_LOW_SPD_IND;
345
        h8_q_cmd(buf, 3, 1);
346
 
347
        h8_enabled = 1;
348
        return;
349
}
350
 
351
static int h8_get_info(char *buf, char **start, off_t fpos, int length)
352
{
353
#ifdef CONFIG_PROC_FS
354
        char *p;
355
 
356
        if (!h8_enabled)
357
                return 0;
358
        p = buf;
359
 
360
 
361
        /*
362
           0) Linux driver version (this will change if format changes)
363
           1)
364
           2)
365
           3)
366
           4)
367
        */
368
 
369
        p += sprintf(p, "%s \n",
370
                     driver_version
371
                     );
372
 
373
        return p - buf;
374
#else
375
        return 0;
376
#endif
377
}
378
 
379
/* Called from console driver -- must make sure h8_enabled. */
380
static int h8_display_blank(void)
381
{
382
#ifdef CONFIG_H8_DISPLAY_BLANK
383
        int     error;
384
 
385
        if (!h8_enabled)
386
                return 0;
387
        error = h8_set_display_power_state(H8_STATE_STANDBY);
388
        if (error == H8_SUCCESS)
389
                return 1;
390
        h8_error("set display standby", error);
391
#endif
392
        return 0;
393
}
394
 
395
/* Called from console driver -- must make sure h8_enabled. */
396
static int h8_display_unblank(void)
397
{
398
#ifdef CONFIG_H8_DISPLAY_BLANK
399
        int error;
400
 
401
        if (!h8_enabled)
402
                return 0;
403
        error = h8_set_display_power_state(H8_STATE_READY);
404
        if (error == H8_SUCCESS)
405
                return 1;
406
        h8_error("set display ready", error);
407
#endif
408
        return 0;
409
}
410
 
411
static int h8_alloc_queues(void)
412
{
413
        h8_cmd_q_t *qp;
414
        unsigned long flags;
415
        int i;
416
 
417
        qp = (h8_cmd_q_t *)kmalloc((sizeof (h8_cmd_q_t) * H8_Q_ALLOC_AMOUNT),
418
                                   GFP_KERNEL);
419
 
420
        if (!qp) {
421
                printk(KERN_ERR "H8: could not allocate memory for command queue\n");
422
                return(0);
423
        }
424
        /* add to the free queue */
425
        save_flags(flags); cli();
426
        for (i = 0; i < H8_Q_ALLOC_AMOUNT; i++) {
427
                /* place each at front of freeq */
428
                list_add(&qp[i].link, &h8_freeq);
429
        }
430
        restore_flags(flags);
431
        return (1);
432
}
433
 
434
/*
435
 * Basic means by which commands are sent to the H8.
436
 */
437
void
438
h8_q_cmd(u_char *cmd, int cmd_size, int resp_size)
439
{
440
        h8_cmd_q_t      *qp;
441
        unsigned long flags;
442
        int             i;
443
 
444
        /* get cmd buf */
445
        save_flags(flags); cli();
446
        while (list_empty(&h8_freeq)) {
447
                Dprintk("H8: need to allocate more cmd buffers\n");
448
                restore_flags(flags);
449
                h8_alloc_queues();
450
                save_flags(flags); cli();
451
        }
452
        /* get first element from queue */
453
        qp = list_entry(h8_freeq.next, h8_cmd_q_t, link);
454
        list_del(&qp->link);
455
 
456
        restore_flags(flags);
457
 
458
        /* fill it in */
459
        for (i = 0; i < cmd_size; i++)
460
            qp->cmdbuf[i] = cmd[i];
461
        qp->ncmd = cmd_size;
462
        qp->nrsp = resp_size;
463
 
464
        /* queue it at the end of the cmd queue */
465
        save_flags(flags); cli();
466
 
467
        /* XXX this actually puts it at the start of cmd queue, bug? */
468
        list_add(&qp->link, &h8_cmdq);
469
 
470
        restore_flags(flags);
471
 
472
        h8_start_new_cmd();
473
}
474
 
475
void
476
h8_start_new_cmd(void)
477
{
478
        unsigned long flags;
479
        h8_cmd_q_t *qp;
480
 
481
        save_flags(flags); cli();
482
        if (h8_state != H8_IDLE) {
483
                if (h8_debug & 0x1)
484
                        Dprintk("h8_start_new_cmd: not idle\n");
485
                restore_flags(flags);
486
                return;
487
        }
488
 
489
        if (!list_empty(&h8_actq)) {
490
                Dprintk("h8_start_new_cmd: inconsistency: IDLE with non-empty active queue!\n");
491
                restore_flags(flags);
492
                return;
493
        }
494
 
495
        if (list_empty(&h8_cmdq)) {
496
                Dprintk("h8_start_new_cmd: no command to dequeue\n");
497
                restore_flags(flags);
498
                return;
499
        }
500
        /*
501
         * Take first command off of the command queue and put
502
         * it on the active queue.
503
         */
504
        qp = list_entry(h8_cmdq.next, h8_cmd_q_t, link);
505
        list_del(&qp->link);
506
        /* XXX should this go to the end of the active queue? */
507
        list_add(&qp->link, &h8_actq);
508
        h8_state = H8_XMIT;
509
        if (h8_debug & 0x1)
510
                Dprintk("h8_start_new_cmd: Starting a command\n");
511
 
512
        qp->cnt = 1;
513
        WRITE_CMD(qp->cmdbuf[0]);               /* Kick it off */
514
 
515
        restore_flags(flags);
516
        return;
517
}
518
 
519
void
520
h8_send_next_cmd_byte(void)
521
{
522
        h8_cmd_q_t      *qp = list_entry(h8_actq.next, h8_cmd_q_t, link);
523
        int cnt;
524
 
525
        cnt = qp->cnt;
526
        qp->cnt++;
527
 
528
        if (h8_debug & 0x1)
529
                Dprintk("h8 sending next cmd byte 0x%x (0x%x)\n",
530
                        cnt, qp->cmdbuf[cnt]);
531
 
532
        if (cnt) {
533
                WRITE_DATA(qp->cmdbuf[cnt]);
534
        } else {
535
                WRITE_CMD(qp->cmdbuf[cnt]);
536
        }
537
        return;
538
}
539
 
540
/*
541
 * Synchronize H8 communications channel for command transmission.
542
 */
543
void
544
h8_sync(void)
545
{
546
        u_char  buf[H8_MAX_CMD_SIZE];
547
 
548
        buf[0] = H8_SYNC;
549
        buf[1] = H8_SYNC_BYTE;
550
        h8_q_cmd(buf, 2, 1);
551
}
552
 
553
/*
554
 * Responds to external interrupt. Reads event status word and
555
 * decodes type of interrupt.
556
 */
557
void
558
h8_read_event_status(void)
559
{
560
 
561
        if(h8_debug & 0x200)
562
                printk(KERN_DEBUG "h8_read_event_status: value 0x%x\n", intrbuf.word);
563
 
564
        /*
565
         * Power related items
566
         */
567
        if (intrbuf.word & H8_DC_CHANGE) {
568
                if(h8_debug & 0x4)
569
                    printk(KERN_DEBUG "h8_read_event_status: DC_CHANGE\n");
570
                /* see if dc added or removed, set batt/dc flag, send event */
571
 
572
                h8_set_event_mask(H8_MANAGE_BATTERY);
573
                wake_up(&h8_monitor_wait);
574
        }
575
 
576
        if (intrbuf.word & H8_POWER_BUTTON) {
577
                printk(KERN_CRIT "Power switch pressed - please wait - preparing to power
578
off\n");
579
                h8_set_event_mask(H8_POWER_BUTTON);
580
                wake_up(&h8_monitor_wait);
581
        }
582
 
583
        /*
584
         * Thermal related items
585
         */
586
        if (intrbuf.word & H8_THERMAL_THRESHOLD) {
587
                if(h8_debug & 0x4)
588
                    printk(KERN_DEBUG "h8_read_event_status: THERMAL_THRESHOLD\n");
589
                h8_set_event_mask(H8_MANAGE_UTHERM);
590
                wake_up(&h8_monitor_wait);
591
        }
592
 
593
        /*
594
         * nops -for now
595
         */
596
        if (intrbuf.word & H8_DOCKING_STATION_STATUS) {
597
                if(h8_debug & 0x4)
598
                    printk(KERN_DEBUG "h8_read_event_status: DOCKING_STATION_STATUS\n");
599
                /* read_ext_status */
600
        }
601
        if (intrbuf.word & H8_EXT_BATT_STATUS) {
602
                if(h8_debug & 0x4)
603
                    printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_STATUS\n");
604
 
605
        }
606
        if (intrbuf.word & H8_EXT_BATT_CHARGE_STATE) {
607
                if(h8_debug & 0x4)
608
                    printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_CHARGE_STATE\n");
609
 
610
        }
611
        if (intrbuf.word & H8_BATT_CHANGE_OVER) {
612
                if(h8_debug & 0x4)
613
                    printk(KERN_DEBUG "h8_read_event_status: BATT_CHANGE_OVER\n");
614
 
615
        }
616
        if (intrbuf.word & H8_WATCHDOG) {
617
                if(h8_debug & 0x4)
618
                    printk(KERN_DEBUG "h8_read_event_status: WATCHDOG\n");
619
                /* nop */
620
        }
621
        if (intrbuf.word & H8_SHUTDOWN) {
622
                if(h8_debug & 0x4)
623
                    printk(KERN_DEBUG "h8_read_event_status: SHUTDOWN\n");
624
                /* nop */
625
        }
626
        if (intrbuf.word & H8_KEYBOARD) {
627
                if(h8_debug & 0x4)
628
                    printk(KERN_DEBUG "h8_read_event_status: KEYBOARD\n");
629
                /* nop */
630
        }
631
        if (intrbuf.word & H8_EXT_MOUSE_OR_CASE_SWITCH) {
632
                if(h8_debug & 0x4)
633
                    printk(KERN_DEBUG "h8_read_event_status: EXT_MOUSE_OR_CASE_SWITCH\n");
634
                /* read_ext_status*/
635
        }
636
        if (intrbuf.word & H8_INT_BATT_LOW) {
637
                if(h8_debug & 0x4)
638
                    printk(KERN_DEBUG "h8_read_event_status: INT_BATT_LOW\n"); post
639
                /* event, warn user */
640
        }
641
        if (intrbuf.word & H8_INT_BATT_CHARGE_STATE) {
642
                if(h8_debug & 0x4)
643
                    printk(KERN_DEBUG "h8_read_event_status: INT_BATT_CHARGE_STATE\n");
644
                /* nop - happens often */
645
        }
646
        if (intrbuf.word & H8_INT_BATT_STATUS) {
647
                if(h8_debug & 0x4)
648
                    printk(KERN_DEBUG "h8_read_event_status: INT_BATT_STATUS\n");
649
 
650
        }
651
        if (intrbuf.word & H8_INT_BATT_CHARGE_THRESHOLD) {
652
                if(h8_debug & 0x4)
653
                    printk(KERN_DEBUG "h8_read_event_status: INT_BATT_CHARGE_THRESHOLD\n");
654
                /* nop - happens often */
655
        }
656
        if (intrbuf.word & H8_EXT_BATT_LOW) {
657
                if(h8_debug & 0x4)
658
                    printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_LOW\n");
659
                /*if no internal, post event, warn user */
660
                /* else nop */
661
        }
662
 
663
        return;
664
}
665
 
666
/*
667
 * Function called when H8 has performed requested command.
668
 */
669
static void
670
h8_cmd_done(h8_cmd_q_t *qp)
671
{
672
 
673
        /* what to do */
674
        switch (qp->cmdbuf[0]) {
675
        case H8_SYNC:
676
            if (h8_debug & 0x40000)
677
                printk(KERN_DEBUG "H8: Sync command done - byte returned was 0x%x\n",
678
                       qp->rcvbuf[0]);
679
            list_add(&qp->link, &h8_freeq);
680
            break;
681
 
682
        case H8_RD_SN:
683
        case H8_RD_ENET_ADDR:
684
            printk(KERN_DEBUG "H8: read Ethernet address: command done - address: %x - %x - %x - %x - %x - %x \n",
685
                   qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2],
686
                   qp->rcvbuf[3], qp->rcvbuf[4], qp->rcvbuf[5]);
687
            list_add(&qp->link, &h8_freeq);
688
            break;
689
 
690
        case H8_RD_HW_VER:
691
        case H8_RD_MIC_VER:
692
        case H8_RD_MAX_TEMP:
693
            printk(KERN_DEBUG "H8: Max recorded CPU temp %d, Sys temp %d\n",
694
                   qp->rcvbuf[0], qp->rcvbuf[1]);
695
            list_add(&qp->link, &h8_freeq);
696
            break;
697
 
698
        case H8_RD_MIN_TEMP:
699
            printk(KERN_DEBUG "H8: Min recorded CPU temp %d, Sys temp %d\n",
700
                   qp->rcvbuf[0], qp->rcvbuf[1]);
701
            list_add(&qp->link, &h8_freeq);
702
            break;
703
 
704
        case H8_RD_CURR_TEMP:
705
            h8_sync_channel |= H8_RD_CURR_TEMP;
706
            xx.byte[0] = qp->rcvbuf[0];
707
            xx.byte[1] = qp->rcvbuf[1];
708
            wake_up(&h8_sync_wait);
709
            list_add(&qp->link, &h8_freeq);
710
            break;
711
 
712
        case H8_RD_SYS_VARIENT:
713
        case H8_RD_PWR_ON_CYCLES:
714
            printk(KERN_DEBUG " H8: RD_PWR_ON_CYCLES command done\n");
715
            break;
716
 
717
        case H8_RD_PWR_ON_SECS:
718
            printk(KERN_DEBUG "H8: RD_PWR_ON_SECS command done\n");
719
            break;
720
 
721
        case H8_RD_RESET_STATUS:
722
        case H8_RD_PWR_DN_STATUS:
723
        case H8_RD_EVENT_STATUS:
724
        case H8_RD_ROM_CKSM:
725
        case H8_RD_EXT_STATUS:
726
            xx.byte[1] = qp->rcvbuf[0];
727
            xx.byte[0] = qp->rcvbuf[1];
728
            h8_sync_channel |= H8_GET_EXT_STATUS;
729
            wake_up(&h8_sync_wait);
730
            list_add(&qp->link, &h8_freeq);
731
            break;
732
 
733
        case H8_RD_USER_CFG:
734
        case H8_RD_INT_BATT_VOLT:
735
        case H8_RD_DC_INPUT_VOLT:
736
        case H8_RD_HORIZ_PTR_VOLT:
737
        case H8_RD_VERT_PTR_VOLT:
738
        case H8_RD_EEPROM_STATUS:
739
        case H8_RD_ERR_STATUS:
740
        case H8_RD_NEW_BUSY_SPEED:
741
        case H8_RD_CONFIG_INTERFACE:
742
        case H8_RD_INT_BATT_STATUS:
743
            printk(KERN_DEBUG "H8: Read int batt status cmd done - returned was %x %x %x\n",
744
                   qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2]);
745
            list_add(&qp->link, &h8_freeq);
746
            break;
747
 
748
        case H8_RD_EXT_BATT_STATUS:
749
        case H8_RD_PWR_UP_STATUS:
750
        case H8_RD_EVENT_STATUS_MASK:
751
        case H8_CTL_EMU_BITPORT:
752
        case H8_DEVICE_CONTROL:
753
            if(h8_debug & 0x20000) {
754
                printk(KERN_DEBUG "H8: Device control cmd done - byte returned was 0x%x\n",
755
                       qp->rcvbuf[0]);
756
            }
757
            list_add(&qp->link, &h8_freeq);
758
            break;
759
 
760
        case H8_CTL_TFT_BRT_DC:
761
        case H8_CTL_WATCHDOG:
762
        case H8_CTL_MIC_PROT:
763
        case H8_CTL_INT_BATT_CHG:
764
        case H8_CTL_EXT_BATT_CHG:
765
        case H8_CTL_MARK_SPACE:
766
        case H8_CTL_MOUSE_SENSITIVITY:
767
        case H8_CTL_DIAG_MODE:
768
        case H8_CTL_IDLE_AND_BUSY_SPDS:
769
            printk(KERN_DEBUG "H8: Idle and busy speed command done\n");
770
            break;
771
 
772
        case H8_CTL_TFT_BRT_BATT:
773
        case H8_CTL_UPPER_TEMP:
774
            if(h8_debug & 0x10) {
775
                XDprintk("H8: ctl upper thermal thresh cmd done - returned was %d\n",
776
                       qp->rcvbuf[0]);
777
            }
778
            list_add(&qp->link, &h8_freeq);
779
            break;
780
 
781
        case H8_CTL_LOWER_TEMP:
782
        case H8_CTL_TEMP_CUTOUT:
783
        case H8_CTL_WAKEUP:
784
        case H8_CTL_CHG_THRESHOLD:
785
        case H8_CTL_TURBO_MODE:
786
        case H8_SET_DIAG_STATUS:
787
        case H8_SOFTWARE_RESET:
788
        case H8_RECAL_PTR:
789
        case H8_SET_INT_BATT_PERCENT:
790
        case H8_WRT_CFG_INTERFACE_REG:
791
        case H8_WRT_EVENT_STATUS_MASK:
792
        case H8_ENTER_POST_MODE:
793
        case H8_EXIT_POST_MODE:
794
        case H8_RD_EEPROM:
795
        case H8_WRT_EEPROM:
796
        case H8_WRT_TO_STATUS_DISP:
797
            printk("H8: Write IO status display command done\n");
798
            break;
799
 
800
        case H8_DEFINE_SPC_CHAR:
801
        case H8_DEFINE_TABLE_STRING_ENTRY:
802
        case H8_PERFORM_EMU_CMD:
803
        case H8_EMU_RD_REG:
804
        case H8_EMU_WRT_REG:
805
        case H8_EMU_RD_RAM:
806
        case H8_EMU_WRT_RAM:
807
        case H8_BQ_RD_REG:
808
        case H8_BQ_WRT_REG:
809
        case H8_PWR_OFF:
810
            printk (KERN_DEBUG "H8: misc command completed\n");
811
            break;
812
        }
813
        return;
814
}
815
 
816
/*
817
 * Retrieve the current CPU temperature and case temperature.  Provides
818
 * the feedback for the thermal control algorithm.  Synchcronized via
819
 * sleep() for priority so that no other actions in the process will take
820
 * place before the data becomes available.
821
 */
822
int
823
h8_get_curr_temp(u_char curr_temp[])
824
{
825
        u_char  buf[H8_MAX_CMD_SIZE];
826
        unsigned long flags;
827
 
828
        memset(buf, 0, H8_MAX_CMD_SIZE);
829
        buf[0] = H8_RD_CURR_TEMP;
830
 
831
        h8_q_cmd(buf, 1, 2);
832
 
833
        save_flags(flags); cli();
834
 
835
        while((h8_sync_channel & H8_RD_CURR_TEMP) == 0)
836
                sleep_on(&h8_sync_wait);
837
 
838
        restore_flags(flags);
839
 
840
        h8_sync_channel &= ~H8_RD_CURR_TEMP;
841
        curr_temp[0] = xx.byte[0];
842
        curr_temp[1] = xx.byte[1];
843
        xx.word = 0;
844
 
845
        if(h8_debug & 0x8)
846
                printk("H8: curr CPU temp %d, Sys temp %d\n",
847
                       curr_temp[0], curr_temp[1]);
848
        return 0;
849
}
850
 
851
static void
852
h8_get_max_temp(void)
853
{
854
        u_char  buf[H8_MAX_CMD_SIZE];
855
 
856
        buf[0] = H8_RD_MAX_TEMP;
857
        h8_q_cmd(buf, 1, 2);
858
}
859
 
860
/*
861
 * Assigns an upper limit to the value of the H8 thermal interrupt.
862
 * As an example setting a value of 115 F here will cause the
863
 * interrupt to trigger when the CPU temperature reaches 115 F.
864
 */
865
static void
866
h8_set_upper_therm_thold(int thold)
867
{
868
        u_char  buf[H8_MAX_CMD_SIZE];
869
 
870
        /* write 0 to reinitialize interrupt */
871
        buf[0] = H8_CTL_UPPER_TEMP;
872
        buf[1] = 0x0;
873
        buf[2] = 0x0;
874
        h8_q_cmd(buf, 3, 1);
875
 
876
        /* Do it for real */
877
        buf[0] = H8_CTL_UPPER_TEMP;
878
        buf[1] = 0x0;
879
        buf[2] = thold;
880
        h8_q_cmd(buf, 3, 1);
881
}
882
 
883
static void
884
h8_get_upper_therm_thold(void)
885
{
886
        u_char  buf[H8_MAX_CMD_SIZE];
887
 
888
        buf[0] = H8_CTL_UPPER_TEMP;
889
        buf[1] = 0xff;
890
        buf[2] = 0;
891
        h8_q_cmd(buf, 3, 1);
892
}
893
 
894
/*
895
 * The external status word contains information on keyboard controller,
896
 * power button, changes in external batt status, change in DC state,
897
 * docking station, etc. General purpose querying use.
898
 */
899
int
900
h8_get_ext_status(u_char stat_word[])
901
{
902
        u_char  buf[H8_MAX_CMD_SIZE];
903
        unsigned long flags;
904
 
905
        memset(buf, 0, H8_MAX_CMD_SIZE);
906
        buf[0] = H8_RD_EXT_STATUS;
907
 
908
        h8_q_cmd(buf, 1, 2);
909
 
910
        save_flags(flags); cli();
911
 
912
        while((h8_sync_channel & H8_GET_EXT_STATUS) == 0)
913
                sleep_on(&h8_sync_wait);
914
 
915
        restore_flags(flags);
916
 
917
        h8_sync_channel &= ~H8_GET_EXT_STATUS;
918
        stat_word[0] = xx.byte[0];
919
        stat_word[1] = xx.byte[1];
920
        xx.word = 0;
921
 
922
        if(h8_debug & 0x8)
923
                printk("H8: curr ext status %x,  %x\n",
924
                       stat_word[0], stat_word[1]);
925
 
926
        return 0;
927
}
928
 
929
/*
930
 * Thread attached to task 0 manages thermal/physcial state of Alphabook.
931
 * When a condition is detected by the interrupt service routine, the
932
 * isr does a wakeup() on h8_monitor_wait.  The mask value is then
933
 * screened for the appropriate action.
934
 */
935
 
936
int
937
h8_monitor_thread(void * unused)
938
{
939
        u_char curr_temp[2];
940
 
941
        /*
942
         * Need a logic based safety valve here. During boot when this thread is
943
         * started and the thermal interrupt is not yet initialized this logic
944
         * checks the temperature and acts accordingly.  When this path is acted
945
         * upon system boot is painfully slow, however, the priority associated
946
         * with overheating is high enough to warrant this action.
947
         */
948
        h8_get_curr_temp(curr_temp);
949
 
950
        printk(KERN_INFO "H8: Initial CPU temp: %d\n", curr_temp[0]);
951
 
952
        if(curr_temp[0] >= h8_uthermal_threshold) {
953
                h8_set_event_mask(H8_MANAGE_UTHERM);
954
                h8_manage_therm();
955
        } else {
956
                /*
957
                 * Arm the upper thermal limit of the H8 so that any temp in
958
                 * excess will trigger the thermal control mechanism.
959
                 */
960
                h8_set_upper_therm_thold(h8_uthermal_threshold);
961
        }
962
 
963
        for(;;) {
964
                sleep_on(&h8_monitor_wait);
965
 
966
                if(h8_debug & 0x2)
967
                        printk(KERN_DEBUG "h8_monitor_thread awakened, mask:%x\n",
968
                                h8_event_mask);
969
 
970
                if (h8_event_mask & (H8_MANAGE_UTHERM|H8_MANAGE_LTHERM)) {
971
                        h8_manage_therm();
972
                }
973
 
974
#if 0
975
                if (h8_event_mask & H8_POWER_BUTTON) {
976
                        h8_system_down();
977
                }
978
 
979
                /*
980
                 * If an external DC supply is removed or added make
981
                 * appropriate CPU speed adjustments.
982
                 */
983
                if (h8_event_mask & H8_MANAGE_BATTERY) {
984
                          h8_run_level_3_manage(H8_RUN);
985
                          h8_clear_event_mask(H8_MANAGE_BATTERY);
986
                }
987
#endif
988
        }
989
}
990
 
991
/*
992
 * Function implements the following policy. When the machine is booted
993
 * the system is set to run at full clock speed. When the upper thermal
994
 * threshold is reached as a result of full clock a damping factor is
995
 * applied to cool off the cpu.  The default value is one quarter clock
996
 * (57 Mhz).  When as a result of this cooling a temperature lower by
997
 * hmc_uthermal_window is reached, the machine is reset to a higher
998
 * speed, one half clock (115 Mhz).  One half clock is maintained until
999
 * the upper thermal threshold is again reached restarting the cycle.
1000
 */
1001
 
1002
int
1003
h8_manage_therm(void)
1004
{
1005
        u_char curr_temp[2];
1006
 
1007
        if(h8_event_mask & H8_MANAGE_UTHERM) {
1008
                /* Upper thermal interrupt received, need to cool down. */
1009
                if(h8_debug & 0x10)
1010
                        printk(KERN_WARNING "H8: Thermal threshold %d F reached\n",
1011
                               h8_uthermal_threshold);
1012
                h8_set_cpu_speed(h8_udamp);
1013
                h8_clear_event_mask(H8_MANAGE_UTHERM);
1014
                h8_set_event_mask(H8_MANAGE_LTHERM);
1015
                /* Check again in 30 seconds for CPU temperature */
1016
                h8_start_monitor_timer(H8_TIMEOUT_INTERVAL);
1017
        } else if (h8_event_mask & H8_MANAGE_LTHERM) {
1018
                /* See how cool the system has become as a result
1019
                   of the reduction in speed. */
1020
                h8_get_curr_temp(curr_temp);
1021
                last_temp = curr_temp[0];
1022
                if (curr_temp[0] < (h8_uthermal_threshold - h8_uthermal_window))
1023
                {
1024
                        /* System cooling has progressed to a point
1025
                           that the CPU may be sped up. */
1026
                        h8_set_upper_therm_thold(h8_uthermal_threshold);
1027
                        h8_set_cpu_speed(h8_ldamp); /* adjustable */
1028
                        if(h8_debug & 0x10)
1029
                            printk(KERN_WARNING "H8: CPU cool, applying cpu_divisor: %d \n",
1030
                                   h8_ldamp);
1031
                        h8_clear_event_mask(H8_MANAGE_LTHERM);
1032
                }
1033
                else /* Not cool enough yet, check again in 30 seconds. */
1034
                        h8_start_monitor_timer(H8_TIMEOUT_INTERVAL);
1035
        } else {
1036
 
1037
        }
1038
        return 0;
1039
}
1040
 
1041
/*
1042
 * Function conditions the value of global_rpb_counter before
1043
 * calling the primitive which causes the actual speed change.
1044
 */
1045
void
1046
h8_set_cpu_speed(int speed_divisor)
1047
{
1048
 
1049
#ifdef NOT_YET
1050
/*
1051
 * global_rpb_counter is consumed by alpha_delay() in determining just
1052
 * how much time to delay.  It is necessary that the number of microseconds
1053
 * in DELAY(n) be kept consistent over a variety of CPU clock speeds.
1054
 * To that end global_rpb_counter is here adjusted.
1055
 */
1056
 
1057
        switch (speed_divisor) {
1058
                case 0:
1059
                        global_rpb_counter = rpb->rpb_counter * 2L;
1060
                        break;
1061
                case 1:
1062
                        global_rpb_counter = rpb->rpb_counter * 4L / 3L ;
1063
                        break;
1064
                case 3:
1065
                        global_rpb_counter = rpb->rpb_counter / 2L;
1066
                        break;
1067
                case 4:
1068
                        global_rpb_counter = rpb->rpb_counter / 4L;
1069
                        break;
1070
                case 5:
1071
                        global_rpb_counter = rpb->rpb_counter / 8L;
1072
                        break;
1073
                /*
1074
                 * This case most commonly needed for cpu_speed_divisor
1075
                 * of 2 which is the value assigned by the firmware.
1076
                 */
1077
                default:
1078
                        global_rpb_counter = rpb->rpb_counter;
1079
                break;
1080
        }
1081
#endif /* NOT_YET */
1082
 
1083
        if(h8_debug & 0x8)
1084
                printk(KERN_DEBUG "H8: Setting CPU speed to %d MHz\n",
1085
                       speed_tab[speed_divisor]);
1086
 
1087
         /* Make the actual speed change */
1088
        lca_clock_fiddle(speed_divisor);
1089
}
1090
 
1091
/*
1092
 * Gets value stored in rpb representing CPU clock speed and adjusts this
1093
 * value based on the current clock speed divisor.
1094
 */
1095
u_long
1096
h8_get_cpu_speed(void)
1097
{
1098
        u_long speed = 0;
1099
        u_long counter;
1100
 
1101
#ifdef NOT_YET
1102
        counter = rpb->rpb_counter / 1000000L;
1103
 
1104
        switch (alphabook_get_clock()) {
1105
                case 0:
1106
                        speed = counter * 2L;
1107
                        break;
1108
                case 1:
1109
                        speed = counter * 4L / 3L ;
1110
                        break;
1111
                case 2:
1112
                        speed = counter;
1113
                        break;
1114
                case 3:
1115
                        speed = counter / 2L;
1116
                        break;
1117
                case 4:
1118
                        speed = counter / 4L;
1119
                        break;
1120
                case 5:
1121
                        speed = counter / 8L;
1122
                        break;
1123
                default:
1124
                break;
1125
        }
1126
        if(h8_debug & 0x8)
1127
                printk(KERN_DEBUG "H8: CPU speed current setting: %d MHz\n", speed);
1128
#endif  /* NOT_YET */
1129
        return speed;
1130
}
1131
 
1132
static void
1133
h8_activate_monitor(unsigned long unused)
1134
{
1135
        unsigned long flags;
1136
 
1137
        save_flags(flags); cli();
1138
        h8_monitor_timer_active = 0;
1139
        restore_flags(flags);
1140
 
1141
        wake_up(&h8_monitor_wait);
1142
}
1143
 
1144
static void
1145
h8_start_monitor_timer(unsigned long secs)
1146
{
1147
        unsigned long flags;
1148
 
1149
        if (h8_monitor_timer_active)
1150
            return;
1151
 
1152
        save_flags(flags); cli();
1153
        h8_monitor_timer_active = 1;
1154
        restore_flags(flags);
1155
 
1156
        init_timer(&h8_monitor_timer);
1157
        h8_monitor_timer.function = h8_activate_monitor;
1158
        h8_monitor_timer.expires = secs * HZ + jiffies;
1159
        add_timer(&h8_monitor_timer);
1160
}
1161
 
1162
static void h8_set_event_mask(int mask)
1163
{
1164
        unsigned long flags;
1165
 
1166
        save_flags(flags); cli();
1167
        h8_event_mask |= mask;
1168
        restore_flags(flags);
1169
}
1170
 
1171
static void h8_clear_event_mask(int mask)
1172
{
1173
        unsigned long flags;
1174
 
1175
        save_flags(flags); cli();
1176
        h8_event_mask &= (~mask);
1177
        restore_flags(flags);
1178
}
1179
 
1180
MODULE_LICENSE("GPL");
1181
EXPORT_NO_SYMBOLS;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.