tadpole.c 2.8 KB

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