pcmcia.c 6.1 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 |= (reg.Value & 0xF) << 12;
  57. reg.Offset = 0x30;
  58. err = pcmcia_access_configuration_register(pdev, &reg);
  59. if (err != CS_SUCCESS)
  60. goto error;
  61. read_addr |= 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 |= 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. /* These are the main device register access functions.
  134. * do_select_core is inline to have the likely hotpath inline.
  135. * All unlikely codepaths are out-of-line. */
  136. static inline int do_select_core(struct ssb_bus *bus,
  137. struct ssb_device *dev,
  138. u16 *offset)
  139. {
  140. int err;
  141. u8 need_seg = (*offset >= 0x800) ? 1 : 0;
  142. if (unlikely(dev != bus->mapped_device)) {
  143. err = ssb_pcmcia_switch_core(bus, dev);
  144. if (unlikely(err))
  145. return err;
  146. }
  147. if (unlikely(need_seg != bus->mapped_pcmcia_seg)) {
  148. err = ssb_pcmcia_switch_segment(bus, need_seg);
  149. if (unlikely(err))
  150. return err;
  151. }
  152. if (need_seg == 1)
  153. *offset -= 0x800;
  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. u16 x;
  160. if (unlikely(do_select_core(bus, dev, &offset)))
  161. return 0xFFFF;
  162. x = readw(bus->mmio + offset);
  163. return x;
  164. }
  165. static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)
  166. {
  167. struct ssb_bus *bus = dev->bus;
  168. u32 x;
  169. if (unlikely(do_select_core(bus, dev, &offset)))
  170. return 0xFFFFFFFF;
  171. x = readl(bus->mmio + offset);
  172. return x;
  173. }
  174. static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value)
  175. {
  176. struct ssb_bus *bus = dev->bus;
  177. if (unlikely(do_select_core(bus, dev, &offset)))
  178. return;
  179. writew(value, bus->mmio + offset);
  180. }
  181. static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value)
  182. {
  183. struct ssb_bus *bus = dev->bus;
  184. if (unlikely(do_select_core(bus, dev, &offset)))
  185. return;
  186. readw(bus->mmio + offset);
  187. writew(value >> 16, bus->mmio + offset + 2);
  188. readw(bus->mmio + offset);
  189. writew(value, bus->mmio + offset);
  190. }
  191. /* Not "static", as it's used in main.c */
  192. const struct ssb_bus_ops ssb_pcmcia_ops = {
  193. .read16 = ssb_pcmcia_read16,
  194. .read32 = ssb_pcmcia_read32,
  195. .write16 = ssb_pcmcia_write16,
  196. .write32 = ssb_pcmcia_write32,
  197. };
  198. int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
  199. struct ssb_init_invariants *iv)
  200. {
  201. //TODO
  202. return 0;
  203. }
  204. int ssb_pcmcia_init(struct ssb_bus *bus)
  205. {
  206. conf_reg_t reg;
  207. int err;
  208. if (bus->bustype != SSB_BUSTYPE_PCMCIA)
  209. return 0;
  210. /* Switch segment to a known state and sync
  211. * bus->mapped_pcmcia_seg with hardware state. */
  212. ssb_pcmcia_switch_segment(bus, 0);
  213. /* Init IRQ routing */
  214. reg.Action = CS_READ;
  215. reg.Function = 0;
  216. if (bus->chip_id == 0x4306)
  217. reg.Offset = 0x00;
  218. else
  219. reg.Offset = 0x80;
  220. err = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
  221. if (err != CS_SUCCESS)
  222. goto error;
  223. reg.Action = CS_WRITE;
  224. reg.Value |= 0x04 | 0x01;
  225. err = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
  226. if (err != CS_SUCCESS)
  227. goto error;
  228. return 0;
  229. error:
  230. return -ENODEV;
  231. }