geode_32.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*
  2. * AMD Geode southbridge support code
  3. * Copyright (C) 2006, Advanced Micro Devices, Inc.
  4. * Copyright (C) 2007, Andres Salomon <dilinger@debian.org>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of version 2 of the GNU General Public License
  8. * as published by the Free Software Foundation.
  9. */
  10. #include <linux/kernel.h>
  11. #include <linux/module.h>
  12. #include <linux/ioport.h>
  13. #include <linux/io.h>
  14. #include <asm/msr.h>
  15. #include <asm/geode.h>
  16. static struct {
  17. char *name;
  18. u32 msr;
  19. int size;
  20. u32 base;
  21. } lbars[] = {
  22. { "geode-pms", MSR_LBAR_PMS, LBAR_PMS_SIZE, 0 },
  23. { "geode-acpi", MSR_LBAR_ACPI, LBAR_ACPI_SIZE, 0 },
  24. { "geode-gpio", MSR_LBAR_GPIO, LBAR_GPIO_SIZE, 0 },
  25. { "geode-mfgpt", MSR_LBAR_MFGPT, LBAR_MFGPT_SIZE, 0 }
  26. };
  27. static void __init init_lbars(void)
  28. {
  29. u32 lo, hi;
  30. int i;
  31. for (i = 0; i < ARRAY_SIZE(lbars); i++) {
  32. rdmsr(lbars[i].msr, lo, hi);
  33. if (hi & 0x01)
  34. lbars[i].base = lo & 0x0000ffff;
  35. if (lbars[i].base == 0)
  36. printk(KERN_ERR "geode: Couldn't initialize '%s'\n",
  37. lbars[i].name);
  38. }
  39. }
  40. int geode_get_dev_base(unsigned int dev)
  41. {
  42. BUG_ON(dev >= ARRAY_SIZE(lbars));
  43. return lbars[dev].base;
  44. }
  45. EXPORT_SYMBOL_GPL(geode_get_dev_base);
  46. /* === GPIO API === */
  47. void geode_gpio_set(u32 gpio, unsigned int reg)
  48. {
  49. u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
  50. if (!base)
  51. return;
  52. /* low bank register */
  53. if (gpio & 0xFFFF)
  54. outl(gpio & 0xFFFF, base + reg);
  55. /* high bank register */
  56. gpio >>= 16;
  57. if (gpio)
  58. outl(gpio, base + 0x80 + reg);
  59. }
  60. EXPORT_SYMBOL_GPL(geode_gpio_set);
  61. void geode_gpio_clear(u32 gpio, unsigned int reg)
  62. {
  63. u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
  64. if (!base)
  65. return;
  66. /* low bank register */
  67. if (gpio & 0xFFFF)
  68. outl((gpio & 0xFFFF) << 16, base + reg);
  69. /* high bank register */
  70. gpio &= (0xFFFF << 16);
  71. if (gpio)
  72. outl(gpio, base + 0x80 + reg);
  73. }
  74. EXPORT_SYMBOL_GPL(geode_gpio_clear);
  75. int geode_gpio_isset(u32 gpio, unsigned int reg)
  76. {
  77. u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
  78. u32 val;
  79. if (!base)
  80. return 0;
  81. /* low bank register */
  82. if (gpio & 0xFFFF) {
  83. val = inl(base + reg) & (gpio & 0xFFFF);
  84. if ((gpio & 0xFFFF) == val)
  85. return 1;
  86. }
  87. /* high bank register */
  88. gpio >>= 16;
  89. if (gpio) {
  90. val = inl(base + 0x80 + reg) & gpio;
  91. if (gpio == val)
  92. return 1;
  93. }
  94. return 0;
  95. }
  96. EXPORT_SYMBOL_GPL(geode_gpio_isset);
  97. void geode_gpio_set_irq(unsigned int group, unsigned int irq)
  98. {
  99. u32 lo, hi;
  100. if (group > 7 || irq > 15)
  101. return;
  102. rdmsr(MSR_PIC_ZSEL_HIGH, lo, hi);
  103. lo &= ~(0xF << (group * 4));
  104. lo |= (irq & 0xF) << (group * 4);
  105. wrmsr(MSR_PIC_ZSEL_HIGH, lo, hi);
  106. }
  107. EXPORT_SYMBOL_GPL(geode_gpio_set_irq);
  108. void geode_gpio_setup_event(unsigned int gpio, int pair, int pme)
  109. {
  110. u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
  111. u32 offset, shift, val;
  112. if (gpio >= 24)
  113. offset = GPIO_MAP_W;
  114. else if (gpio >= 16)
  115. offset = GPIO_MAP_Z;
  116. else if (gpio >= 8)
  117. offset = GPIO_MAP_Y;
  118. else
  119. offset = GPIO_MAP_X;
  120. shift = (gpio % 8) * 4;
  121. val = inl(base + offset);
  122. /* Clear whatever was there before */
  123. val &= ~(0xF << shift);
  124. /* And set the new value */
  125. val |= ((pair & 7) << shift);
  126. /* Set the PME bit if this is a PME event */
  127. if (pme)
  128. val |= (1 << (shift + 3));
  129. outl(val, base + offset);
  130. }
  131. EXPORT_SYMBOL_GPL(geode_gpio_setup_event);
  132. int geode_has_vsa2(void)
  133. {
  134. static int has_vsa2 = -1;
  135. if (has_vsa2 == -1) {
  136. u16 val;
  137. /*
  138. * The VSA has virtual registers that we can query for a
  139. * signature.
  140. */
  141. outw(VSA_VR_UNLOCK, VSA_VRC_INDEX);
  142. outw(VSA_VR_SIGNATURE, VSA_VRC_INDEX);
  143. val = inw(VSA_VRC_DATA);
  144. has_vsa2 = (val == AMD_VSA_SIG || val == GSW_VSA_SIG);
  145. }
  146. return has_vsa2;
  147. }
  148. EXPORT_SYMBOL_GPL(geode_has_vsa2);
  149. static int __init geode_southbridge_init(void)
  150. {
  151. if (!is_geode())
  152. return -ENODEV;
  153. init_lbars();
  154. (void) mfgpt_timer_setup();
  155. return 0;
  156. }
  157. postcore_initcall(geode_southbridge_init);