]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
baf37f06 PB |
2 | /* |
3 | * Copyright (C) 2013 Imagination Technologies | |
c5bf161f | 4 | * Author: Paul Burton <[email protected]> |
baf37f06 PB |
5 | */ |
6 | ||
8bee3a38 | 7 | #include <dm.h> |
691d719d | 8 | #include <init.h> |
baf37f06 PB |
9 | #include <msc01.h> |
10 | #include <pci.h> | |
11 | #include <pci_msc01.h> | |
12 | #include <asm/io.h> | |
13 | ||
14 | #define PCI_ACCESS_READ 0 | |
15 | #define PCI_ACCESS_WRITE 1 | |
16 | ||
17 | struct msc01_pci_controller { | |
18 | struct pci_controller hose; | |
19 | void *base; | |
20 | }; | |
21 | ||
22 | static inline struct msc01_pci_controller * | |
23 | hose_to_msc01(struct pci_controller *hose) | |
24 | { | |
25 | return container_of(hose, struct msc01_pci_controller, hose); | |
26 | } | |
27 | ||
28 | static int msc01_config_access(struct msc01_pci_controller *msc01, | |
29 | unsigned char access_type, pci_dev_t bdf, | |
30 | int where, u32 *data) | |
31 | { | |
32 | const u32 aborts = MSC01_PCI_INTSTAT_MA_MSK | MSC01_PCI_INTSTAT_TA_MSK; | |
33 | void *intstat = msc01->base + MSC01_PCI_INTSTAT_OFS; | |
34 | void *cfgdata = msc01->base + MSC01_PCI_CFGDATA_OFS; | |
35 | unsigned int bus = PCI_BUS(bdf); | |
36 | unsigned int dev = PCI_DEV(bdf); | |
37 | unsigned int devfn = PCI_DEV(bdf) << 3 | PCI_FUNC(bdf); | |
38 | ||
39 | /* clear abort status */ | |
40 | __raw_writel(aborts, intstat); | |
41 | ||
42 | /* setup address */ | |
43 | __raw_writel((bus << MSC01_PCI_CFGADDR_BNUM_SHF) | | |
44 | (dev << MSC01_PCI_CFGADDR_DNUM_SHF) | | |
45 | (devfn << MSC01_PCI_CFGADDR_FNUM_SHF) | | |
46 | ((where / 4) << MSC01_PCI_CFGADDR_RNUM_SHF), | |
47 | msc01->base + MSC01_PCI_CFGADDR_OFS); | |
48 | ||
49 | /* perform access */ | |
50 | if (access_type == PCI_ACCESS_WRITE) | |
51 | __raw_writel(*data, cfgdata); | |
52 | else | |
53 | *data = __raw_readl(cfgdata); | |
54 | ||
55 | /* check for aborts */ | |
56 | if (__raw_readl(intstat) & aborts) { | |
57 | /* clear abort status */ | |
58 | __raw_writel(aborts, intstat); | |
59 | return -1; | |
60 | } | |
61 | ||
62 | return 0; | |
63 | } | |
64 | ||
8bee3a38 DS |
65 | static int msc01_pci_read_config(const struct udevice *dev, pci_dev_t bdf, |
66 | uint where, ulong *val, enum pci_size_t size) | |
67 | { | |
68 | struct msc01_pci_controller *msc01 = dev_get_priv(dev); | |
69 | u32 data = 0; | |
70 | ||
71 | if (msc01_config_access(msc01, PCI_ACCESS_READ, bdf, where, &data)) { | |
72 | *val = pci_get_ff(size); | |
73 | return 0; | |
74 | } | |
75 | ||
76 | *val = pci_conv_32_to_size(data, where, size); | |
77 | ||
78 | return 0; | |
79 | } | |
80 | ||
81 | static int msc01_pci_write_config(struct udevice *dev, pci_dev_t bdf, | |
82 | uint where, ulong val, enum pci_size_t size) | |
83 | { | |
84 | struct msc01_pci_controller *msc01 = dev_get_priv(dev); | |
85 | u32 data = 0; | |
86 | ||
87 | if (size == PCI_SIZE_32) { | |
88 | data = val; | |
89 | } else { | |
90 | u32 old; | |
91 | ||
92 | if (msc01_config_access(msc01, PCI_ACCESS_READ, bdf, where, &old)) | |
93 | return 0; | |
94 | ||
95 | data = pci_conv_size_to_32(old, val, where, size); | |
96 | } | |
97 | ||
98 | msc01_config_access(msc01, PCI_ACCESS_WRITE, bdf, where, &data); | |
99 | ||
100 | return 0; | |
101 | } | |
102 | ||
103 | static int msc01_pci_probe(struct udevice *dev) | |
104 | { | |
105 | struct msc01_pci_controller *msc01 = dev_get_priv(dev); | |
106 | ||
107 | msc01->base = dev_remap_addr(dev); | |
108 | if (!msc01->base) | |
109 | return -EINVAL; | |
110 | ||
111 | return 0; | |
112 | } | |
113 | ||
114 | static const struct dm_pci_ops msc01_pci_ops = { | |
115 | .read_config = msc01_pci_read_config, | |
116 | .write_config = msc01_pci_write_config, | |
117 | }; | |
118 | ||
119 | static const struct udevice_id msc01_pci_ids[] = { | |
120 | { .compatible = "mips,pci-msc01" }, | |
121 | { } | |
122 | }; | |
123 | ||
124 | U_BOOT_DRIVER(msc01_pci) = { | |
125 | .name = "msc01_pci", | |
126 | .id = UCLASS_PCI, | |
127 | .of_match = msc01_pci_ids, | |
128 | .ops = &msc01_pci_ops, | |
129 | .probe = msc01_pci_probe, | |
130 | .priv_auto = sizeof(struct msc01_pci_controller), | |
131 | }; |