]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/mips/pci/pci-ath724x.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[karo-tx-linux.git] / arch / mips / pci / pci-ath724x.c
1 /*
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>
12 #include <asm/mach-ath79/pci-ath724x.h>
13
14 #define reg_read(_phys)         (*(unsigned int *) KSEG1ADDR(_phys))
15 #define reg_write(_phys, _val)  ((*(unsigned int *) KSEG1ADDR(_phys)) = (_val))
16
17 #define ATH724X_PCI_DEV_BASE    0x14000000
18 #define ATH724X_PCI_MEM_BASE    0x10000000
19 #define ATH724X_PCI_MEM_SIZE    0x08000000
20
21 static DEFINE_SPINLOCK(ath724x_pci_lock);
22 static struct ath724x_pci_data *pci_data;
23 static int pci_data_size;
24
25 static int ath724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where,
26                             int size, uint32_t *value)
27 {
28         unsigned long flags, addr, tval, mask;
29
30         if (devfn)
31                 return PCIBIOS_DEVICE_NOT_FOUND;
32
33         if (where & (size - 1))
34                 return PCIBIOS_BAD_REGISTER_NUMBER;
35
36         spin_lock_irqsave(&ath724x_pci_lock, flags);
37
38         switch (size) {
39         case 1:
40                 addr = where & ~3;
41                 mask = 0xff000000 >> ((where % 4) * 8);
42                 tval = reg_read(ATH724X_PCI_DEV_BASE + addr);
43                 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);
49                 tval = reg_read(ATH724X_PCI_DEV_BASE + addr);
50                 tval = tval & ~mask;
51                 *value = (tval >> ((4 - (where % 4))*8));
52                 break;
53         case 4:
54                 *value = reg_read(ATH724X_PCI_DEV_BASE + where);
55                 break;
56         default:
57                 spin_unlock_irqrestore(&ath724x_pci_lock, flags);
58
59                 return PCIBIOS_BAD_REGISTER_NUMBER;
60         }
61
62         spin_unlock_irqrestore(&ath724x_pci_lock, flags);
63
64         return PCIBIOS_SUCCESSFUL;
65 }
66
67 static int ath724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where,
68                              int size, uint32_t value)
69 {
70         unsigned long flags, tval, addr, mask;
71
72         if (devfn)
73                 return PCIBIOS_DEVICE_NOT_FOUND;
74
75         if (where & (size - 1))
76                 return PCIBIOS_BAD_REGISTER_NUMBER;
77
78         spin_lock_irqsave(&ath724x_pci_lock, flags);
79
80         switch (size) {
81         case 1:
82                 addr = (ATH724X_PCI_DEV_BASE + where) & ~3;
83                 mask = 0xff000000 >> ((where % 4)*8);
84                 tval = reg_read(addr);
85                 tval = tval & ~mask;
86                 tval |= (value << ((4 - (where % 4))*8)) & mask;
87                 reg_write(addr, tval);
88                 break;
89         case 2:
90                 addr = (ATH724X_PCI_DEV_BASE + where) & ~3;
91                 mask = 0xffff0000 >> ((where % 4)*8);
92                 tval = reg_read(addr);
93                 tval = tval & ~mask;
94                 tval |= (value << ((4 - (where % 4))*8)) & mask;
95                 reg_write(addr, tval);
96                 break;
97         case 4:
98                 reg_write((ATH724X_PCI_DEV_BASE + where), value);
99                 break;
100         default:
101                 spin_unlock_irqrestore(&ath724x_pci_lock, flags);
102
103                 return PCIBIOS_BAD_REGISTER_NUMBER;
104         }
105
106         spin_unlock_irqrestore(&ath724x_pci_lock, flags);
107
108         return PCIBIOS_SUCCESSFUL;
109 }
110
111 static struct pci_ops ath724x_pci_ops = {
112         .read   = ath724x_pci_read,
113         .write  = ath724x_pci_write,
114 };
115
116 static struct resource ath724x_io_resource = {
117         .name   = "PCI IO space",
118         .start  = 0,
119         .end    = 0,
120         .flags  = IORESOURCE_IO,
121 };
122
123 static struct resource ath724x_mem_resource = {
124         .name   = "PCI memory space",
125         .start  = ATH724X_PCI_MEM_BASE,
126         .end    = ATH724X_PCI_MEM_BASE + ATH724X_PCI_MEM_SIZE - 1,
127         .flags  = IORESOURCE_MEM,
128 };
129
130 static struct pci_controller ath724x_pci_controller = {
131         .pci_ops        = &ath724x_pci_ops,
132         .io_resource    = &ath724x_io_resource,
133         .mem_resource   = &ath724x_mem_resource,
134 };
135
136 void ath724x_pci_add_data(struct ath724x_pci_data *data, int size)
137 {
138         pci_data        = data;
139         pci_data_size   = size;
140 }
141
142 int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin)
143 {
144         unsigned int devfn = dev->devfn;
145         int irq = -1;
146
147         if (devfn > pci_data_size - 1)
148                 return irq;
149
150         irq = pci_data[devfn].irq;
151
152         return irq;
153 }
154
155 int pcibios_plat_dev_init(struct pci_dev *dev)
156 {
157         unsigned int devfn = dev->devfn;
158
159         if (devfn > pci_data_size - 1)
160                 return PCIBIOS_DEVICE_NOT_FOUND;
161
162         dev->dev.platform_data = pci_data[devfn].pdata;
163
164         return PCIBIOS_SUCCESSFUL;
165 }
166
167 static int __init ath724x_pcibios_init(void)
168 {
169         register_pci_controller(&ath724x_pci_controller);
170
171         return PCIBIOS_SUCCESSFUL;
172 }
173
174 arch_initcall(ath724x_pcibios_init);