79a5ddae733dbf718c195c6bd85b60d5c8ff7b94
[platform/kernel/linux-arm64.git] / arch / sh / drivers / pci / ops-sh7786.c
1 /*
2  * Generic SH7786 PCI-Express operations.
3  *
4  *  Copyright (C) 2009 - 2010  Paul Mundt
5  *
6  * This file is subject to the terms and conditions of the GNU General Public
7  * License v2. See the file "COPYING" in the main directory of this archive
8  * for more details.
9  */
10 #include <linux/kernel.h>
11 #include <linux/init.h>
12 #include <linux/pci.h>
13 #include <linux/io.h>
14 #include <linux/spinlock.h>
15 #include "pcie-sh7786.h"
16
17 enum {
18         PCI_ACCESS_READ,
19         PCI_ACCESS_WRITE,
20 };
21
22 static DEFINE_SPINLOCK(sh7786_pcie_lock);
23
24 static int sh7786_pcie_config_access(unsigned char access_type,
25                 struct pci_bus *bus, unsigned int devfn, int where, u32 *data)
26 {
27         struct pci_channel *chan = bus->sysdata;
28         int dev, func, type;
29
30         dev = PCI_SLOT(devfn);
31         func = PCI_FUNC(devfn);
32         type = !!bus->parent;
33
34         if (bus->number > 255 || dev > 31 || func > 7)
35                 return PCIBIOS_FUNC_NOT_SUPPORTED;
36         if (bus->parent == NULL && dev)
37                 return PCIBIOS_DEVICE_NOT_FOUND;
38
39         /* Clear errors */
40         pci_write_reg(chan, pci_read_reg(chan, SH4A_PCIEERRFR), SH4A_PCIEERRFR);
41
42         /* Set the PIO address */
43         pci_write_reg(chan, (bus->number << 24) | (dev << 19) |
44                                 (func << 16) | (where & ~3), SH4A_PCIEPAR);
45
46         /* Enable the configuration access */
47         pci_write_reg(chan, (1 << 31) | (type << 8), SH4A_PCIEPCTLR);
48
49         /* Check for errors */
50         if (pci_read_reg(chan, SH4A_PCIEERRFR) & 0x10)
51                 return PCIBIOS_DEVICE_NOT_FOUND;
52         /* Check for master and target aborts */
53         if (pci_read_reg(chan, SH4A_PCIEPCICONF1) & ((1 << 29) | (1 << 28)))
54                 return PCIBIOS_DEVICE_NOT_FOUND;
55
56         if (access_type == PCI_ACCESS_READ)
57                 *data = pci_read_reg(chan, SH4A_PCIEPDR);
58         else
59                 pci_write_reg(chan, *data, SH4A_PCIEPDR);
60
61         return PCIBIOS_SUCCESSFUL;
62 }
63
64 static int sh7786_pcie_read(struct pci_bus *bus, unsigned int devfn,
65                             int where, int size, u32 *val)
66 {
67         unsigned long flags;
68         int ret;
69         u32 data;
70
71         if ((size == 2) && (where & 1))
72                 return PCIBIOS_BAD_REGISTER_NUMBER;
73         else if ((size == 4) && (where & 3))
74                 return PCIBIOS_BAD_REGISTER_NUMBER;
75
76         spin_lock_irqsave(&sh7786_pcie_lock, flags);
77         ret = sh7786_pcie_config_access(PCI_ACCESS_READ, bus,
78                                         devfn, where, &data);
79         if (ret != PCIBIOS_SUCCESSFUL) {
80                 *val = 0xffffffff;
81                 goto out;
82         }
83
84         if (size == 1)
85                 *val = (data >> ((where & 3) << 3)) & 0xff;
86         else if (size == 2)
87                 *val = (data >> ((where & 2) << 3)) & 0xffff;
88         else
89                 *val = data;
90
91         dev_dbg(&bus->dev, "pcie-config-read: bus=%3d devfn=0x%04x "
92                 "where=0x%04x size=%d val=0x%08lx\n", bus->number,
93                 devfn, where, size, (unsigned long)*val);
94
95 out:
96         spin_unlock_irqrestore(&sh7786_pcie_lock, flags);
97         return ret;
98 }
99
100 static int sh7786_pcie_write(struct pci_bus *bus, unsigned int devfn,
101                              int where, int size, u32 val)
102 {
103         unsigned long flags;
104         int shift, ret;
105         u32 data;
106
107         if ((size == 2) && (where & 1))
108                 return PCIBIOS_BAD_REGISTER_NUMBER;
109         else if ((size == 4) && (where & 3))
110                 return PCIBIOS_BAD_REGISTER_NUMBER;
111
112         spin_lock_irqsave(&sh7786_pcie_lock, flags);
113         ret = sh7786_pcie_config_access(PCI_ACCESS_READ, bus,
114                                         devfn, where, &data);
115         if (ret != PCIBIOS_SUCCESSFUL)
116                 goto out;
117
118         dev_dbg(&bus->dev, "pcie-config-write: bus=%3d devfn=0x%04x "
119                 "where=0x%04x size=%d val=%08lx\n", bus->number,
120                 devfn, where, size, (unsigned long)val);
121
122         if (size == 1) {
123                 shift = (where & 3) << 3;
124                 data &= ~(0xff << shift);
125                 data |= ((val & 0xff) << shift);
126         } else if (size == 2) {
127                 shift = (where & 2) << 3;
128                 data &= ~(0xffff << shift);
129                 data |= ((val & 0xffff) << shift);
130         } else
131                 data = val;
132
133         ret = sh7786_pcie_config_access(PCI_ACCESS_WRITE, bus,
134                                         devfn, where, &data);
135 out:
136         spin_unlock_irqrestore(&sh7786_pcie_lock, flags);
137         return ret;
138 }
139
140 struct pci_ops sh7786_pci_ops = {
141         .read   = sh7786_pcie_read,
142         .write  = sh7786_pcie_write,
143 };