Root/target/linux/adm8668/files/arch/mips/pci/pci-adm8668.c

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
22static 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
30static inline void write_cfgaddr(u32 addr)
31{
32    __raw_writel((addr | PCI_ENABLE),
33            (void __iomem *)KSEG1ADDR(ADM8668_PCICFG_BASE));
34}
35
36static inline void write_cfgdata(u32 data)
37{
38    __raw_writel(data, (void __iomem *)KSEG1ADDR(ADM8668_PCIDAT_BASE));
39}
40
41static inline u32 read_cfgdata(void)
42{
43    return __raw_readl((void __iomem *)KSEG1ADDR(ADM8668_PCIDAT_BASE));
44}
45
46static 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
52static 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
84static 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
119struct pci_ops adm8668_pci_ops = {
120    .read = pci_read_config,
121    .write = pci_write_config
122};
123
124
125struct 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
132struct 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
139struct pci_controller adm8668_pci_controller = {
140    .pci_ops = &adm8668_pci_ops,
141    .io_resource = &pciioport_resource,
142    .mem_resource = &pciiomem_resource,
143};
144
145int 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
159int pcibios_plat_dev_init(struct pci_dev *dev)
160{
161    return 0;
162}
163
164static 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}
182DECLARE_PCI_FIXUP_HEADER(0x1317, 0x8688, adm8668_pci_fixup);
183
184static 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}
200arch_initcall(adm8668_pci_init);
201

Archive Download this file



interactive