~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to arch/arm/mach-cns3xxx/pcie.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * PCI-E support for CNS3xxx
 
3
 *
 
4
 * Copyright 2008 Cavium Networks
 
5
 *                Richard Liu <richard.liu@caviumnetworks.com>
 
6
 * Copyright 2010 MontaVista Software, LLC.
 
7
 *                Anton Vorontsov <avorontsov@mvista.com>
 
8
 *
 
9
 * This file is free software; you can redistribute it and/or modify
 
10
 * it under the terms of the GNU General Public License, Version 2, as
 
11
 * published by the Free Software Foundation.
 
12
 */
 
13
 
 
14
#include <linux/init.h>
 
15
#include <linux/kernel.h>
 
16
#include <linux/bug.h>
 
17
#include <linux/pci.h>
 
18
#include <linux/io.h>
 
19
#include <linux/ioport.h>
 
20
#include <linux/interrupt.h>
 
21
#include <linux/ptrace.h>
 
22
#include <asm/mach/map.h>
 
23
#include <mach/cns3xxx.h>
 
24
#include "core.h"
 
25
 
 
26
enum cns3xxx_access_type {
 
27
        CNS3XXX_HOST_TYPE = 0,
 
28
        CNS3XXX_CFG0_TYPE,
 
29
        CNS3XXX_CFG1_TYPE,
 
30
        CNS3XXX_NUM_ACCESS_TYPES,
 
31
};
 
32
 
 
33
struct cns3xxx_pcie {
 
34
        struct map_desc cfg_bases[CNS3XXX_NUM_ACCESS_TYPES];
 
35
        unsigned int irqs[2];
 
36
        struct resource res_io;
 
37
        struct resource res_mem;
 
38
        struct hw_pci hw_pci;
 
39
 
 
40
        bool linked;
 
41
};
 
42
 
 
43
static struct cns3xxx_pcie cns3xxx_pcie[]; /* forward decl. */
 
44
 
 
45
static struct cns3xxx_pcie *sysdata_to_cnspci(void *sysdata)
 
46
{
 
47
        struct pci_sys_data *root = sysdata;
 
48
 
 
49
        return &cns3xxx_pcie[root->domain];
 
50
}
 
51
 
 
52
static struct cns3xxx_pcie *pdev_to_cnspci(const struct pci_dev *dev)
 
53
{
 
54
        return sysdata_to_cnspci(dev->sysdata);
 
55
}
 
56
 
 
57
static struct cns3xxx_pcie *pbus_to_cnspci(struct pci_bus *bus)
 
58
{
 
59
        return sysdata_to_cnspci(bus->sysdata);
 
60
}
 
61
 
 
62
static void __iomem *cns3xxx_pci_cfg_base(struct pci_bus *bus,
 
63
                                  unsigned int devfn, int where)
 
64
{
 
65
        struct cns3xxx_pcie *cnspci = pbus_to_cnspci(bus);
 
66
        int busno = bus->number;
 
67
        int slot = PCI_SLOT(devfn);
 
68
        int offset;
 
69
        enum cns3xxx_access_type type;
 
70
        void __iomem *base;
 
71
 
 
72
        /* If there is no link, just show the CNS PCI bridge. */
 
73
        if (!cnspci->linked && (busno > 0 || slot > 0))
 
74
                return NULL;
 
75
 
 
76
        /*
 
77
         * The CNS PCI bridge doesn't fit into the PCI hierarchy, though
 
78
         * we still want to access it. For this to work, we must place
 
79
         * the first device on the same bus as the CNS PCI bridge.
 
80
         */
 
81
        if (busno == 0) {
 
82
                if (slot > 1)
 
83
                        return NULL;
 
84
                type = slot;
 
85
        } else {
 
86
                type = CNS3XXX_CFG1_TYPE;
 
87
        }
 
88
 
 
89
        base = (void __iomem *)cnspci->cfg_bases[type].virtual;
 
90
        offset = ((busno & 0xf) << 20) | (devfn << 12) | (where & 0xffc);
 
91
 
 
92
        return base + offset;
 
93
}
 
94
 
 
95
static int cns3xxx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
 
96
                                   int where, int size, u32 *val)
 
97
{
 
98
        u32 v;
 
99
        void __iomem *base;
 
100
        u32 mask = (0x1ull << (size * 8)) - 1;
 
101
        int shift = (where % 4) * 8;
 
102
 
 
103
        base = cns3xxx_pci_cfg_base(bus, devfn, where);
 
104
        if (!base) {
 
105
                *val = 0xffffffff;
 
106
                return PCIBIOS_SUCCESSFUL;
 
107
        }
 
108
 
 
109
        v = __raw_readl(base);
 
110
 
 
111
        if (bus->number == 0 && devfn == 0 &&
 
112
                        (where & 0xffc) == PCI_CLASS_REVISION) {
 
113
                /*
 
114
                 * RC's class is 0xb, but Linux PCI driver needs 0x604
 
115
                 * for a PCIe bridge. So we must fixup the class code
 
116
                 * to 0x604 here.
 
117
                 */
 
118
                v &= 0xff;
 
119
                v |= 0x604 << 16;
 
120
        }
 
121
 
 
122
        *val = (v >> shift) & mask;
 
123
 
 
124
        return PCIBIOS_SUCCESSFUL;
 
125
}
 
126
 
 
127
static int cns3xxx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
 
128
                                    int where, int size, u32 val)
 
129
{
 
130
        u32 v;
 
131
        void __iomem *base;
 
132
        u32 mask = (0x1ull << (size * 8)) - 1;
 
133
        int shift = (where % 4) * 8;
 
134
 
 
135
        base = cns3xxx_pci_cfg_base(bus, devfn, where);
 
136
        if (!base)
 
137
                return PCIBIOS_SUCCESSFUL;
 
138
 
 
139
        v = __raw_readl(base);
 
140
 
 
141
        v &= ~(mask << shift);
 
142
        v |= (val & mask) << shift;
 
143
 
 
144
        __raw_writel(v, base);
 
145
 
 
146
        return PCIBIOS_SUCCESSFUL;
 
147
}
 
148
 
 
149
static int cns3xxx_pci_setup(int nr, struct pci_sys_data *sys)
 
150
{
 
151
        struct cns3xxx_pcie *cnspci = sysdata_to_cnspci(sys);
 
152
        struct resource *res_io = &cnspci->res_io;
 
153
        struct resource *res_mem = &cnspci->res_mem;
 
154
        struct resource **sysres = sys->resource;
 
155
 
 
156
        BUG_ON(request_resource(&iomem_resource, res_io) ||
 
157
               request_resource(&iomem_resource, res_mem));
 
158
 
 
159
        sysres[0] = res_io;
 
160
        sysres[1] = res_mem;
 
161
 
 
162
        return 1;
 
163
}
 
164
 
 
165
static struct pci_ops cns3xxx_pcie_ops = {
 
166
        .read = cns3xxx_pci_read_config,
 
167
        .write = cns3xxx_pci_write_config,
 
168
};
 
169
 
 
170
static struct pci_bus *cns3xxx_pci_scan_bus(int nr, struct pci_sys_data *sys)
 
171
{
 
172
        return pci_scan_bus(sys->busnr, &cns3xxx_pcie_ops, sys);
 
173
}
 
174
 
 
175
static int cns3xxx_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 
176
{
 
177
        struct cns3xxx_pcie *cnspci = pdev_to_cnspci(dev);
 
178
        int irq = cnspci->irqs[slot];
 
179
 
 
180
        pr_info("PCIe map irq: %04d:%02x:%02x.%02x slot %d, pin %d, irq: %d\n",
 
181
                pci_domain_nr(dev->bus), dev->bus->number, PCI_SLOT(dev->devfn),
 
182
                PCI_FUNC(dev->devfn), slot, pin, irq);
 
183
 
 
184
        return irq;
 
185
}
 
186
 
 
187
static struct cns3xxx_pcie cns3xxx_pcie[] = {
 
188
        [0] = {
 
189
                .cfg_bases = {
 
190
                        [CNS3XXX_HOST_TYPE] = {
 
191
                                .virtual = CNS3XXX_PCIE0_HOST_BASE_VIRT,
 
192
                                .pfn = __phys_to_pfn(CNS3XXX_PCIE0_HOST_BASE),
 
193
                                .length = SZ_16M,
 
194
                                .type = MT_DEVICE,
 
195
                        },
 
196
                        [CNS3XXX_CFG0_TYPE] = {
 
197
                                .virtual = CNS3XXX_PCIE0_CFG0_BASE_VIRT,
 
198
                                .pfn = __phys_to_pfn(CNS3XXX_PCIE0_CFG0_BASE),
 
199
                                .length = SZ_16M,
 
200
                                .type = MT_DEVICE,
 
201
                        },
 
202
                        [CNS3XXX_CFG1_TYPE] = {
 
203
                                .virtual = CNS3XXX_PCIE0_CFG1_BASE_VIRT,
 
204
                                .pfn = __phys_to_pfn(CNS3XXX_PCIE0_CFG1_BASE),
 
205
                                .length = SZ_16M,
 
206
                                .type = MT_DEVICE,
 
207
                        },
 
208
                },
 
209
                .res_io = {
 
210
                        .name = "PCIe0 I/O space",
 
211
                        .start = CNS3XXX_PCIE0_IO_BASE,
 
212
                        .end = CNS3XXX_PCIE0_IO_BASE + SZ_16M - 1,
 
213
                        .flags = IORESOURCE_IO,
 
214
                },
 
215
                .res_mem = {
 
216
                        .name = "PCIe0 non-prefetchable",
 
217
                        .start = CNS3XXX_PCIE0_MEM_BASE,
 
218
                        .end = CNS3XXX_PCIE0_MEM_BASE + SZ_16M - 1,
 
219
                        .flags = IORESOURCE_MEM,
 
220
                },
 
221
                .irqs = { IRQ_CNS3XXX_PCIE0_RC, IRQ_CNS3XXX_PCIE0_DEVICE, },
 
222
                .hw_pci = {
 
223
                        .domain = 0,
 
224
                        .swizzle = pci_std_swizzle,
 
225
                        .nr_controllers = 1,
 
226
                        .setup = cns3xxx_pci_setup,
 
227
                        .scan = cns3xxx_pci_scan_bus,
 
228
                        .map_irq = cns3xxx_pcie_map_irq,
 
229
                },
 
230
        },
 
231
        [1] = {
 
232
                .cfg_bases = {
 
233
                        [CNS3XXX_HOST_TYPE] = {
 
234
                                .virtual = CNS3XXX_PCIE1_HOST_BASE_VIRT,
 
235
                                .pfn = __phys_to_pfn(CNS3XXX_PCIE1_HOST_BASE),
 
236
                                .length = SZ_16M,
 
237
                                .type = MT_DEVICE,
 
238
                        },
 
239
                        [CNS3XXX_CFG0_TYPE] = {
 
240
                                .virtual = CNS3XXX_PCIE1_CFG0_BASE_VIRT,
 
241
                                .pfn = __phys_to_pfn(CNS3XXX_PCIE1_CFG0_BASE),
 
242
                                .length = SZ_16M,
 
243
                                .type = MT_DEVICE,
 
244
                        },
 
245
                        [CNS3XXX_CFG1_TYPE] = {
 
246
                                .virtual = CNS3XXX_PCIE1_CFG1_BASE_VIRT,
 
247
                                .pfn = __phys_to_pfn(CNS3XXX_PCIE1_CFG1_BASE),
 
248
                                .length = SZ_16M,
 
249
                                .type = MT_DEVICE,
 
250
                        },
 
251
                },
 
252
                .res_io = {
 
253
                        .name = "PCIe1 I/O space",
 
254
                        .start = CNS3XXX_PCIE1_IO_BASE,
 
255
                        .end = CNS3XXX_PCIE1_IO_BASE + SZ_16M - 1,
 
256
                        .flags = IORESOURCE_IO,
 
257
                },
 
258
                .res_mem = {
 
259
                        .name = "PCIe1 non-prefetchable",
 
260
                        .start = CNS3XXX_PCIE1_MEM_BASE,
 
261
                        .end = CNS3XXX_PCIE1_MEM_BASE + SZ_16M - 1,
 
262
                        .flags = IORESOURCE_MEM,
 
263
                },
 
264
                .irqs = { IRQ_CNS3XXX_PCIE1_RC, IRQ_CNS3XXX_PCIE1_DEVICE, },
 
265
                .hw_pci = {
 
266
                        .domain = 1,
 
267
                        .swizzle = pci_std_swizzle,
 
268
                        .nr_controllers = 1,
 
269
                        .setup = cns3xxx_pci_setup,
 
270
                        .scan = cns3xxx_pci_scan_bus,
 
271
                        .map_irq = cns3xxx_pcie_map_irq,
 
272
                },
 
273
        },
 
274
};
 
275
 
 
276
static void __init cns3xxx_pcie_check_link(struct cns3xxx_pcie *cnspci)
 
277
{
 
278
        int port = cnspci->hw_pci.domain;
 
279
        u32 reg;
 
280
        unsigned long time;
 
281
 
 
282
        reg = __raw_readl(MISC_PCIE_CTRL(port));
 
283
        /*
 
284
         * Enable Application Request to 1, it will exit L1 automatically,
 
285
         * but when chip back, it will use another clock, still can use 0x1.
 
286
         */
 
287
        reg |= 0x3;
 
288
        __raw_writel(reg, MISC_PCIE_CTRL(port));
 
289
 
 
290
        pr_info("PCIe: Port[%d] Enable PCIe LTSSM\n", port);
 
291
        pr_info("PCIe: Port[%d] Check data link layer...", port);
 
292
 
 
293
        time = jiffies;
 
294
        while (1) {
 
295
                reg = __raw_readl(MISC_PCIE_PM_DEBUG(port));
 
296
                if (reg & 0x1) {
 
297
                        pr_info("Link up.\n");
 
298
                        cnspci->linked = 1;
 
299
                        break;
 
300
                } else if (time_after(jiffies, time + 50)) {
 
301
                        pr_info("Device not found.\n");
 
302
                        break;
 
303
                }
 
304
        }
 
305
}
 
306
 
 
307
static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci)
 
308
{
 
309
        int port = cnspci->hw_pci.domain;
 
310
        struct pci_sys_data sd = {
 
311
                .domain = port,
 
312
        };
 
313
        struct pci_bus bus = {
 
314
                .number = 0,
 
315
                .ops = &cns3xxx_pcie_ops,
 
316
                .sysdata = &sd,
 
317
        };
 
318
        u32 io_base = cnspci->res_io.start >> 16;
 
319
        u32 mem_base = cnspci->res_mem.start >> 16;
 
320
        u32 host_base = cnspci->cfg_bases[CNS3XXX_HOST_TYPE].pfn;
 
321
        u32 cfg0_base = cnspci->cfg_bases[CNS3XXX_CFG0_TYPE].pfn;
 
322
        u32 devfn = 0;
 
323
        u8 tmp8;
 
324
        u16 pos;
 
325
        u16 dc;
 
326
 
 
327
        host_base = (__pfn_to_phys(host_base) - 1) >> 16;
 
328
        cfg0_base = (__pfn_to_phys(cfg0_base) - 1) >> 16;
 
329
 
 
330
        pci_bus_write_config_byte(&bus, devfn, PCI_PRIMARY_BUS, 0);
 
331
        pci_bus_write_config_byte(&bus, devfn, PCI_SECONDARY_BUS, 1);
 
332
        pci_bus_write_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, 1);
 
333
 
 
334
        pci_bus_read_config_byte(&bus, devfn, PCI_PRIMARY_BUS, &tmp8);
 
335
        pci_bus_read_config_byte(&bus, devfn, PCI_SECONDARY_BUS, &tmp8);
 
336
        pci_bus_read_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, &tmp8);
 
337
 
 
338
        pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_BASE, mem_base);
 
339
        pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_LIMIT, host_base);
 
340
        pci_bus_write_config_word(&bus, devfn, PCI_IO_BASE_UPPER16, io_base);
 
341
        pci_bus_write_config_word(&bus, devfn, PCI_IO_LIMIT_UPPER16, cfg0_base);
 
342
 
 
343
        if (!cnspci->linked)
 
344
                return;
 
345
 
 
346
        /* Set Device Max_Read_Request_Size to 128 byte */
 
347
        devfn = PCI_DEVFN(1, 0);
 
348
        pos = pci_bus_find_capability(&bus, devfn, PCI_CAP_ID_EXP);
 
349
        pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, &dc);
 
350
        dc &= ~(0x3 << 12);     /* Clear Device Control Register [14:12] */
 
351
        pci_bus_write_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, dc);
 
352
        pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, &dc);
 
353
        if (!(dc & (0x3 << 12)))
 
354
                pr_info("PCIe: Set Device Max_Read_Request_Size to 128 byte\n");
 
355
 
 
356
        /* Disable PCIe0 Interrupt Mask INTA to INTD */
 
357
        __raw_writel(~0x3FFF, MISC_PCIE_INT_MASK(port));
 
358
}
 
359
 
 
360
static int cns3xxx_pcie_abort_handler(unsigned long addr, unsigned int fsr,
 
361
                                      struct pt_regs *regs)
 
362
{
 
363
        if (fsr & (1 << 10))
 
364
                regs->ARM_pc += 4;
 
365
        return 0;
 
366
}
 
367
 
 
368
static int __init cns3xxx_pcie_init(void)
 
369
{
 
370
        int i;
 
371
 
 
372
        pcibios_min_io = 0;
 
373
        pcibios_min_mem = 0;
 
374
 
 
375
        hook_fault_code(16 + 6, cns3xxx_pcie_abort_handler, SIGBUS, 0,
 
376
                        "imprecise external abort");
 
377
 
 
378
        for (i = 0; i < ARRAY_SIZE(cns3xxx_pcie); i++) {
 
379
                iotable_init(cns3xxx_pcie[i].cfg_bases,
 
380
                             ARRAY_SIZE(cns3xxx_pcie[i].cfg_bases));
 
381
                cns3xxx_pwr_clk_en(0x1 << PM_CLK_GATE_REG_OFFSET_PCIE(i));
 
382
                cns3xxx_pwr_soft_rst(0x1 << PM_SOFT_RST_REG_OFFST_PCIE(i));
 
383
                cns3xxx_pcie_check_link(&cns3xxx_pcie[i]);
 
384
                cns3xxx_pcie_hw_init(&cns3xxx_pcie[i]);
 
385
                pci_common_init(&cns3xxx_pcie[i].hw_pci);
 
386
        }
 
387
 
 
388
        pci_assign_unassigned_resources();
 
389
 
 
390
        return 0;
 
391
}
 
392
device_initcall(cns3xxx_pcie_init);