pcmcia.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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 <pcmcia/cs_types.h>
  13. #include <pcmcia/cs.h>
  14. #include <pcmcia/cistpl.h>
  15. #include <pcmcia/ciscode.h>
  16. #include <pcmcia/ds.h>
  17. #include <pcmcia/cisreg.h>
  18. #include "ssb_private.h"
  19. /* Define the following to 1 to enable a printk on each coreswitch. */
  20. #define SSB_VERBOSE_PCMCIACORESWITCH_DEBUG 0
  21. int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
  22. u8 coreidx)
  23. {
  24. struct pcmcia_device *pdev = bus->host_pcmcia;
  25. int err;
  26. int attempts = 0;
  27. u32 cur_core;
  28. conf_reg_t reg;
  29. u32 addr;
  30. u32 read_addr;
  31. addr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE;
  32. while (1) {
  33. reg.Action = CS_WRITE;
  34. reg.Offset = 0x2E;
  35. reg.Value = (addr & 0x0000F000) >> 12;
  36. err = pcmcia_access_configuration_register(pdev, &reg);
  37. if (err != CS_SUCCESS)
  38. goto error;
  39. reg.Offset = 0x30;
  40. reg.Value = (addr & 0x00FF0000) >> 16;
  41. err = pcmcia_access_configuration_register(pdev, &reg);
  42. if (err != CS_SUCCESS)
  43. goto error;
  44. reg.Offset = 0x32;
  45. reg.Value = (addr & 0xFF000000) >> 24;
  46. err = pcmcia_access_configuration_register(pdev, &reg);
  47. if (err != CS_SUCCESS)
  48. goto error;
  49. read_addr = 0;
  50. reg.Action = CS_READ;
  51. reg.Offset = 0x2E;
  52. err = pcmcia_access_configuration_register(pdev, &reg);
  53. if (err != CS_SUCCESS)
  54. goto error;
  55. read_addr |= (reg.Value & 0xF) << 12;
  56. reg.Offset = 0x30;
  57. err = pcmcia_access_configuration_register(pdev, &reg);
  58. if (err != CS_SUCCESS)
  59. goto error;
  60. read_addr |= reg.Value << 16;
  61. reg.Offset = 0x32;
  62. err = pcmcia_access_configuration_register(pdev, &reg);
  63. if (err != CS_SUCCESS)
  64. goto error;
  65. read_addr |= reg.Value << 24;
  66. cur_core = (read_addr - SSB_ENUM_BASE) / SSB_CORE_SIZE;
  67. if (cur_core == coreidx)
  68. break;
  69. if (attempts++ > SSB_BAR0_MAX_RETRIES)
  70. goto error;
  71. udelay(10);
  72. }
  73. return 0;
  74. error:
  75. ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
  76. return -ENODEV;
  77. }
  78. int ssb_pcmcia_switch_core(struct ssb_bus *bus,
  79. struct ssb_device *dev)
  80. {
  81. int err;
  82. unsigned long flags;
  83. #if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG
  84. ssb_printk(KERN_INFO PFX
  85. "Switching to %s core, index %d\n",
  86. ssb_core_name(dev->id.coreid),
  87. dev->core_index);
  88. #endif
  89. spin_lock_irqsave(&bus->bar_lock, flags);
  90. err = ssb_pcmcia_switch_coreidx(bus, dev->core_index);
  91. if (!err)
  92. bus->mapped_device = dev;
  93. spin_unlock_irqrestore(&bus->bar_lock, flags);
  94. return err;
  95. }
  96. int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
  97. {
  98. int attempts = 0;
  99. unsigned long flags;
  100. conf_reg_t reg;
  101. int res, err = 0;
  102. SSB_WARN_ON((seg != 0) && (seg != 1));
  103. reg.Offset = 0x34;
  104. reg.Function = 0;
  105. spin_lock_irqsave(&bus->bar_lock, flags);
  106. while (1) {
  107. reg.Action = CS_WRITE;
  108. reg.Value = seg;
  109. res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
  110. if (unlikely(res != CS_SUCCESS))
  111. goto error;
  112. reg.Value = 0xFF;
  113. reg.Action = CS_READ;
  114. res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
  115. if (unlikely(res != CS_SUCCESS))
  116. goto error;
  117. if (reg.Value == seg)
  118. break;
  119. if (unlikely(attempts++ > SSB_BAR0_MAX_RETRIES))
  120. goto error;
  121. udelay(10);
  122. }
  123. bus->mapped_pcmcia_seg = seg;
  124. out_unlock:
  125. spin_unlock_irqrestore(&bus->bar_lock, flags);
  126. return err;
  127. error:
  128. ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n");
  129. err = -ENODEV;
  130. goto out_unlock;
  131. }
  132. /* These are the main device register access functions.
  133. * do_select_core is inline to have the likely hotpath inline.
  134. * All unlikely codepaths are out-of-line. */
  135. static inline int do_select_core(struct ssb_bus *bus,
  136. struct ssb_device *dev,
  137. u16 *offset)
  138. {
  139. int err;
  140. u8 need_seg = (*offset >= 0x800) ? 1 : 0;
  141. if (unlikely(dev != bus->mapped_device)) {
  142. err = ssb_pcmcia_switch_core(bus, dev);
  143. if (unlikely(err))
  144. return err;
  145. }
  146. if (unlikely(need_seg != bus->mapped_pcmcia_seg)) {
  147. err = ssb_pcmcia_switch_segment(bus, need_seg);
  148. if (unlikely(err))
  149. return err;
  150. }
  151. if (need_seg == 1)
  152. *offset -= 0x800;
  153. return 0;
  154. }
  155. static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset)
  156. {
  157. struct ssb_bus *bus = dev->bus;
  158. u16 x;
  159. if (unlikely(do_select_core(bus, dev, &offset)))
  160. return 0xFFFF;
  161. x = readw(bus->mmio + offset);
  162. return x;
  163. }
  164. static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)
  165. {
  166. struct ssb_bus *bus = dev->bus;
  167. u32 x;
  168. if (unlikely(do_select_core(bus, dev, &offset)))
  169. return 0xFFFFFFFF;
  170. x = readl(bus->mmio + offset);
  171. return x;
  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(do_select_core(bus, 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(do_select_core(bus, dev, &offset)))
  184. return;
  185. readw(bus->mmio + offset);
  186. writew(value >> 16, bus->mmio + offset + 2);
  187. readw(bus->mmio + offset);
  188. writew(value, bus->mmio + offset);
  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. }