pcmcia.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /*
  2. * Sonics Silicon Backplane
  3. * PCMCIA-Hostbus related functions
  4. *
  5. * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
  6. * Copyright 2007 Michael Buesch <mb@bu3sch.de>
  7. *
  8. * Licensed under the GNU/GPL. See COPYING for details.
  9. */
  10. #include <linux/ssb/ssb.h>
  11. #include <linux/delay.h>
  12. #include <linux/io.h>
  13. #include <pcmcia/cs_types.h>
  14. #include <pcmcia/cs.h>
  15. #include <pcmcia/cistpl.h>
  16. #include <pcmcia/ciscode.h>
  17. #include <pcmcia/ds.h>
  18. #include <pcmcia/cisreg.h>
  19. #include "ssb_private.h"
  20. /* Define the following to 1 to enable a printk on each coreswitch. */
  21. #define SSB_VERBOSE_PCMCIACORESWITCH_DEBUG 0
  22. int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
  23. u8 coreidx)
  24. {
  25. struct pcmcia_device *pdev = bus->host_pcmcia;
  26. int err;
  27. int attempts = 0;
  28. u32 cur_core;
  29. conf_reg_t reg;
  30. u32 addr;
  31. u32 read_addr;
  32. addr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE;
  33. while (1) {
  34. reg.Action = CS_WRITE;
  35. reg.Offset = 0x2E;
  36. reg.Value = (addr & 0x0000F000) >> 12;
  37. err = pcmcia_access_configuration_register(pdev, &reg);
  38. if (err != CS_SUCCESS)
  39. goto error;
  40. reg.Offset = 0x30;
  41. reg.Value = (addr & 0x00FF0000) >> 16;
  42. err = pcmcia_access_configuration_register(pdev, &reg);
  43. if (err != CS_SUCCESS)
  44. goto error;
  45. reg.Offset = 0x32;
  46. reg.Value = (addr & 0xFF000000) >> 24;
  47. err = pcmcia_access_configuration_register(pdev, &reg);
  48. if (err != CS_SUCCESS)
  49. goto error;
  50. read_addr = 0;
  51. reg.Action = CS_READ;
  52. reg.Offset = 0x2E;
  53. err = pcmcia_access_configuration_register(pdev, &reg);
  54. if (err != CS_SUCCESS)
  55. goto error;
  56. read_addr |= ((u32)(reg.Value & 0x0F)) << 12;
  57. reg.Offset = 0x30;
  58. err = pcmcia_access_configuration_register(pdev, &reg);
  59. if (err != CS_SUCCESS)
  60. goto error;
  61. read_addr |= ((u32)reg.Value) << 16;
  62. reg.Offset = 0x32;
  63. err = pcmcia_access_configuration_register(pdev, &reg);
  64. if (err != CS_SUCCESS)
  65. goto error;
  66. read_addr |= ((u32)reg.Value) << 24;
  67. cur_core = (read_addr - SSB_ENUM_BASE) / SSB_CORE_SIZE;
  68. if (cur_core == coreidx)
  69. break;
  70. if (attempts++ > SSB_BAR0_MAX_RETRIES)
  71. goto error;
  72. udelay(10);
  73. }
  74. return 0;
  75. error:
  76. ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
  77. return -ENODEV;
  78. }
  79. int ssb_pcmcia_switch_core(struct ssb_bus *bus,
  80. struct ssb_device *dev)
  81. {
  82. int err;
  83. unsigned long flags;
  84. #if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG
  85. ssb_printk(KERN_INFO PFX
  86. "Switching to %s core, index %d\n",
  87. ssb_core_name(dev->id.coreid),
  88. dev->core_index);
  89. #endif
  90. spin_lock_irqsave(&bus->bar_lock, flags);
  91. err = ssb_pcmcia_switch_coreidx(bus, dev->core_index);
  92. if (!err)
  93. bus->mapped_device = dev;
  94. spin_unlock_irqrestore(&bus->bar_lock, flags);
  95. return err;
  96. }
  97. int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
  98. {
  99. int attempts = 0;
  100. unsigned long flags;
  101. conf_reg_t reg;
  102. int res, err = 0;
  103. SSB_WARN_ON((seg != 0) && (seg != 1));
  104. reg.Offset = 0x34;
  105. reg.Function = 0;
  106. spin_lock_irqsave(&bus->bar_lock, flags);
  107. while (1) {
  108. reg.Action = CS_WRITE;
  109. reg.Value = seg;
  110. res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
  111. if (unlikely(res != CS_SUCCESS))
  112. goto error;
  113. reg.Value = 0xFF;
  114. reg.Action = CS_READ;
  115. res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
  116. if (unlikely(res != CS_SUCCESS))
  117. goto error;
  118. if (reg.Value == seg)
  119. break;
  120. if (unlikely(attempts++ > SSB_BAR0_MAX_RETRIES))
  121. goto error;
  122. udelay(10);
  123. }
  124. bus->mapped_pcmcia_seg = seg;
  125. out_unlock:
  126. spin_unlock_irqrestore(&bus->bar_lock, flags);
  127. return err;
  128. error:
  129. ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n");
  130. err = -ENODEV;
  131. goto out_unlock;
  132. }
  133. static int select_core_and_segment(struct ssb_device *dev,
  134. u16 *offset)
  135. {
  136. struct ssb_bus *bus = dev->bus;
  137. int err;
  138. u8 need_segment;
  139. if (*offset >= 0x800) {
  140. *offset -= 0x800;
  141. need_segment = 1;
  142. } else
  143. need_segment = 0;
  144. if (unlikely(dev != bus->mapped_device)) {
  145. err = ssb_pcmcia_switch_core(bus, dev);
  146. if (unlikely(err))
  147. return err;
  148. }
  149. if (unlikely(need_segment != bus->mapped_pcmcia_seg)) {
  150. err = ssb_pcmcia_switch_segment(bus, need_segment);
  151. if (unlikely(err))
  152. return err;
  153. }
  154. return 0;
  155. }
  156. static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset)
  157. {
  158. struct ssb_bus *bus = dev->bus;
  159. if (unlikely(select_core_and_segment(dev, &offset)))
  160. return 0xFFFF;
  161. return readw(bus->mmio + offset);
  162. }
  163. static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)
  164. {
  165. struct ssb_bus *bus = dev->bus;
  166. u32 lo, hi;
  167. if (unlikely(select_core_and_segment(dev, &offset)))
  168. return 0xFFFFFFFF;
  169. lo = readw(bus->mmio + offset);
  170. hi = readw(bus->mmio + offset + 2);
  171. return (lo | (hi << 16));
  172. }
  173. static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value)
  174. {
  175. struct ssb_bus *bus = dev->bus;
  176. if (unlikely(select_core_and_segment(dev, &offset)))
  177. return;
  178. writew(value, bus->mmio + offset);
  179. }
  180. static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value)
  181. {
  182. struct ssb_bus *bus = dev->bus;
  183. if (unlikely(select_core_and_segment(dev, &offset)))
  184. return;
  185. writeb((value & 0xFF000000) >> 24, bus->mmio + offset + 3);
  186. writeb((value & 0x00FF0000) >> 16, bus->mmio + offset + 2);
  187. writeb((value & 0x0000FF00) >> 8, bus->mmio + offset + 1);
  188. writeb((value & 0x000000FF) >> 0, bus->mmio + offset + 0);
  189. }
  190. /* Not "static", as it's used in main.c */
  191. const struct ssb_bus_ops ssb_pcmcia_ops = {
  192. .read16 = ssb_pcmcia_read16,
  193. .read32 = ssb_pcmcia_read32,
  194. .write16 = ssb_pcmcia_write16,
  195. .write32 = ssb_pcmcia_write32,
  196. };
  197. int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
  198. struct ssb_init_invariants *iv)
  199. {
  200. //TODO
  201. return 0;
  202. }
  203. int ssb_pcmcia_init(struct ssb_bus *bus)
  204. {
  205. conf_reg_t reg;
  206. int err;
  207. if (bus->bustype != SSB_BUSTYPE_PCMCIA)
  208. return 0;
  209. /* Switch segment to a known state and sync
  210. * bus->mapped_pcmcia_seg with hardware state. */
  211. ssb_pcmcia_switch_segment(bus, 0);
  212. /* Init IRQ routing */
  213. reg.Action = CS_READ;
  214. reg.Function = 0;
  215. if (bus->chip_id == 0x4306)
  216. reg.Offset = 0x00;
  217. else
  218. reg.Offset = 0x80;
  219. err = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
  220. if (err != CS_SUCCESS)
  221. goto error;
  222. reg.Action = CS_WRITE;
  223. reg.Value |= 0x04 | 0x01;
  224. err = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
  225. if (err != CS_SUCCESS)
  226. goto error;
  227. return 0;
  228. error:
  229. return -ENODEV;
  230. }