140-arm-gemini-add-pci-support.patch 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. --- a/arch/arm/Kconfig
  2. +++ b/arch/arm/Kconfig
  3. @@ -400,6 +400,7 @@ config ARCH_GEMINI
  4. select CLKSRC_MMIO
  5. select CPU_FA526
  6. select GENERIC_CLOCKEVENTS
  7. + select MIGHT_HAVE_PCI
  8. help
  9. Support for the Cortina Systems Gemini family SoCs
  10. --- a/arch/arm/mach-gemini/include/mach/hardware.h
  11. +++ b/arch/arm/mach-gemini/include/mach/hardware.h
  12. @@ -71,4 +71,9 @@
  13. */
  14. #define IO_ADDRESS(x) IOMEM((((x) & 0xFFF00000) >> 4) | ((x) & 0x000FFFFF) | 0xF0000000)
  15. +/*
  16. + * PCI subsystem macros
  17. + */
  18. +#define pcibios_assign_all_busses() 1
  19. +
  20. #endif
  21. --- a/arch/arm/mach-gemini/include/mach/irqs.h
  22. +++ b/arch/arm/mach-gemini/include/mach/irqs.h
  23. @@ -43,11 +43,14 @@
  24. #define NORMAL_IRQ_NUM 32
  25. -#define GPIO_IRQ_BASE NORMAL_IRQ_NUM
  26. +#define PCI_IRQ_BASE NORMAL_IRQ_NUM
  27. +#define PCI_IRQ_NUM 4
  28. +
  29. +#define GPIO_IRQ_BASE (NORMAL_IRQ_NUM + PCI_IRQ_NUM)
  30. #define GPIO_IRQ_NUM (3 * 32)
  31. #define ARCH_TIMER_IRQ IRQ_TIMER2
  32. -#define NR_IRQS (NORMAL_IRQ_NUM + GPIO_IRQ_NUM)
  33. +#define NR_IRQS (NORMAL_IRQ_NUM + PCI_IRQ_NUM + GPIO_IRQ_NUM)
  34. #endif /* __MACH_IRQS_H__ */
  35. --- a/arch/arm/mach-gemini/Makefile
  36. +++ b/arch/arm/mach-gemini/Makefile
  37. @@ -6,6 +6,8 @@
  38. obj-y := irq.o mm.o time.o devices.o gpio.o idle.o reset.o
  39. +obj-$(CONFIG_PCI) += pci.o
  40. +
  41. # Board-specific support
  42. obj-$(CONFIG_MACH_NAS4220B) += board-nas4220b.o
  43. obj-$(CONFIG_MACH_RUT100) += board-rut1xx.o
  44. --- a/arch/arm/mach-gemini/mm.c
  45. +++ b/arch/arm/mach-gemini/mm.c
  46. @@ -59,6 +59,11 @@ static struct map_desc gemini_io_desc[]
  47. .length = SZ_512K,
  48. .type = MT_DEVICE,
  49. }, {
  50. + .virtual = (unsigned long)IO_ADDRESS(GEMINI_PCI_IO_BASE),
  51. + .pfn = __phys_to_pfn(GEMINI_PCI_IO_BASE),
  52. + .length = SZ_512K,
  53. + .type = MT_DEVICE,
  54. + }, {
  55. .virtual = (unsigned long)IO_ADDRESS(GEMINI_FLASH_CTRL_BASE),
  56. .pfn = __phys_to_pfn(GEMINI_FLASH_CTRL_BASE),
  57. .length = SZ_512K,
  58. --- /dev/null
  59. +++ b/arch/arm/mach-gemini/pci.c
  60. @@ -0,0 +1,320 @@
  61. +/*
  62. + * Support for Gemini PCI Controller
  63. + *
  64. + * Copyright (C) 2009 Janos Laube <janos.dev@gmail.com>
  65. + * Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
  66. + *
  67. + * based on SL2312 PCI controller code
  68. + * Storlink (C) 2003
  69. + *
  70. + * This program is free software; you can redistribute it and/or modify
  71. + * it under the terms of the GNU General Public License as published by
  72. + * the Free Software Foundation; either version 2 of the License, or
  73. + * (at your option) any later version.
  74. + */
  75. +
  76. +#include <linux/kernel.h>
  77. +#include <linux/pci.h>
  78. +#include <linux/irq.h>
  79. +#include <linux/gpio.h>
  80. +
  81. +#include <asm/mach/pci.h>
  82. +
  83. +#include <mach/irqs.h>
  84. +#include <mach/hardware.h>
  85. +
  86. +#define GEMINI_PCI_IOSIZE_1M 0x0000
  87. +
  88. +#define GEMINI_PCI_PMC 0x40
  89. +#define GEMINI_PCI_PMCSR 0x44
  90. +#define GEMINI_PCI_CTRL1 0x48
  91. +#define GEMINI_PCI_CTRL2 0x4C
  92. +#define GEMINI_PCI_MEM1_BASE_SIZE 0x50
  93. +#define GEMINI_PCI_MEM2_BASE_SIZE 0x54
  94. +#define GEMINI_PCI_MEM3_BASE_SIZE 0x58
  95. +
  96. +#define PCI_CTRL2_INTSTS_OFFSET 28
  97. +#define PCI_CTRL2_INTMASK_OFFSET 22
  98. +
  99. +#define GEMINI_PCI_DMA_MASK 0xFFF00000
  100. +#define GEMINI_PCI_DMA_MEM1_BASE 0x00000000
  101. +#define GEMINI_PCI_DMA_MEM2_BASE 0x00000000
  102. +#define GEMINI_PCI_DMA_MEM3_BASE 0x00000000
  103. +#define GEMINI_PCI_DMA_MEM1_SIZE 7
  104. +#define GEMINI_PCI_DMA_MEM2_SIZE 6
  105. +#define GEMINI_PCI_DMA_MEM3_SIZE 6
  106. +
  107. +#define PCI_CONF_ENABLE (1 << 31)
  108. +#define PCI_CONF_WHERE(r) ((r) & 0xFC)
  109. +#define PCI_CONF_BUS(b) (((b) & 0xFF) << 16)
  110. +#define PCI_CONF_DEVICE(d) (((d) & 0x1F) << 11)
  111. +#define PCI_CONF_FUNCTION(f) (((f) & 0x07) << 8)
  112. +
  113. +#define PCI_IOSIZE_REG (IO_ADDRESS(GEMINI_PCI_IO_BASE))
  114. +#define PCI_PROT_REG (IO_ADDRESS(GEMINI_PCI_IO_BASE) + 0x04)
  115. +#define PCI_CTRL_REG (IO_ADDRESS(GEMINI_PCI_IO_BASE) + 0x08)
  116. +#define PCI_SOFTRST_REG (IO_ADDRESS(GEMINI_PCI_IO_BASE) + 0x10)
  117. +#define PCI_CONFIG_REG (IO_ADDRESS(GEMINI_PCI_IO_BASE) + 0x28)
  118. +#define PCI_DATA_REG (IO_ADDRESS(GEMINI_PCI_IO_BASE) + 0x2C)
  119. +
  120. +
  121. +static DEFINE_SPINLOCK(gemini_pci_lock);
  122. +
  123. +static int gemini_pci_read_config(struct pci_bus* bus, unsigned int fn,
  124. + int config, int size, u32* value)
  125. +{
  126. + unsigned long irq_flags;
  127. +
  128. + spin_lock_irqsave(&gemini_pci_lock, irq_flags);
  129. +
  130. + __raw_writel(PCI_CONF_BUS(bus->number) |
  131. + PCI_CONF_DEVICE(PCI_SLOT(fn)) |
  132. + PCI_CONF_FUNCTION(PCI_FUNC(fn)) |
  133. + PCI_CONF_WHERE(config) |
  134. + PCI_CONF_ENABLE,
  135. + PCI_CONFIG_REG);
  136. +
  137. + *value = __raw_readl(PCI_DATA_REG);
  138. +
  139. + if (size == 1)
  140. + *value = (*value >> (8 * (config & 3))) & 0xFF;
  141. + else if (size == 2)
  142. + *value = (*value >> (8 * (config & 3))) & 0xFFFF;
  143. +
  144. + spin_unlock_irqrestore(&gemini_pci_lock, irq_flags);
  145. +
  146. + dev_dbg(&bus->dev,
  147. + "[read] slt: %.2d, fnc: %d, cnf: 0x%.2X, val (%d bytes): 0x%.8X\n",
  148. + PCI_SLOT(fn), PCI_FUNC(fn), config, size, *value);
  149. +
  150. + return PCIBIOS_SUCCESSFUL;
  151. +}
  152. +
  153. +static int gemini_pci_write_config(struct pci_bus* bus, unsigned int fn,
  154. + int config, int size, u32 value)
  155. +{
  156. + unsigned long irq_flags = 0;
  157. + int ret = PCIBIOS_SUCCESSFUL;
  158. +
  159. + dev_dbg(&bus->dev,
  160. + "[write] slt: %.2d, fnc: %d, cnf: 0x%.2X, val (%d bytes): 0x%.8X\n",
  161. + PCI_SLOT(fn), PCI_FUNC(fn), config, size, value);
  162. +
  163. + spin_lock_irqsave(&gemini_pci_lock, irq_flags);
  164. +
  165. + __raw_writel(PCI_CONF_BUS(bus->number) |
  166. + PCI_CONF_DEVICE(PCI_SLOT(fn)) |
  167. + PCI_CONF_FUNCTION(PCI_FUNC(fn)) |
  168. + PCI_CONF_WHERE(config) |
  169. + PCI_CONF_ENABLE,
  170. + PCI_CONFIG_REG);
  171. +
  172. + switch(size) {
  173. + case 4:
  174. + __raw_writel(value, PCI_DATA_REG);
  175. + break;
  176. + case 2:
  177. + __raw_writew(value, PCI_DATA_REG + (config & 3));
  178. + break;
  179. + case 1:
  180. + __raw_writeb(value, PCI_DATA_REG + (config & 3));
  181. + break;
  182. + default:
  183. + ret = PCIBIOS_BAD_REGISTER_NUMBER;
  184. + }
  185. +
  186. + spin_unlock_irqrestore(&gemini_pci_lock, irq_flags);
  187. +
  188. + return ret;
  189. +}
  190. +
  191. +static struct pci_ops gemini_pci_ops = {
  192. + .read = gemini_pci_read_config,
  193. + .write = gemini_pci_write_config,
  194. +};
  195. +
  196. +static struct resource gemini_pci_resource_io = {
  197. + .name = "PCI I/O Space",
  198. + .start = GEMINI_PCI_IO_BASE,
  199. + .end = GEMINI_PCI_IO_BASE + SZ_1M - 1,
  200. + .flags = IORESOURCE_IO,
  201. +};
  202. +
  203. +static struct resource gemini_pci_resource_mem = {
  204. + .name = "PCI Memory Space",
  205. + .start = GEMINI_PCI_MEM_BASE,
  206. + .end = GEMINI_PCI_MEM_BASE + SZ_128M - 1,
  207. + .flags = IORESOURCE_MEM,
  208. +};
  209. +
  210. +static int __init gemini_pci_request_resources(struct pci_sys_data *sys)
  211. +{
  212. + if (request_resource(&ioport_resource, &gemini_pci_resource_io))
  213. + goto bad_resources;
  214. + if (request_resource(&iomem_resource, &gemini_pci_resource_mem))
  215. + goto bad_resources;
  216. +
  217. + pci_add_resource(&sys->resources, &gemini_pci_resource_io);
  218. + pci_add_resource(&sys->resources, &gemini_pci_resource_mem);
  219. +
  220. + return 0;
  221. +
  222. +bad_resources:
  223. + pr_err("Gemini PCI: request_resource() failed. "
  224. + "Abort PCI bus enumeration.\n");
  225. + return -1;
  226. +}
  227. +
  228. +static int __init gemini_pci_setup(int nr, struct pci_sys_data *sys)
  229. +{
  230. + unsigned int cmd;
  231. +
  232. + pcibios_min_io = 0x100;
  233. + pcibios_min_mem = 0;
  234. +
  235. + if ((nr > 0) || gemini_pci_request_resources(sys))
  236. + return 0;
  237. +
  238. + /* setup I/O space to 1MB size */
  239. + __raw_writel(GEMINI_PCI_IOSIZE_1M, PCI_IOSIZE_REG);
  240. +
  241. + /* setup hostbridge */
  242. + cmd = __raw_readl(PCI_CTRL_REG);
  243. + cmd |= PCI_COMMAND_IO;
  244. + cmd |= PCI_COMMAND_MEMORY;
  245. + cmd |= PCI_COMMAND_MASTER;
  246. + __raw_writel(cmd, PCI_CTRL_REG);
  247. +
  248. + return 1;
  249. +}
  250. +
  251. +static struct pci_bus* __init gemini_pci_scan_bus(int nr, struct pci_sys_data* sys)
  252. +{
  253. + unsigned int reg = 0;
  254. + struct pci_bus* bus = 0;
  255. +
  256. + bus = pci_scan_bus(nr, &gemini_pci_ops, sys);
  257. + if (bus) {
  258. + dev_dbg(&bus->dev, "setting up PCI DMA\n");
  259. + reg = (GEMINI_PCI_DMA_MEM1_BASE & GEMINI_PCI_DMA_MASK)
  260. + | (GEMINI_PCI_DMA_MEM1_SIZE << 16);
  261. + gemini_pci_write_config(bus, 0, GEMINI_PCI_MEM1_BASE_SIZE, 4, reg);
  262. + reg = (GEMINI_PCI_DMA_MEM2_BASE & GEMINI_PCI_DMA_MASK)
  263. + | (GEMINI_PCI_DMA_MEM2_SIZE << 16);
  264. + gemini_pci_write_config(bus, 0, GEMINI_PCI_MEM2_BASE_SIZE, 4, reg);
  265. + reg = (GEMINI_PCI_DMA_MEM3_BASE & GEMINI_PCI_DMA_MASK)
  266. + | (GEMINI_PCI_DMA_MEM3_SIZE << 16);
  267. + gemini_pci_write_config(bus, 0, GEMINI_PCI_MEM3_BASE_SIZE, 4, reg);
  268. + }
  269. +
  270. + return bus;
  271. +}
  272. +
  273. +/* Should work with all boards based on original Storlink EVB */
  274. +static int __init gemini_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
  275. +{
  276. + if (slot < 9 || slot > 12)
  277. + return -1;
  278. +
  279. + return PCI_IRQ_BASE + (((slot - 9) + (pin - 1)) & 0x3);
  280. +}
  281. +
  282. +static struct hw_pci gemini_hw_pci __initdata = {
  283. + .nr_controllers = 1,
  284. + .setup = gemini_pci_setup,
  285. + .scan = gemini_pci_scan_bus,
  286. + .map_irq = gemini_pci_map_irq,
  287. +};
  288. +
  289. +/* we need this for muxed PCI interrupts handling */
  290. +static struct pci_bus bogus_pci_bus;
  291. +
  292. +static void gemini_pci_ack_irq(struct irq_data *d)
  293. +{
  294. + unsigned int irq = d->irq;
  295. + unsigned int reg;
  296. +
  297. + gemini_pci_read_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, &reg);
  298. + reg &= ~(0xF << PCI_CTRL2_INTSTS_OFFSET);
  299. + reg |= 1 << (irq - PCI_IRQ_BASE + PCI_CTRL2_INTSTS_OFFSET);
  300. + gemini_pci_write_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, reg);
  301. +}
  302. +
  303. +static void gemini_pci_mask_irq(struct irq_data *d)
  304. +{
  305. + unsigned int irq = d->irq;
  306. + unsigned int reg;
  307. +
  308. + gemini_pci_read_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, &reg);
  309. + reg &= ~((0xF << PCI_CTRL2_INTSTS_OFFSET)
  310. + | (1 << (irq - PCI_IRQ_BASE + PCI_CTRL2_INTMASK_OFFSET)));
  311. + gemini_pci_write_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, reg);
  312. +}
  313. +
  314. +static void gemini_pci_unmask_irq(struct irq_data *d)
  315. +{
  316. + unsigned int irq = d->irq;
  317. + unsigned int reg;
  318. +
  319. + gemini_pci_read_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, &reg);
  320. + reg &= ~(0xF << PCI_CTRL2_INTSTS_OFFSET);
  321. + reg |= 1 << (irq - PCI_IRQ_BASE + PCI_CTRL2_INTMASK_OFFSET);
  322. + gemini_pci_write_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, reg);
  323. +}
  324. +
  325. +static void gemini_pci_irq_handler(unsigned int irq, struct irq_desc *desc)
  326. +{
  327. + unsigned int pci_irq_no, irq_stat, reg, i;
  328. +
  329. + gemini_pci_read_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, &reg);
  330. + irq_stat = reg >> PCI_CTRL2_INTSTS_OFFSET;
  331. +
  332. + for (i = 0; i < 4; i++) {
  333. +
  334. + if ((irq_stat & (1 << i)) == 0)
  335. + continue;
  336. +
  337. + pci_irq_no = PCI_IRQ_BASE + i;
  338. +
  339. + BUG_ON(!(irq_desc[pci_irq_no].handle_irq));
  340. + irq_desc[pci_irq_no].handle_irq(pci_irq_no,
  341. + &irq_desc[pci_irq_no]);
  342. + }
  343. +}
  344. +
  345. +static struct irq_chip gemini_pci_irq_chip = {
  346. + .name = "PCI",
  347. + .irq_ack = gemini_pci_ack_irq,
  348. + .irq_mask = gemini_pci_mask_irq,
  349. + .irq_unmask = gemini_pci_unmask_irq,
  350. +};
  351. +
  352. +static int __init gemini_pci_init(void)
  353. +{
  354. + int i;
  355. +
  356. + for (i = 72; i <= 95; i++)
  357. + gpio_request(i, "PCI");
  358. +
  359. + /* initialize our bogus bus */
  360. + dev_set_name(&bogus_pci_bus.dev, "PCI IRQ handler");
  361. + bogus_pci_bus.number = 0;
  362. +
  363. + /* mask and clear all interrupts */
  364. + gemini_pci_write_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2 + 2, 2,
  365. + 0xF000);
  366. +
  367. + for (i = PCI_IRQ_BASE; i < PCI_IRQ_BASE + 4; i++) {
  368. + irq_set_chip_and_handler(i, &gemini_pci_irq_chip,
  369. + handle_level_irq);
  370. + set_irq_flags(i, IRQF_VALID);
  371. + }
  372. +
  373. + irq_set_chained_handler(IRQ_PCI, gemini_pci_irq_handler);
  374. +
  375. + pci_common_init(&gemini_hw_pci);
  376. +
  377. + return 0;
  378. +}
  379. +
  380. +subsys_initcall(gemini_pci_init);