OpenWrt – Blame information for rev 2
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> |
||
3 | * Copyright (C) 2012 Florian Fainelli <florian@openwrt.org> |
||
4 | * |
||
5 | * This file is subject to the terms and conditions of the GNU General Public |
||
6 | * License. See the file "COPYING" in the main directory of this archive |
||
7 | * for more details. |
||
8 | * |
||
9 | * Note that this controller is identical to the ADM5120 one |
||
10 | */ |
||
11 | |||
12 | #include <linux/kernel.h> |
||
13 | #include <linux/init.h> |
||
14 | #include <linux/pci.h> |
||
15 | #include <linux/types.h> |
||
16 | #include <linux/spinlock.h> |
||
17 | |||
18 | #include <asm/byteorder.h> |
||
19 | #include <asm/pci.h> |
||
20 | #include <adm8668.h> |
||
21 | |||
22 | static DEFINE_SPINLOCK(pci_lock); |
||
23 | |||
24 | #define PCI_ENABLE 0x80000000 |
||
25 | #define ADMPCI_IO_BASE 0x12600000 |
||
26 | #define ADMPCI_IO_SIZE 0x1fffff |
||
27 | #define ADMPCI_MEM_BASE 0x16000000 |
||
28 | #define ADMPCI_MEM_SIZE 0x7ffffff |
||
29 | |||
30 | static inline void write_cfgaddr(u32 addr) |
||
31 | { |
||
32 | __raw_writel((addr | PCI_ENABLE), |
||
33 | (void __iomem *)KSEG1ADDR(ADM8668_PCICFG_BASE)); |
||
34 | } |
||
35 | |||
36 | static inline void write_cfgdata(u32 data) |
||
37 | { |
||
38 | __raw_writel(data, (void __iomem *)KSEG1ADDR(ADM8668_PCIDAT_BASE)); |
||
39 | } |
||
40 | |||
41 | static inline u32 read_cfgdata(void) |
||
42 | { |
||
43 | return __raw_readl((void __iomem *)KSEG1ADDR(ADM8668_PCIDAT_BASE)); |
||
44 | } |
||
45 | |||
46 | static inline u32 mkaddr(struct pci_bus *bus, unsigned int devfn, int where) |
||
47 | { |
||
48 | return ((bus->number & 0xff) << 16) | ((devfn & 0xff) << 8) | |
||
49 | (where & 0xfc); |
||
50 | } |
||
51 | |||
52 | static int pci_read_config(struct pci_bus *bus, unsigned int devfn, |
||
53 | int where, int size, u32 *val) |
||
54 | { |
||
55 | unsigned long flags; |
||
56 | u32 data; |
||
57 | |||
58 | spin_lock_irqsave(&pci_lock, flags); |
||
59 | write_cfgaddr(mkaddr(bus, devfn, where)); |
||
60 | data = read_cfgdata(); |
||
61 | |||
62 | switch (size) { |
||
63 | case 1: |
||
64 | if (where & 1) |
||
65 | data >>= 8; |
||
66 | if (where & 2) |
||
67 | data >>= 16; |
||
68 | data &= 0xff; |
||
69 | break; |
||
70 | case 2: |
||
71 | if (where & 2) |
||
72 | data >>= 16; |
||
73 | data &= 0xffff; |
||
74 | break; |
||
75 | } |
||
76 | |||
77 | *val = data; |
||
78 | |||
79 | spin_unlock_irqrestore(&pci_lock, flags); |
||
80 | |||
81 | return PCIBIOS_SUCCESSFUL; |
||
82 | } |
||
83 | |||
84 | static int pci_write_config(struct pci_bus *bus, unsigned int devfn, |
||
85 | int where, int size, u32 val) |
||
86 | { |
||
87 | unsigned long flags; |
||
88 | u32 data; |
||
89 | int s; |
||
90 | |||
91 | spin_lock_irqsave(&pci_lock, flags); |
||
92 | |||
93 | write_cfgaddr(mkaddr(bus, devfn, where)); |
||
94 | data = read_cfgdata(); |
||
95 | |||
96 | switch (size) { |
||
97 | case 1: |
||
98 | s = ((where & 3) << 3); |
||
99 | data &= ~(0xff << s); |
||
100 | data |= ((val & 0xff) << s); |
||
101 | break; |
||
102 | case 2: |
||
103 | s = ((where & 2) << 4); |
||
104 | data &= ~(0xffff << s); |
||
105 | data |= ((val & 0xffff) << s); |
||
106 | break; |
||
107 | case 4: |
||
108 | data = val; |
||
109 | break; |
||
110 | } |
||
111 | |||
112 | write_cfgdata(data); |
||
113 | |||
114 | spin_unlock_irqrestore(&pci_lock, flags); |
||
115 | |||
116 | return PCIBIOS_SUCCESSFUL; |
||
117 | } |
||
118 | |||
119 | struct pci_ops adm8668_pci_ops = { |
||
120 | .read = pci_read_config, |
||
121 | .write = pci_write_config |
||
122 | }; |
||
123 | |||
124 | |||
125 | struct resource pciioport_resource = { |
||
126 | .name = "adm8668_pci", |
||
127 | .start = ADMPCI_IO_BASE, |
||
128 | .end = ADMPCI_IO_BASE + ADMPCI_IO_SIZE, |
||
129 | .flags = IORESOURCE_IO |
||
130 | }; |
||
131 | |||
132 | struct resource pciiomem_resource = { |
||
133 | .name = "adm8668_pci", |
||
134 | .start = ADMPCI_MEM_BASE, |
||
135 | .end = ADMPCI_MEM_BASE + ADMPCI_MEM_SIZE, |
||
136 | .flags = IORESOURCE_MEM |
||
137 | }; |
||
138 | |||
139 | struct pci_controller adm8668_pci_controller = { |
||
140 | .pci_ops = &adm8668_pci_ops, |
||
141 | .io_resource = &pciioport_resource, |
||
142 | .mem_resource = &pciiomem_resource, |
||
143 | }; |
||
144 | |||
145 | int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) |
||
146 | { |
||
147 | switch (slot) { |
||
148 | case 1: |
||
149 | return 14; |
||
150 | case 2: |
||
151 | return 13; |
||
152 | case 3: |
||
153 | return 12; |
||
154 | default: |
||
155 | return dev->irq; |
||
156 | } |
||
157 | } |
||
158 | |||
159 | int pcibios_plat_dev_init(struct pci_dev *dev) |
||
160 | { |
||
161 | return 0; |
||
162 | } |
||
163 | |||
164 | static void adm8668_pci_fixup(struct pci_dev *dev) |
||
165 | { |
||
166 | if (dev->devfn != 0) |
||
167 | return; |
||
168 | |||
169 | pr_info("PCI: fixing up ADM8668 controller\n"); |
||
170 | |||
171 | /* setup COMMAND register */ |
||
172 | pci_write_config_word(dev, PCI_COMMAND, |
||
173 | (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER)); |
||
174 | |||
175 | /* setup CACHE_LINE_SIZE register */ |
||
176 | pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 4); |
||
177 | |||
178 | /* setup BARS */ |
||
179 | pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0); |
||
180 | pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0); |
||
181 | } |
||
182 | DECLARE_PCI_FIXUP_HEADER(0x1317, 0x8688, adm8668_pci_fixup); |
||
183 | |||
184 | static int __init adm8668_pci_init(void) |
||
185 | { |
||
186 | void __iomem *io_map_base; |
||
187 | |||
188 | ioport_resource.start = ADMPCI_IO_BASE; |
||
189 | ioport_resource.end = ADMPCI_IO_BASE + ADMPCI_IO_SIZE; |
||
190 | |||
191 | io_map_base = ioremap(ADMPCI_IO_BASE, ADMPCI_IO_SIZE); |
||
192 | if (!io_map_base) |
||
193 | printk("io_map_base didn't work.\n"); |
||
194 | |||
195 | adm8668_pci_controller.io_map_base = (unsigned long)io_map_base; |
||
196 | register_pci_controller(&adm8668_pci_controller); |
||
197 | |||
198 | return 0; |
||
199 | } |
||
200 | arch_initcall(adm8668_pci_init); |