1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * DMA translation between STA2x11 AMBA memory mapping and the x86 memory mapping |
4 | * |
5 | * ST Microelectronics ConneXt (STA2X11/STA2X10) |
6 | * |
7 | * Copyright (c) 2010-2011 Wind River Systems, Inc. |
8 | */ |
9 | |
10 | #include <linux/pci.h> |
11 | #include <linux/pci_ids.h> |
12 | #include <linux/export.h> |
13 | #include <linux/list.h> |
14 | #include <linux/dma-map-ops.h> |
15 | #include <linux/swiotlb.h> |
16 | #include <asm/iommu.h> |
17 | #include <asm/sta2x11.h> |
18 | |
19 | #define STA2X11_SWIOTLB_SIZE (4*1024*1024) |
20 | |
21 | /* |
22 | * We build a list of bus numbers that are under the ConneXt. The |
23 | * main bridge hosts 4 busses, which are the 4 endpoints, in order. |
24 | */ |
25 | #define STA2X11_NR_EP 4 /* 0..3 included */ |
26 | #define STA2X11_NR_FUNCS 8 /* 0..7 included */ |
27 | #define STA2X11_AMBA_SIZE (512 << 20) |
28 | |
29 | struct sta2x11_ahb_regs { /* saved during suspend */ |
30 | u32 base, pexlbase, pexhbase, crw; |
31 | }; |
32 | |
33 | struct sta2x11_mapping { |
34 | int is_suspended; |
35 | struct sta2x11_ahb_regs regs[STA2X11_NR_FUNCS]; |
36 | }; |
37 | |
38 | struct sta2x11_instance { |
39 | struct list_head list; |
40 | int bus0; |
41 | struct sta2x11_mapping map[STA2X11_NR_EP]; |
42 | }; |
43 | |
44 | static LIST_HEAD(sta2x11_instance_list); |
45 | |
46 | /* At probe time, record new instances of this bridge (likely one only) */ |
47 | static void sta2x11_new_instance(struct pci_dev *pdev) |
48 | { |
49 | struct sta2x11_instance *instance; |
50 | |
51 | instance = kzalloc(size: sizeof(*instance), GFP_ATOMIC); |
52 | if (!instance) |
53 | return; |
54 | /* This has a subordinate bridge, with 4 more-subordinate ones */ |
55 | instance->bus0 = pdev->subordinate->number + 1; |
56 | |
57 | if (list_empty(head: &sta2x11_instance_list)) { |
58 | int size = STA2X11_SWIOTLB_SIZE; |
59 | /* First instance: register your own swiotlb area */ |
60 | dev_info(&pdev->dev, "Using SWIOTLB (size %i)\n" , size); |
61 | if (swiotlb_init_late(size, GFP_DMA, NULL)) |
62 | dev_emerg(&pdev->dev, "init swiotlb failed\n" ); |
63 | } |
64 | list_add(new: &instance->list, head: &sta2x11_instance_list); |
65 | } |
66 | DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, 0xcc17, sta2x11_new_instance); |
67 | |
68 | /* |
69 | * Utility functions used in this file from below |
70 | */ |
71 | static struct sta2x11_instance *sta2x11_pdev_to_instance(struct pci_dev *pdev) |
72 | { |
73 | struct sta2x11_instance *instance; |
74 | int ep; |
75 | |
76 | list_for_each_entry(instance, &sta2x11_instance_list, list) { |
77 | ep = pdev->bus->number - instance->bus0; |
78 | if (ep >= 0 && ep < STA2X11_NR_EP) |
79 | return instance; |
80 | } |
81 | return NULL; |
82 | } |
83 | |
84 | static int sta2x11_pdev_to_ep(struct pci_dev *pdev) |
85 | { |
86 | struct sta2x11_instance *instance; |
87 | |
88 | instance = sta2x11_pdev_to_instance(pdev); |
89 | if (!instance) |
90 | return -1; |
91 | |
92 | return pdev->bus->number - instance->bus0; |
93 | } |
94 | |
95 | /* This is exported, as some devices need to access the MFD registers */ |
96 | struct sta2x11_instance *sta2x11_get_instance(struct pci_dev *pdev) |
97 | { |
98 | return sta2x11_pdev_to_instance(pdev); |
99 | } |
100 | EXPORT_SYMBOL(sta2x11_get_instance); |
101 | |
102 | /* At setup time, we use our own ops if the device is a ConneXt one */ |
103 | static void sta2x11_setup_pdev(struct pci_dev *pdev) |
104 | { |
105 | struct sta2x11_instance *instance = sta2x11_pdev_to_instance(pdev); |
106 | |
107 | if (!instance) /* either a sta2x11 bridge or another ST device */ |
108 | return; |
109 | |
110 | /* We must enable all devices as master, for audio DMA to work */ |
111 | pci_set_master(dev: pdev); |
112 | } |
113 | DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_setup_pdev); |
114 | |
115 | /* |
116 | * At boot we must set up the mappings for the pcie-to-amba bridge. |
117 | * It involves device access, and the same happens at suspend/resume time |
118 | */ |
119 | |
120 | #define AHB_MAPB 0xCA4 |
121 | #define AHB_CRW(i) (AHB_MAPB + 0 + (i) * 0x10) |
122 | #define AHB_CRW_SZMASK 0xfffffc00UL |
123 | #define AHB_CRW_ENABLE (1 << 0) |
124 | #define AHB_CRW_WTYPE_MEM (2 << 1) |
125 | #define AHB_CRW_ROE (1UL << 3) /* Relax Order Ena */ |
126 | #define AHB_CRW_NSE (1UL << 4) /* No Snoop Enable */ |
127 | #define AHB_BASE(i) (AHB_MAPB + 4 + (i) * 0x10) |
128 | #define AHB_PEXLBASE(i) (AHB_MAPB + 8 + (i) * 0x10) |
129 | #define AHB_PEXHBASE(i) (AHB_MAPB + 12 + (i) * 0x10) |
130 | |
131 | /* At probe time, enable mapping for each endpoint, using the pdev */ |
132 | static void sta2x11_map_ep(struct pci_dev *pdev) |
133 | { |
134 | struct sta2x11_instance *instance = sta2x11_pdev_to_instance(pdev); |
135 | struct device *dev = &pdev->dev; |
136 | u32 amba_base, max_amba_addr; |
137 | int i, ret; |
138 | |
139 | if (!instance) |
140 | return; |
141 | |
142 | pci_read_config_dword(dev: pdev, AHB_BASE(0), val: &amba_base); |
143 | max_amba_addr = amba_base + STA2X11_AMBA_SIZE - 1; |
144 | |
145 | ret = dma_direct_set_offset(dev, cpu_start: 0, dma_start: amba_base, STA2X11_AMBA_SIZE); |
146 | if (ret) |
147 | dev_err(dev, "sta2x11: could not set DMA offset\n" ); |
148 | |
149 | dev->bus_dma_limit = max_amba_addr; |
150 | dma_set_mask_and_coherent(dev: &pdev->dev, mask: max_amba_addr); |
151 | |
152 | /* Configure AHB mapping */ |
153 | pci_write_config_dword(dev: pdev, AHB_PEXLBASE(0), val: 0); |
154 | pci_write_config_dword(dev: pdev, AHB_PEXHBASE(0), val: 0); |
155 | pci_write_config_dword(dev: pdev, AHB_CRW(0), STA2X11_AMBA_SIZE | |
156 | AHB_CRW_WTYPE_MEM | AHB_CRW_ENABLE); |
157 | |
158 | /* Disable all the other windows */ |
159 | for (i = 1; i < STA2X11_NR_FUNCS; i++) |
160 | pci_write_config_dword(dev: pdev, AHB_CRW(i), val: 0); |
161 | |
162 | dev_info(&pdev->dev, |
163 | "sta2x11: Map EP %i: AMBA address %#8x-%#8x\n" , |
164 | sta2x11_pdev_to_ep(pdev), amba_base, max_amba_addr); |
165 | } |
166 | DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_map_ep); |
167 | |
168 | #ifdef CONFIG_PM /* Some register values must be saved and restored */ |
169 | |
170 | static struct sta2x11_mapping *sta2x11_pdev_to_mapping(struct pci_dev *pdev) |
171 | { |
172 | struct sta2x11_instance *instance; |
173 | int ep; |
174 | |
175 | instance = sta2x11_pdev_to_instance(pdev); |
176 | if (!instance) |
177 | return NULL; |
178 | ep = sta2x11_pdev_to_ep(pdev); |
179 | return instance->map + ep; |
180 | } |
181 | |
182 | static void suspend_mapping(struct pci_dev *pdev) |
183 | { |
184 | struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev); |
185 | int i; |
186 | |
187 | if (!map) |
188 | return; |
189 | |
190 | if (map->is_suspended) |
191 | return; |
192 | map->is_suspended = 1; |
193 | |
194 | /* Save all window configs */ |
195 | for (i = 0; i < STA2X11_NR_FUNCS; i++) { |
196 | struct sta2x11_ahb_regs *regs = map->regs + i; |
197 | |
198 | pci_read_config_dword(dev: pdev, AHB_BASE(i), val: ®s->base); |
199 | pci_read_config_dword(dev: pdev, AHB_PEXLBASE(i), val: ®s->pexlbase); |
200 | pci_read_config_dword(dev: pdev, AHB_PEXHBASE(i), val: ®s->pexhbase); |
201 | pci_read_config_dword(dev: pdev, AHB_CRW(i), val: ®s->crw); |
202 | } |
203 | } |
204 | DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, suspend_mapping); |
205 | |
206 | static void resume_mapping(struct pci_dev *pdev) |
207 | { |
208 | struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev); |
209 | int i; |
210 | |
211 | if (!map) |
212 | return; |
213 | |
214 | |
215 | if (!map->is_suspended) |
216 | goto out; |
217 | map->is_suspended = 0; |
218 | |
219 | /* Restore all window configs */ |
220 | for (i = 0; i < STA2X11_NR_FUNCS; i++) { |
221 | struct sta2x11_ahb_regs *regs = map->regs + i; |
222 | |
223 | pci_write_config_dword(dev: pdev, AHB_BASE(i), val: regs->base); |
224 | pci_write_config_dword(dev: pdev, AHB_PEXLBASE(i), val: regs->pexlbase); |
225 | pci_write_config_dword(dev: pdev, AHB_PEXHBASE(i), val: regs->pexhbase); |
226 | pci_write_config_dword(dev: pdev, AHB_CRW(i), val: regs->crw); |
227 | } |
228 | out: |
229 | pci_set_master(dev: pdev); /* Like at boot, enable master on all devices */ |
230 | } |
231 | DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, resume_mapping); |
232 | |
233 | #endif /* CONFIG_PM */ |
234 | |