blob: 772d12c5fc9edf795547287c5e900753075e3bae [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
14#define reg_read(_phys) (*(unsigned int *) KSEG1ADDR(_phys))
15#define reg_write(_phys, _val) ((*(unsigned int *) KSEG1ADDR(_phys)) = (_val))
16
Gabor Juhosd624bd32012-03-14 10:29:26 +010017#define AR724X_PCI_DEV_BASE 0x14000000
18#define AR724X_PCI_MEM_BASE 0x10000000
19#define AR724X_PCI_MEM_SIZE 0x08000000
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000020
Gabor Juhosd624bd32012-03-14 10:29:26 +010021static DEFINE_SPINLOCK(ar724x_pci_lock);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000022
Gabor Juhosd624bd32012-03-14 10:29:26 +010023static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where,
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000024 int size, uint32_t *value)
25{
26 unsigned long flags, addr, tval, mask;
27
28 if (devfn)
29 return PCIBIOS_DEVICE_NOT_FOUND;
30
31 if (where & (size - 1))
32 return PCIBIOS_BAD_REGISTER_NUMBER;
33
Gabor Juhosd624bd32012-03-14 10:29:26 +010034 spin_lock_irqsave(&ar724x_pci_lock, flags);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000035
36 switch (size) {
37 case 1:
38 addr = where & ~3;
39 mask = 0xff000000 >> ((where % 4) * 8);
Gabor Juhosd624bd32012-03-14 10:29:26 +010040 tval = reg_read(AR724X_PCI_DEV_BASE + addr);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000041 tval = tval & ~mask;
42 *value = (tval >> ((4 - (where % 4))*8));
43 break;
44 case 2:
45 addr = where & ~3;
46 mask = 0xffff0000 >> ((where % 4)*8);
Gabor Juhosd624bd32012-03-14 10:29:26 +010047 tval = reg_read(AR724X_PCI_DEV_BASE + addr);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000048 tval = tval & ~mask;
49 *value = (tval >> ((4 - (where % 4))*8));
50 break;
51 case 4:
Gabor Juhosd624bd32012-03-14 10:29:26 +010052 *value = reg_read(AR724X_PCI_DEV_BASE + where);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000053 break;
54 default:
Gabor Juhosd624bd32012-03-14 10:29:26 +010055 spin_unlock_irqrestore(&ar724x_pci_lock, flags);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000056
57 return PCIBIOS_BAD_REGISTER_NUMBER;
58 }
59
Gabor Juhosd624bd32012-03-14 10:29:26 +010060 spin_unlock_irqrestore(&ar724x_pci_lock, flags);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000061
62 return PCIBIOS_SUCCESSFUL;
63}
64
Gabor Juhosd624bd32012-03-14 10:29:26 +010065static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where,
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000066 int size, uint32_t value)
67{
68 unsigned long flags, tval, addr, mask;
69
70 if (devfn)
71 return PCIBIOS_DEVICE_NOT_FOUND;
72
73 if (where & (size - 1))
74 return PCIBIOS_BAD_REGISTER_NUMBER;
75
Gabor Juhosd624bd32012-03-14 10:29:26 +010076 spin_lock_irqsave(&ar724x_pci_lock, flags);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000077
78 switch (size) {
79 case 1:
Gabor Juhosd624bd32012-03-14 10:29:26 +010080 addr = (AR724X_PCI_DEV_BASE + where) & ~3;
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000081 mask = 0xff000000 >> ((where % 4)*8);
82 tval = reg_read(addr);
83 tval = tval & ~mask;
84 tval |= (value << ((4 - (where % 4))*8)) & mask;
85 reg_write(addr, tval);
86 break;
87 case 2:
Gabor Juhosd624bd32012-03-14 10:29:26 +010088 addr = (AR724X_PCI_DEV_BASE + where) & ~3;
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000089 mask = 0xffff0000 >> ((where % 4)*8);
90 tval = reg_read(addr);
91 tval = tval & ~mask;
92 tval |= (value << ((4 - (where % 4))*8)) & mask;
93 reg_write(addr, tval);
94 break;
95 case 4:
Gabor Juhosd624bd32012-03-14 10:29:26 +010096 reg_write((AR724X_PCI_DEV_BASE + where), value);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +000097 break;
98 default:
Gabor Juhosd624bd32012-03-14 10:29:26 +010099 spin_unlock_irqrestore(&ar724x_pci_lock, flags);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000100
101 return PCIBIOS_BAD_REGISTER_NUMBER;
102 }
103
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_SUCCESSFUL;
107}
108
Gabor Juhosd624bd32012-03-14 10:29:26 +0100109static struct pci_ops ar724x_pci_ops = {
110 .read = ar724x_pci_read,
111 .write = ar724x_pci_write,
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000112};
113
Gabor Juhosd624bd32012-03-14 10:29:26 +0100114static struct resource ar724x_io_resource = {
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000115 .name = "PCI IO space",
116 .start = 0,
117 .end = 0,
118 .flags = IORESOURCE_IO,
119};
120
Gabor Juhosd624bd32012-03-14 10:29:26 +0100121static struct resource ar724x_mem_resource = {
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000122 .name = "PCI memory space",
Gabor Juhosd624bd32012-03-14 10:29:26 +0100123 .start = AR724X_PCI_MEM_BASE,
124 .end = AR724X_PCI_MEM_BASE + AR724X_PCI_MEM_SIZE - 1,
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000125 .flags = IORESOURCE_MEM,
126};
127
Gabor Juhosd624bd32012-03-14 10:29:26 +0100128static struct pci_controller ar724x_pci_controller = {
129 .pci_ops = &ar724x_pci_ops,
130 .io_resource = &ar724x_io_resource,
131 .mem_resource = &ar724x_mem_resource,
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000132};
133
Gabor Juhosd624bd32012-03-14 10:29:26 +0100134int __init ar724x_pcibios_init(void)
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000135{
Gabor Juhosd624bd32012-03-14 10:29:26 +0100136 register_pci_controller(&ar724x_pci_controller);
Rene Bolldorf4ff40d52011-11-17 14:25:09 +0000137
138 return PCIBIOS_SUCCESSFUL;
139}