1/* tadpole.c: Probing for the tadpole clock stopping h/w at boot time. 2 * 3 * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk) 4 */ 5 6#include <linux/string.h> 7#include <linux/kernel.h> 8#include <linux/sched.h> 9#include <linux/init.h> 10 11#include <asm/asi.h> 12#include <asm/oplib.h> 13#include <asm/io.h> 14 15#define MACIO_SCSI_CSR_ADDR 0x78400000 16#define MACIO_EN_DMA 0x00000200 17#define CLOCK_INIT_DONE 1 18 19static int clk_state; 20static volatile unsigned char *clk_ctrl; 21void (*cpu_pwr_save)(void); 22 23static inline unsigned int ldphys(unsigned int addr) 24{ 25 unsigned long data; 26 27 __asm__ __volatile__("\n\tlda [%1] %2, %0\n\t" : 28 "=r" (data) : 29 "r" (addr), "i" (ASI_M_BYPASS)); 30 return data; 31} 32 33static void clk_init(void) 34{ 35 __asm__ __volatile__("mov 0x6c, %%g1\n\t" 36 "mov 0x4c, %%g2\n\t" 37 "mov 0xdf, %%g3\n\t" 38 "stb %%g1, [%0+3]\n\t" 39 "stb %%g2, [%0+3]\n\t" 40 "stb %%g3, [%0+3]\n\t" : : 41 "r" (clk_ctrl) : 42 "g1", "g2", "g3"); 43} 44 45static void clk_slow(void) 46{ 47 __asm__ __volatile__("mov 0xcc, %%g2\n\t" 48 "mov 0x4c, %%g3\n\t" 49 "mov 0xcf, %%g4\n\t" 50 "mov 0xdf, %%g5\n\t" 51 "stb %%g2, [%0+3]\n\t" 52 "stb %%g3, [%0+3]\n\t" 53 "stb %%g4, [%0+3]\n\t" 54 "stb %%g5, [%0+3]\n\t" : : 55 "r" (clk_ctrl) : 56 "g2", "g3", "g4", "g5"); 57} 58 59static void tsu_clockstop(void) 60{ 61 unsigned int mcsr; 62 unsigned long flags; 63 64 if (!clk_ctrl) 65 return; 66 if (!(clk_state & CLOCK_INIT_DONE)) { 67 save_and_cli(flags); 68 clk_init(); 69 clk_state |= CLOCK_INIT_DONE; /* all done */ 70 restore_flags(flags); 71 return; 72 } 73 if (!(clk_ctrl[2] & 1)) 74 return; /* no speed up yet */ 75 76 save_and_cli(flags); 77 78 /* if SCSI DMA in progress, don't slow clock */ 79 mcsr = ldphys(MACIO_SCSI_CSR_ADDR); 80 if ((mcsr&MACIO_EN_DMA) != 0) { 81 restore_flags(flags); 82 return; 83 } 84 /* TODO... the minimum clock setting ought to increase the 85 * memory refresh interval.. 86 */ 87 clk_slow(); 88 restore_flags(flags); 89} 90 91static void swift_clockstop(void) 92{ 93 if (!clk_ctrl) 94 return; 95 clk_ctrl[0] = 0; 96} 97 98void __init clock_stop_probe(void) 99{ 100 unsigned int node, clk_nd; 101 char name[20]; 102 103 prom_getstring(prom_root_node, "name", name, sizeof(name)); 104 if (strncmp(name, "Tadpole", 7)) 105 return; 106 node = prom_getchild(prom_root_node); 107 node = prom_searchsiblings(node, "obio"); 108 node = prom_getchild(node); 109 clk_nd = prom_searchsiblings(node, "clk-ctrl"); 110 if (!clk_nd) 111 return; 112 printk("Clock Stopping h/w detected... "); 113 clk_ctrl = (char *) prom_getint(clk_nd, "address"); 114 clk_state = 0; 115 if (name[10] == '\0') { 116 cpu_pwr_save = tsu_clockstop; 117 printk("enabled (S3)\n"); 118 } else if ((name[10] == 'X') || (name[10] == 'G')) { 119 cpu_pwr_save = swift_clockstop; 120 printk("enabled (%s)\n",name+7); 121 } else 122 printk("disabled %s\n",name+7); 123} 124