blob: bb4f2162d4e4b3464c2c0c2856725e30356c0f57 [file] [log] [blame]
Rene Bolldorf4ff40d52011-11-17 14:25:09 +00001/*
2 * Atheros 724x PCI support
3 *
4 * Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published
8 * by the Free Software Foundation.
9 */
10
11#include <linux/pci.h>
Gabor Juhos659243c2012-03-14 10:29:23 +010012#include <asm/mach-ath79/pci.h>
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000013
Gabor Juhosc1984412012-03-14 10:29:27 +010014#define AR724X_PCI_CFG_BASE 0x14000000
15#define AR724X_PCI_CFG_SIZE 0x1000
Gabor Juhosd624bd32012-03-14 10:29:26 +010016#define AR724X_PCI_MEM_BASE 0x10000000
17#define AR724X_PCI_MEM_SIZE 0x08000000
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000018
Gabor Juhosd624bd32012-03-14 10:29:26 +010019static DEFINE_SPINLOCK(ar724x_pci_lock);
Gabor Juhosc1984412012-03-14 10:29:27 +010020static void __iomem *ar724x_pci_devcfg_base;
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000021
Gabor Juhosd624bd32012-03-14 10:29:26 +010022static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where,
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000023 int size, uint32_t *value)
24{
Gabor Juhos64adb6b2012-03-14 10:36:04 +010025 unsigned long flags;
Gabor Juhosc1984412012-03-14 10:29:27 +010026 void __iomem *base;
Gabor Juhos64adb6b2012-03-14 10:36:04 +010027 u32 data;
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000028
29 if (devfn)
30 return PCIBIOS_DEVICE_NOT_FOUND;
31
Gabor Juhosc1984412012-03-14 10:29:27 +010032 base = ar724x_pci_devcfg_base;
33
Gabor Juhosd624bd32012-03-14 10:29:26 +010034 spin_lock_irqsave(&ar724x_pci_lock, flags);
Gabor Juhos64adb6b2012-03-14 10:36:04 +010035 data = __raw_readl(base + (where & ~3));
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000036
37 switch (size) {
38 case 1:
Gabor Juhos64adb6b2012-03-14 10:36:04 +010039 if (where & 1)
40 data >>= 8;
41 if (where & 2)
42 data >>= 16;
43 data &= 0xff;
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000044 break;
45 case 2:
Gabor Juhos64adb6b2012-03-14 10:36:04 +010046 if (where & 2)
47 data >>= 16;
48 data &= 0xffff;
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000049 break;
50 case 4:
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000051 break;
52 default:
Gabor Juhosd624bd32012-03-14 10:29:26 +010053 spin_unlock_irqrestore(&ar724x_pci_lock, flags);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000054
55 return PCIBIOS_BAD_REGISTER_NUMBER;
56 }
57
Gabor Juhosd624bd32012-03-14 10:29:26 +010058 spin_unlock_irqrestore(&ar724x_pci_lock, flags);
Gabor Juhos64adb6b2012-03-14 10:36:04 +010059 *value = data;
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000060
61 return PCIBIOS_SUCCESSFUL;
62}
63
Gabor Juhosd624bd32012-03-14 10:29:26 +010064static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where,
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000065 int size, uint32_t value)
66{
Gabor Juhos64adb6b2012-03-14 10:36:04 +010067 unsigned long flags;
Gabor Juhosc1984412012-03-14 10:29:27 +010068 void __iomem *base;
Gabor Juhos64adb6b2012-03-14 10:36:04 +010069 u32 data;
70 int s;
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000071
72 if (devfn)
73 return PCIBIOS_DEVICE_NOT_FOUND;
74
Gabor Juhosc1984412012-03-14 10:29:27 +010075 base = ar724x_pci_devcfg_base;
76
Gabor Juhosd624bd32012-03-14 10:29:26 +010077 spin_lock_irqsave(&ar724x_pci_lock, flags);
Gabor Juhos64adb6b2012-03-14 10:36:04 +010078 data = __raw_readl(base + (where & ~3));
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000079
80 switch (size) {
81 case 1:
Gabor Juhos64adb6b2012-03-14 10:36:04 +010082 s = ((where & 3) * 8);
83 data &= ~(0xff << s);
84 data |= ((value & 0xff) << s);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000085 break;
86 case 2:
Gabor Juhos64adb6b2012-03-14 10:36:04 +010087 s = ((where & 2) * 8);
88 data &= ~(0xffff << s);
89 data |= ((value & 0xffff) << s);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000090 break;
91 case 4:
Gabor Juhos64adb6b2012-03-14 10:36:04 +010092 data = value;
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000093 break;
94 default:
Gabor Juhosd624bd32012-03-14 10:29:26 +010095 spin_unlock_irqrestore(&ar724x_pci_lock, flags);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000096
97 return PCIBIOS_BAD_REGISTER_NUMBER;
98 }
99
Gabor Juhos64adb6b2012-03-14 10:36:04 +0100100 __raw_writel(data, base + (where & ~3));
101 /* flush write */
102 __raw_readl(base + (where & ~3));
Gabor Juhosd624bd32012-03-14 10:29:26 +0100103 spin_unlock_irqrestore(&ar724x_pci_lock, flags);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000104
105 return PCIBIOS_SUCCESSFUL;
106}
107
Gabor Juhosd624bd32012-03-14 10:29:26 +0100108static struct pci_ops ar724x_pci_ops = {
109 .read = ar724x_pci_read,
110 .write = ar724x_pci_write,
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000111};
112
Gabor Juhosd624bd32012-03-14 10:29:26 +0100113static struct resource ar724x_io_resource = {
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000114 .name = "PCI IO space",
115 .start = 0,
116 .end = 0,
117 .flags = IORESOURCE_IO,
118};
119
Gabor Juhosd624bd32012-03-14 10:29:26 +0100120static struct resource ar724x_mem_resource = {
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000121 .name = "PCI memory space",
Gabor Juhosd624bd32012-03-14 10:29:26 +0100122 .start = AR724X_PCI_MEM_BASE,
123 .end = AR724X_PCI_MEM_BASE + AR724X_PCI_MEM_SIZE - 1,
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000124 .flags = IORESOURCE_MEM,
125};
126
Gabor Juhosd624bd32012-03-14 10:29:26 +0100127static struct pci_controller ar724x_pci_controller = {
128 .pci_ops = &ar724x_pci_ops,
129 .io_resource = &ar724x_io_resource,
130 .mem_resource = &ar724x_mem_resource,
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000131};
132
Gabor Juhosd624bd32012-03-14 10:29:26 +0100133int __init ar724x_pcibios_init(void)
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000134{
Gabor Juhosc1984412012-03-14 10:29:27 +0100135 ar724x_pci_devcfg_base = ioremap(AR724X_PCI_CFG_BASE,
136 AR724X_PCI_CFG_SIZE);
137 if (ar724x_pci_devcfg_base == NULL)
138 return -ENOMEM;
139
Gabor Juhosd624bd32012-03-14 10:29:26 +0100140 register_pci_controller(&ar724x_pci_controller);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000141
142 return PCIBIOS_SUCCESSFUL;
143}