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 
ath724x_pci_read(struct pci_bus * bus,unsigned int devfn,int where,int size,uint32_t * value)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 
ath724x_pci_write(struct pci_bus * bus,unsigned int devfn,int where,int size,uint32_t value)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 
ath724x_pci_add_data(struct ath724x_pci_data * data,int size)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 
pcibios_map_irq(const struct pci_dev * dev,uint8_t slot,uint8_t pin)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 
pcibios_plat_dev_init(struct pci_dev * dev)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 
ath724x_pcibios_init(void)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);
175