2 * Hitachi H8/337 Microcontroller driver
4 * The H8 is used to deal with the power and thermal environment
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
13 #include <linux/config.h>
14 #include <linux/module.h>
16 #include <asm/system.h>
19 #include <linux/types.h>
20 #include <linux/stddef.h>
21 #include <linux/timer.h>
22 #include <linux/fcntl.h>
23 #include <linux/linkage.h>
24 #include <linux/stat.h>
25 #include <linux/proc_fs.h>
26 #include <linux/miscdevice.h>
27 #include <linux/list.h>
28 #include <linux/ioport.h>
29 #include <linux/poll.h>
30 #include <linux/init.h>
31 #include <linux/slab.h>
38 #define Dprintk printk
43 #define XDprintk if(h8_debug==-1)printk
46 * The h8 device is one of the misc char devices.
48 #define H8_MINOR_DEV 140
51 * Forward declarations.
53 static int h8_init(void);
54 static int h8_display_blank(void);
55 static int h8_display_unblank(void);
57 static void h8_intr(int irq, void *dev_id, struct pt_regs *regs);
59 static int h8_get_info(char *, char **, off_t, int);
64 static void h8_hw_init(void);
65 static void h8_start_new_cmd(void);
66 static void h8_send_next_cmd_byte(void);
67 static void h8_read_event_status(void);
68 static void h8_sync(void);
69 static void h8_q_cmd(u_char *, int, int);
70 static void h8_cmd_done(h8_cmd_q_t *qp);
71 static int h8_alloc_queues(void);
73 static u_long h8_get_cpu_speed(void);
74 static int h8_get_curr_temp(u_char curr_temp[]);
75 static void h8_get_max_temp(void);
76 static void h8_get_upper_therm_thold(void);
77 static void h8_set_upper_therm_thold(int);
78 static int h8_get_ext_status(u_char stat_word[]);
80 static int h8_monitor_thread(void *);
82 static int h8_manage_therm(void);
83 static void h8_set_cpu_speed(int speed_divisor);
85 static void h8_start_monitor_timer(unsigned long secs);
86 static void h8_activate_monitor(unsigned long unused);
88 /* in arch/alpha/kernel/lca.c */
89 extern void lca_clock_print(void);
90 extern int lca_get_clock(void);
91 extern void lca_clock_fiddle(int);
93 static void h8_set_event_mask(int);
94 static void h8_clear_event_mask(int);
100 static struct timer_list h8_monitor_timer;
101 static int h8_monitor_timer_active = 0;
103 static char driver_version[] = "X0.0";/* no spaces */
105 static union intr_buf intrbuf;
106 static int intr_buf_ptr;
107 static union intr_buf xx;
108 static u_char last_temp;
111 * I/O Macros for register reads and writes.
113 #define H8_READ(a) inb((a))
114 #define H8_WRITE(d,a) outb((d),(a))
116 #define H8_GET_STATUS H8_READ((h8_base) + H8_STATUS_REG_OFF)
117 #define H8_READ_DATA H8_READ((h8_base) + H8_DATA_REG_OFF)
118 #define WRITE_DATA(d) H8_WRITE((d), h8_base + H8_DATA_REG_OFF)
119 #define WRITE_CMD(d) H8_WRITE((d), h8_base + H8_CMD_REG_OFF)
121 static unsigned int h8_base = H8_BASE_ADDR;
122 static unsigned int h8_irq = H8_IRQ;
123 static unsigned int h8_state = H8_IDLE;
124 static unsigned int h8_index = -1;
125 static unsigned int h8_enabled = 0;
127 static LIST_HEAD(h8_actq);
128 static LIST_HEAD(h8_cmdq);
129 static LIST_HEAD(h8_freeq);
132 * Globals used in thermal control of Alphabook1.
134 static int cpu_speed_divisor = -1;
135 static int h8_event_mask = 0;
136 static DECLARE_WAIT_QUEUE_HEAD(h8_monitor_wait);
137 static unsigned int h8_command_mask = 0;
138 static int h8_uthermal_threshold = DEFAULT_UTHERMAL_THRESHOLD;
139 static int h8_uthermal_window = UTH_HYSTERESIS;
140 static int h8_debug = 0xfffffdfc;
141 static int h8_ldamp = MHZ_115;
142 static int h8_udamp = MHZ_57;
143 static u_char h8_current_temp = 0;
144 static u_char h8_system_temp = 0;
145 static int h8_sync_channel = 0;
146 static DECLARE_WAIT_QUEUE_HEAD(h8_sync_wait);
147 static int h8_init_performed;
149 /* CPU speeds and clock divisor values */
150 static int speed_tab[6] = {230, 153, 115, 57, 28, 14};
153 * H8 interrupt handler
155 static void h8_intr(int irq, void *dev_id, struct pt_regs *regs)
157 u_char stat_reg, data_reg;
158 h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link);
160 stat_reg = H8_GET_STATUS;
161 data_reg = H8_READ_DATA;
163 XDprintk("h8_intr: state %d status 0x%x data 0x%x\n", h8_state, stat_reg, data_reg);
166 /* Response to an asynchronous event. */
167 case H8_IDLE: { /* H8_IDLE */
168 if (stat_reg & H8_OFULL) {
169 if (data_reg == H8_INTR) {
170 h8_state = H8_INTR_MODE;
171 /* Executing a command to determine what happened. */
172 WRITE_CMD(H8_RD_EVENT_STATUS);
174 WRITE_CMD(H8_RD_EVENT_STATUS);
176 Dprintk("h8_intr: idle stat 0x%x data 0x%x\n",
180 Dprintk("h8_intr: bogus interrupt\n");
184 case H8_INTR_MODE: { /* H8_INTR_MODE */
185 XDprintk("H8 intr/intr_mode\n");
186 if (data_reg == H8_BYTE_LEVEL_ACK) {
188 } else if (data_reg == H8_CMD_ACK) {
191 intrbuf.byte[intr_buf_ptr] = data_reg;
194 h8_read_event_status();
200 /* Placed in this state by h8_start_new_cmd(). */
201 case H8_XMIT: { /* H8_XMIT */
202 XDprintk("H8 intr/xmit\n");
203 /* If a byte level acknowledgement has been received */
204 if (data_reg == H8_BYTE_LEVEL_ACK) {
205 XDprintk("H8 intr/xmit BYTE ACK\n");
207 if (qp->nacks > qp->ncmd)
209 Dprintk("h8intr: bogus # of acks!\n");
211 * If the number of bytes sent is less than the total
212 * number of bytes in the command.
214 if (qp->cnt < qp->ncmd) {
215 h8_send_next_cmd_byte();
218 /* If the complete command has produced an acknowledgement. */
219 } else if (data_reg == H8_CMD_ACK) {
220 XDprintk("H8 intr/xmit CMD ACK\n");
221 /* If there are response bytes */
228 /* Error, need to start over with a clean slate. */
229 } else if (data_reg == H8_NACK) {
230 XDprintk("h8_intr: NACK received restarting command\n");
237 Dprintk ("h8intr: xmit unknown data 0x%x \n", data_reg);
242 case H8_RESYNC: { /* H8_RESYNC */
243 XDprintk("H8 intr/resync\n");
244 if (data_reg == H8_BYTE_LEVEL_ACK) {
246 } else if (data_reg == H8_SYNC_BYTE) {
248 if (!list_empty(&h8_actq))
249 h8_send_next_cmd_byte();
251 Dprintk ("h8_intr: resync unknown data 0x%x \n", data_reg);
256 case H8_RCV: { /* H8_RCV */
257 XDprintk("H8 intr/rcv\n");
258 if (qp->cnt < qp->nrsp) {
259 qp->rcvbuf[qp->cnt] = data_reg;
261 /* If command reception finished. */
262 if (qp->cnt == qp->nrsp) {
266 /* More commands to send over? */
267 if (!list_empty(&h8_cmdq))
272 Dprintk ("h8intr: rcv overflow cmd 0x%x\n", qp->cmdbuf[0]);
276 default: /* default */
277 Dprintk("H8 intr/unknown\n");
283 static void __exit h8_cleanup (void)
285 remove_proc_entry("driver/h8", NULL);
286 release_region(h8_base, 8);
287 free_irq(h8_irq, NULL);
290 static int __init h8_init(void)
292 if(request_irq(h8_irq, h8_intr, SA_INTERRUPT, "h8", NULL))
294 printk(KERN_ERR "H8: error: IRQ %d is not free\n", h8_irq);
297 printk(KERN_INFO "H8 at 0x%x IRQ %d\n", h8_base, h8_irq);
299 if (!request_region(h8_base, 8, "h8"))
301 free_irq(h8_irq, NULL);
305 create_proc_info_entry("driver/h8", 0, NULL, h8_get_info);
311 kernel_thread(h8_monitor_thread, NULL, 0);
316 module_init(h8_init);
317 module_exit(h8_cleanup);
319 static void __init h8_hw_init(void)
321 u_char buf[H8_MAX_CMD_SIZE];
323 /* set CPU speed to max for booting */
324 h8_set_cpu_speed(MHZ_230);
329 h8_sync(); /* activate interrupts */
331 /* To clear conditions left by console */
332 h8_read_event_status();
334 /* Perform a conditioning read */
335 buf[0] = H8_DEVICE_CONTROL;
340 /* Turn on built-in and external mice, capture power switch */
341 buf[0] = H8_DEVICE_CONTROL;
343 buf[2] = H8_ENAB_INT_PTR | H8_ENAB_EXT_PTR |
344 /*H8_DISAB_PWR_OFF_SW |*/ H8_ENAB_LOW_SPD_IND;
351 static int h8_get_info(char *buf, char **start, off_t fpos, int length)
353 #ifdef CONFIG_PROC_FS
362 0) Linux driver version (this will change if format changes)
369 p += sprintf(p, "%s \n",
379 /* Called from console driver -- must make sure h8_enabled. */
380 static int h8_display_blank(void)
382 #ifdef CONFIG_H8_DISPLAY_BLANK
387 error = h8_set_display_power_state(H8_STATE_STANDBY);
388 if (error == H8_SUCCESS)
390 h8_error("set display standby", error);
395 /* Called from console driver -- must make sure h8_enabled. */
396 static int h8_display_unblank(void)
398 #ifdef CONFIG_H8_DISPLAY_BLANK
403 error = h8_set_display_power_state(H8_STATE_READY);
404 if (error == H8_SUCCESS)
406 h8_error("set display ready", error);
411 static int h8_alloc_queues(void)
417 qp = (h8_cmd_q_t *)kmalloc((sizeof (h8_cmd_q_t) * H8_Q_ALLOC_AMOUNT),
421 printk(KERN_ERR "H8: could not allocate memory for command queue\n");
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);
430 restore_flags(flags);
435 * Basic means by which commands are sent to the H8.
438 h8_q_cmd(u_char *cmd, int cmd_size, int resp_size)
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);
450 save_flags(flags); cli();
452 /* get first element from queue */
453 qp = list_entry(h8_freeq.next, h8_cmd_q_t, link);
456 restore_flags(flags);
459 for (i = 0; i < cmd_size; i++)
460 qp->cmdbuf[i] = cmd[i];
462 qp->nrsp = resp_size;
464 /* queue it at the end of the cmd queue */
465 save_flags(flags); cli();
467 /* XXX this actually puts it at the start of cmd queue, bug? */
468 list_add(&qp->link, &h8_cmdq);
470 restore_flags(flags);
476 h8_start_new_cmd(void)
481 save_flags(flags); cli();
482 if (h8_state != H8_IDLE) {
484 Dprintk("h8_start_new_cmd: not idle\n");
485 restore_flags(flags);
489 if (!list_empty(&h8_actq)) {
490 Dprintk("h8_start_new_cmd: inconsistency: IDLE with non-empty active queue!\n");
491 restore_flags(flags);
495 if (list_empty(&h8_cmdq)) {
496 Dprintk("h8_start_new_cmd: no command to dequeue\n");
497 restore_flags(flags);
501 * Take first command off of the command queue and put
502 * it on the active queue.
504 qp = list_entry(h8_cmdq.next, h8_cmd_q_t, link);
506 /* XXX should this go to the end of the active queue? */
507 list_add(&qp->link, &h8_actq);
510 Dprintk("h8_start_new_cmd: Starting a command\n");
513 WRITE_CMD(qp->cmdbuf[0]); /* Kick it off */
515 restore_flags(flags);
520 h8_send_next_cmd_byte(void)
522 h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link);
529 Dprintk("h8 sending next cmd byte 0x%x (0x%x)\n",
530 cnt, qp->cmdbuf[cnt]);
533 WRITE_DATA(qp->cmdbuf[cnt]);
535 WRITE_CMD(qp->cmdbuf[cnt]);
541 * Synchronize H8 communications channel for command transmission.
546 u_char buf[H8_MAX_CMD_SIZE];
549 buf[1] = H8_SYNC_BYTE;
554 * Responds to external interrupt. Reads event status word and
555 * decodes type of interrupt.
558 h8_read_event_status(void)
562 printk(KERN_DEBUG "h8_read_event_status: value 0x%x\n", intrbuf.word);
565 * Power related items
567 if (intrbuf.word & H8_DC_CHANGE) {
569 printk(KERN_DEBUG "h8_read_event_status: DC_CHANGE\n");
570 /* see if dc added or removed, set batt/dc flag, send event */
572 h8_set_event_mask(H8_MANAGE_BATTERY);
573 wake_up(&h8_monitor_wait);
576 if (intrbuf.word & H8_POWER_BUTTON) {
577 printk(KERN_CRIT "Power switch pressed - please wait - preparing to power
579 h8_set_event_mask(H8_POWER_BUTTON);
580 wake_up(&h8_monitor_wait);
584 * Thermal related items
586 if (intrbuf.word & H8_THERMAL_THRESHOLD) {
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);
596 if (intrbuf.word & H8_DOCKING_STATION_STATUS) {
598 printk(KERN_DEBUG "h8_read_event_status: DOCKING_STATION_STATUS\n");
599 /* read_ext_status */
601 if (intrbuf.word & H8_EXT_BATT_STATUS) {
603 printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_STATUS\n");
606 if (intrbuf.word & H8_EXT_BATT_CHARGE_STATE) {
608 printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_CHARGE_STATE\n");
611 if (intrbuf.word & H8_BATT_CHANGE_OVER) {
613 printk(KERN_DEBUG "h8_read_event_status: BATT_CHANGE_OVER\n");
616 if (intrbuf.word & H8_WATCHDOG) {
618 printk(KERN_DEBUG "h8_read_event_status: WATCHDOG\n");
621 if (intrbuf.word & H8_SHUTDOWN) {
623 printk(KERN_DEBUG "h8_read_event_status: SHUTDOWN\n");
626 if (intrbuf.word & H8_KEYBOARD) {
628 printk(KERN_DEBUG "h8_read_event_status: KEYBOARD\n");
631 if (intrbuf.word & H8_EXT_MOUSE_OR_CASE_SWITCH) {
633 printk(KERN_DEBUG "h8_read_event_status: EXT_MOUSE_OR_CASE_SWITCH\n");
636 if (intrbuf.word & H8_INT_BATT_LOW) {
638 printk(KERN_DEBUG "h8_read_event_status: INT_BATT_LOW\n"); post
639 /* event, warn user */
641 if (intrbuf.word & H8_INT_BATT_CHARGE_STATE) {
643 printk(KERN_DEBUG "h8_read_event_status: INT_BATT_CHARGE_STATE\n");
644 /* nop - happens often */
646 if (intrbuf.word & H8_INT_BATT_STATUS) {
648 printk(KERN_DEBUG "h8_read_event_status: INT_BATT_STATUS\n");
651 if (intrbuf.word & H8_INT_BATT_CHARGE_THRESHOLD) {
653 printk(KERN_DEBUG "h8_read_event_status: INT_BATT_CHARGE_THRESHOLD\n");
654 /* nop - happens often */
656 if (intrbuf.word & H8_EXT_BATT_LOW) {
658 printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_LOW\n");
659 /*if no internal, post event, warn user */
667 * Function called when H8 has performed requested command.
670 h8_cmd_done(h8_cmd_q_t *qp)
674 switch (qp->cmdbuf[0]) {
676 if (h8_debug & 0x40000)
677 printk(KERN_DEBUG "H8: Sync command done - byte returned was 0x%x\n",
679 list_add(&qp->link, &h8_freeq);
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);
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);
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);
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);
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");
717 case H8_RD_PWR_ON_SECS:
718 printk(KERN_DEBUG "H8: RD_PWR_ON_SECS command done\n");
721 case H8_RD_RESET_STATUS:
722 case H8_RD_PWR_DN_STATUS:
723 case H8_RD_EVENT_STATUS:
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);
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);
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",
757 list_add(&qp->link, &h8_freeq);
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");
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",
778 list_add(&qp->link, &h8_freeq);
781 case H8_CTL_LOWER_TEMP:
782 case H8_CTL_TEMP_CUTOUT:
784 case H8_CTL_CHG_THRESHOLD:
785 case H8_CTL_TURBO_MODE:
786 case H8_SET_DIAG_STATUS:
787 case H8_SOFTWARE_RESET:
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:
796 case H8_WRT_TO_STATUS_DISP:
797 printk("H8: Write IO status display command done\n");
800 case H8_DEFINE_SPC_CHAR:
801 case H8_DEFINE_TABLE_STRING_ENTRY:
802 case H8_PERFORM_EMU_CMD:
810 printk (KERN_DEBUG "H8: misc command completed\n");
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.
823 h8_get_curr_temp(u_char curr_temp[])
825 u_char buf[H8_MAX_CMD_SIZE];
828 memset(buf, 0, H8_MAX_CMD_SIZE);
829 buf[0] = H8_RD_CURR_TEMP;
833 save_flags(flags); cli();
835 while((h8_sync_channel & H8_RD_CURR_TEMP) == 0)
836 sleep_on(&h8_sync_wait);
838 restore_flags(flags);
840 h8_sync_channel &= ~H8_RD_CURR_TEMP;
841 curr_temp[0] = xx.byte[0];
842 curr_temp[1] = xx.byte[1];
846 printk("H8: curr CPU temp %d, Sys temp %d\n",
847 curr_temp[0], curr_temp[1]);
852 h8_get_max_temp(void)
854 u_char buf[H8_MAX_CMD_SIZE];
856 buf[0] = H8_RD_MAX_TEMP;
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.
866 h8_set_upper_therm_thold(int thold)
868 u_char buf[H8_MAX_CMD_SIZE];
870 /* write 0 to reinitialize interrupt */
871 buf[0] = H8_CTL_UPPER_TEMP;
877 buf[0] = H8_CTL_UPPER_TEMP;
884 h8_get_upper_therm_thold(void)
886 u_char buf[H8_MAX_CMD_SIZE];
888 buf[0] = H8_CTL_UPPER_TEMP;
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.
900 h8_get_ext_status(u_char stat_word[])
902 u_char buf[H8_MAX_CMD_SIZE];
905 memset(buf, 0, H8_MAX_CMD_SIZE);
906 buf[0] = H8_RD_EXT_STATUS;
910 save_flags(flags); cli();
912 while((h8_sync_channel & H8_GET_EXT_STATUS) == 0)
913 sleep_on(&h8_sync_wait);
915 restore_flags(flags);
917 h8_sync_channel &= ~H8_GET_EXT_STATUS;
918 stat_word[0] = xx.byte[0];
919 stat_word[1] = xx.byte[1];
923 printk("H8: curr ext status %x, %x\n",
924 stat_word[0], stat_word[1]);
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.
937 h8_monitor_thread(void * unused)
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.
948 h8_get_curr_temp(curr_temp);
950 printk(KERN_INFO "H8: Initial CPU temp: %d\n", curr_temp[0]);
952 if(curr_temp[0] >= h8_uthermal_threshold) {
953 h8_set_event_mask(H8_MANAGE_UTHERM);
957 * Arm the upper thermal limit of the H8 so that any temp in
958 * excess will trigger the thermal control mechanism.
960 h8_set_upper_therm_thold(h8_uthermal_threshold);
964 sleep_on(&h8_monitor_wait);
967 printk(KERN_DEBUG "h8_monitor_thread awakened, mask:%x\n",
970 if (h8_event_mask & (H8_MANAGE_UTHERM|H8_MANAGE_LTHERM)) {
975 if (h8_event_mask & H8_POWER_BUTTON) {
980 * If an external DC supply is removed or added make
981 * appropriate CPU speed adjustments.
983 if (h8_event_mask & H8_MANAGE_BATTERY) {
984 h8_run_level_3_manage(H8_RUN);
985 h8_clear_event_mask(H8_MANAGE_BATTERY);
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.
1003 h8_manage_therm(void)
1005 u_char curr_temp[2];
1007 if(h8_event_mask & H8_MANAGE_UTHERM) {
1008 /* Upper thermal interrupt received, need to cool down. */
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))
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 */
1029 printk(KERN_WARNING "H8: CPU cool, applying cpu_divisor: %d \n",
1031 h8_clear_event_mask(H8_MANAGE_LTHERM);
1033 else /* Not cool enough yet, check again in 30 seconds. */
1034 h8_start_monitor_timer(H8_TIMEOUT_INTERVAL);
1042 * Function conditions the value of global_rpb_counter before
1043 * calling the primitive which causes the actual speed change.
1046 h8_set_cpu_speed(int speed_divisor)
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.
1057 switch (speed_divisor) {
1059 global_rpb_counter = rpb->rpb_counter * 2L;
1062 global_rpb_counter = rpb->rpb_counter * 4L / 3L ;
1065 global_rpb_counter = rpb->rpb_counter / 2L;
1068 global_rpb_counter = rpb->rpb_counter / 4L;
1071 global_rpb_counter = rpb->rpb_counter / 8L;
1074 * This case most commonly needed for cpu_speed_divisor
1075 * of 2 which is the value assigned by the firmware.
1078 global_rpb_counter = rpb->rpb_counter;
1081 #endif /* NOT_YET */
1084 printk(KERN_DEBUG "H8: Setting CPU speed to %d MHz\n",
1085 speed_tab[speed_divisor]);
1087 /* Make the actual speed change */
1088 lca_clock_fiddle(speed_divisor);
1092 * Gets value stored in rpb representing CPU clock speed and adjusts this
1093 * value based on the current clock speed divisor.
1096 h8_get_cpu_speed(void)
1102 counter = rpb->rpb_counter / 1000000L;
1104 switch (alphabook_get_clock()) {
1106 speed = counter * 2L;
1109 speed = counter * 4L / 3L ;
1115 speed = counter / 2L;
1118 speed = counter / 4L;
1121 speed = counter / 8L;
1127 printk(KERN_DEBUG "H8: CPU speed current setting: %d MHz\n", speed);
1128 #endif /* NOT_YET */
1133 h8_activate_monitor(unsigned long unused)
1135 unsigned long flags;
1137 save_flags(flags); cli();
1138 h8_monitor_timer_active = 0;
1139 restore_flags(flags);
1141 wake_up(&h8_monitor_wait);
1145 h8_start_monitor_timer(unsigned long secs)
1147 unsigned long flags;
1149 if (h8_monitor_timer_active)
1152 save_flags(flags); cli();
1153 h8_monitor_timer_active = 1;
1154 restore_flags(flags);
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);
1162 static void h8_set_event_mask(int mask)
1164 unsigned long flags;
1166 save_flags(flags); cli();
1167 h8_event_mask |= mask;
1168 restore_flags(flags);
1171 static void h8_clear_event_mask(int mask)
1173 unsigned long flags;
1175 save_flags(flags); cli();
1176 h8_event_mask &= (~mask);
1177 restore_flags(flags);
1180 MODULE_LICENSE("GPL");