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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [char/] [h8.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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