blob: 22f5e5bc4dfe872f23d09fed43a68d496981a7b2 [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{
25 unsigned long flags, addr, tval, mask;
Gabor Juhosc1984412012-03-14 10:29:27 +010026 void __iomem *base;
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000027
28 if (devfn)
29 return PCIBIOS_DEVICE_NOT_FOUND;
30
31 if (where & (size - 1))
32 return PCIBIOS_BAD_REGISTER_NUMBER;
33
Gabor Juhosc1984412012-03-14 10:29:27 +010034 base = ar724x_pci_devcfg_base;
35
Gabor Juhosd624bd32012-03-14 10:29:26 +010036 spin_lock_irqsave(&ar724x_pci_lock, flags);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000037
38 switch (size) {
39 case 1:
40 addr = where & ~3;
41 mask = 0xff000000 >> ((where % 4) * 8);
Gabor Juhosc1984412012-03-14 10:29:27 +010042 tval = __raw_readl(base + addr);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000043 tval = tval & ~mask;
44 *value = (tval >> ((4 - (where % 4))*8));
45 break;
46 case 2:
47 addr = where & ~3;
48 mask = 0xffff0000 >> ((where % 4)*8);
Gabor Juhosc1984412012-03-14 10:29:27 +010049 tval = __raw_readl(base + addr);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000050 tval = tval & ~mask;
51 *value = (tval >> ((4 - (where % 4))*8));
52 break;
53 case 4:
Gabor Juhosc1984412012-03-14 10:29:27 +010054 *value = __raw_readl(base + where);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000055 break;
56 default:
Gabor Juhosd624bd32012-03-14 10:29:26 +010057 spin_unlock_irqrestore(&ar724x_pci_lock, flags);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000058
59 return PCIBIOS_BAD_REGISTER_NUMBER;
60 }
61
Gabor Juhosd624bd32012-03-14 10:29:26 +010062 spin_unlock_irqrestore(&ar724x_pci_lock, flags);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000063
64 return PCIBIOS_SUCCESSFUL;
65}
66
Gabor Juhosd624bd32012-03-14 10:29:26 +010067static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where,
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000068 int size, uint32_t value)
69{
70 unsigned long flags, tval, addr, mask;
Gabor Juhosc1984412012-03-14 10:29:27 +010071 void __iomem *base;
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000072
73 if (devfn)
74 return PCIBIOS_DEVICE_NOT_FOUND;
75
76 if (where & (size - 1))
77 return PCIBIOS_BAD_REGISTER_NUMBER;
78
Gabor Juhosc1984412012-03-14 10:29:27 +010079 base = ar724x_pci_devcfg_base;
80
Gabor Juhosd624bd32012-03-14 10:29:26 +010081 spin_lock_irqsave(&ar724x_pci_lock, flags);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000082
83 switch (size) {
84 case 1:
Gabor Juhosc1984412012-03-14 10:29:27 +010085 addr = where & ~3;
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000086 mask = 0xff000000 >> ((where % 4)*8);
Gabor Juhosc1984412012-03-14 10:29:27 +010087 tval = __raw_readl(base + addr);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000088 tval = tval & ~mask;
89 tval |= (value << ((4 - (where % 4))*8)) & mask;
Gabor Juhosc1984412012-03-14 10:29:27 +010090 __raw_writel(tval, base + addr);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000091 break;
92 case 2:
Gabor Juhosc1984412012-03-14 10:29:27 +010093 addr = where & ~3;
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000094 mask = 0xffff0000 >> ((where % 4)*8);
Gabor Juhosc1984412012-03-14 10:29:27 +010095 tval = __raw_readl(base + addr);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000096 tval = tval & ~mask;
97 tval |= (value << ((4 - (where % 4))*8)) & mask;
Gabor Juhosc1984412012-03-14 10:29:27 +010098 __raw_writel(tval, base + addr);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000099 break;
100 case 4:
Gabor Juhosc1984412012-03-14 10:29:27 +0100101 __raw_writel(value, (base + where));
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000102 break;
103 default:
Gabor Juhosd624bd32012-03-14 10:29:26 +0100104 spin_unlock_irqrestore(&ar724x_pci_lock, flags);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000105
106 return PCIBIOS_BAD_REGISTER_NUMBER;
107 }
108
Gabor Juhosd624bd32012-03-14 10:29:26 +0100109 spin_unlock_irqrestore(&ar724x_pci_lock, flags);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000110
111 return PCIBIOS_SUCCESSFUL;
112}
113
Gabor Juhosd624bd32012-03-14 10:29:26 +0100114static struct pci_ops ar724x_pci_ops = {
115 .read = ar724x_pci_read,
116 .write = ar724x_pci_write,
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000117};
118
Gabor Juhosd624bd32012-03-14 10:29:26 +0100119static struct resource ar724x_io_resource = {
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000120 .name = "PCI IO space",
121 .start = 0,
122 .end = 0,
123 .flags = IORESOURCE_IO,
124};
125
Gabor Juhosd624bd32012-03-14 10:29:26 +0100126static struct resource ar724x_mem_resource = {
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000127 .name = "PCI memory space",
Gabor Juhosd624bd32012-03-14 10:29:26 +0100128 .start = AR724X_PCI_MEM_BASE,
129 .end = AR724X_PCI_MEM_BASE + AR724X_PCI_MEM_SIZE - 1,
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000130 .flags = IORESOURCE_MEM,
131};
132
Gabor Juhosd624bd32012-03-14 10:29:26 +0100133static struct pci_controller ar724x_pci_controller = {
134 .pci_ops = &ar724x_pci_ops,
135 .io_resource = &ar724x_io_resource,
136 .mem_resource = &ar724x_mem_resource,
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000137};
138
Gabor Juhosd624bd32012-03-14 10:29:26 +0100139int __init ar724x_pcibios_init(void)
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000140{
Gabor Juhosc1984412012-03-14 10:29:27 +0100141 ar724x_pci_devcfg_base = ioremap(AR724X_PCI_CFG_BASE,
142 AR724X_PCI_CFG_SIZE);
143 if (ar724x_pci_devcfg_base == NULL)
144 return -ENOMEM;
145
Gabor Juhosd624bd32012-03-14 10:29:26 +0100146 register_pci_controller(&ar724x_pci_controller);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000147
148 return PCIBIOS_SUCCESSFUL;
149}