GNU Linux-libre 4.14.295-gnu1
[releases.git] / drivers / staging / media / atomisp / platform / intel-mid / intel_mid_pcihelpers.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/export.h>
3 #include <linux/pci.h>
4 #include <linux/pm_qos.h>
5 #include <linux/delay.h>
6
7 /* G-Min addition: "platform_is()" lives in intel_mid_pm.h in the MCG
8  * tree, but it's just platform ID info and we don't want to pull in
9  * the whole SFI-based PM architecture.
10  */
11 #define INTEL_ATOM_MRST 0x26
12 #define INTEL_ATOM_MFLD 0x27
13 #define INTEL_ATOM_CLV 0x35
14 #define INTEL_ATOM_MRFLD 0x4a
15 #define INTEL_ATOM_BYT 0x37
16 #define INTEL_ATOM_MOORFLD 0x5a
17 #define INTEL_ATOM_CHT 0x4c
18 /* synchronization for sharing the I2C controller */
19 #define PUNIT_PORT      0x04
20 #define PUNIT_DOORBELL_OPCODE   (0xE0)
21 #define PUNIT_DOORBELL_REG      (0x0)
22 #ifndef CSTATE_EXIT_LATENCY
23 #define CSTATE_EXIT_LATENCY_C1 1
24 #endif
25 static inline int platform_is(u8 model)
26 {
27         return (boot_cpu_data.x86_model == model);
28 }
29
30 #include "../../include/asm/intel_mid_pcihelpers.h"
31
32 /* Unified message bus read/write operation */
33 static DEFINE_SPINLOCK(msgbus_lock);
34
35 static struct pci_dev *pci_root;
36 static struct pm_qos_request pm_qos;
37
38 #define DW_I2C_NEED_QOS (platform_is(INTEL_ATOM_BYT))
39
40 static int intel_mid_msgbus_init(void)
41 {
42         pci_root = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0));
43         if (!pci_root) {
44                 pr_err("%s: Error: msgbus PCI handle NULL\n", __func__);
45                 return -ENODEV;
46         }
47
48         if (DW_I2C_NEED_QOS) {
49                 pm_qos_add_request(&pm_qos,
50                         PM_QOS_CPU_DMA_LATENCY,
51                         PM_QOS_DEFAULT_VALUE);
52         }
53         return 0;
54 }
55 fs_initcall(intel_mid_msgbus_init);
56
57 u32 intel_mid_msgbus_read32_raw(u32 cmd)
58 {
59         unsigned long irq_flags;
60         u32 data;
61
62         spin_lock_irqsave(&msgbus_lock, irq_flags);
63         pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd);
64         pci_read_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, &data);
65         spin_unlock_irqrestore(&msgbus_lock, irq_flags);
66
67         return data;
68 }
69 EXPORT_SYMBOL(intel_mid_msgbus_read32_raw);
70
71 /*
72  * GU: this function is only used by the VISA and 'VXD' drivers.
73  */
74 u32 intel_mid_msgbus_read32_raw_ext(u32 cmd, u32 cmd_ext)
75 {
76         unsigned long irq_flags;
77         u32 data;
78
79         spin_lock_irqsave(&msgbus_lock, irq_flags);
80         pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_EXT_REG, cmd_ext);
81         pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd);
82         pci_read_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, &data);
83         spin_unlock_irqrestore(&msgbus_lock, irq_flags);
84
85         return data;
86 }
87 EXPORT_SYMBOL(intel_mid_msgbus_read32_raw_ext);
88
89 void intel_mid_msgbus_write32_raw(u32 cmd, u32 data)
90 {
91         unsigned long irq_flags;
92
93         spin_lock_irqsave(&msgbus_lock, irq_flags);
94         pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, data);
95         pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd);
96         spin_unlock_irqrestore(&msgbus_lock, irq_flags);
97 }
98 EXPORT_SYMBOL(intel_mid_msgbus_write32_raw);
99
100 /*
101  * GU: this function is only used by the VISA and 'VXD' drivers.
102  */
103 void intel_mid_msgbus_write32_raw_ext(u32 cmd, u32 cmd_ext, u32 data)
104 {
105         unsigned long irq_flags;
106
107         spin_lock_irqsave(&msgbus_lock, irq_flags);
108         pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, data);
109         pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_EXT_REG, cmd_ext);
110         pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd);
111         spin_unlock_irqrestore(&msgbus_lock, irq_flags);
112 }
113 EXPORT_SYMBOL(intel_mid_msgbus_write32_raw_ext);
114
115 u32 intel_mid_msgbus_read32(u8 port, u32 addr)
116 {
117         unsigned long irq_flags;
118         u32 data;
119         u32 cmd;
120         u32 cmdext;
121
122         cmd = (PCI_ROOT_MSGBUS_READ << 24) | (port << 16) |
123                 ((addr & 0xff) << 8) | PCI_ROOT_MSGBUS_DWORD_ENABLE;
124         cmdext = addr & 0xffffff00;
125
126         spin_lock_irqsave(&msgbus_lock, irq_flags);
127
128         if (cmdext) {
129                 /* This resets to 0 automatically, no need to write 0 */
130                 pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_EXT_REG,
131                                         cmdext);
132         }
133
134         pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd);
135         pci_read_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, &data);
136         spin_unlock_irqrestore(&msgbus_lock, irq_flags);
137
138         return data;
139 }
140 EXPORT_SYMBOL(intel_mid_msgbus_read32);
141
142 void intel_mid_msgbus_write32(u8 port, u32 addr, u32 data)
143 {
144         unsigned long irq_flags;
145         u32 cmd;
146         u32 cmdext;
147
148         cmd = (PCI_ROOT_MSGBUS_WRITE << 24) | (port << 16) |
149                 ((addr & 0xFF) << 8) | PCI_ROOT_MSGBUS_DWORD_ENABLE;
150         cmdext = addr & 0xffffff00;
151
152         spin_lock_irqsave(&msgbus_lock, irq_flags);
153         pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, data);
154
155         if (cmdext) {
156                 /* This resets to 0 automatically, no need to write 0 */
157                 pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_EXT_REG,
158                                         cmdext);
159         }
160
161         pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd);
162         spin_unlock_irqrestore(&msgbus_lock, irq_flags);
163 }
164 EXPORT_SYMBOL(intel_mid_msgbus_write32);
165
166 /* called only from where is later then fs_initcall */
167 u32 intel_mid_soc_stepping(void)
168 {
169         return pci_root->revision;
170 }
171 EXPORT_SYMBOL(intel_mid_soc_stepping);
172
173 static bool is_south_complex_device(struct pci_dev *dev)
174 {
175         unsigned int base_class = dev->class >> 16;
176         unsigned int sub_class  = (dev->class & SUB_CLASS_MASK) >> 8;
177
178         /* other than camera, pci bridges and display,
179          * everything else are south complex devices.
180          */
181         if (((base_class == PCI_BASE_CLASS_MULTIMEDIA) &&
182              (sub_class == ISP_SUB_CLASS)) ||
183             (base_class == PCI_BASE_CLASS_BRIDGE) ||
184             ((base_class == PCI_BASE_CLASS_DISPLAY) && !sub_class))
185                 return false;
186         else
187                 return true;
188 }
189
190 /* In BYT platform, d3_delay for internal south complex devices,
191  * they are not subject to 10 ms d3 to d0 delay required by pci spec.
192  */
193 static void pci_d3_delay_fixup(struct pci_dev *dev)
194 {
195         if (platform_is(INTEL_ATOM_BYT) ||
196                 platform_is(INTEL_ATOM_CHT)) {
197                 /* All internal devices are in bus 0. */
198                 if (dev->bus->number == 0 && is_south_complex_device(dev)) {
199                         dev->d3_delay = INTERNAL_PCI_PM_D3_WAIT;
200                         dev->d3cold_delay = INTERNAL_PCI_PM_D3_WAIT;
201                 }
202         }
203 }
204 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_d3_delay_fixup);
205
206 #define PUNIT_SEMAPHORE (platform_is(INTEL_ATOM_BYT) ? 0x7 : 0x10E)
207 #define GET_SEM() (intel_mid_msgbus_read32(PUNIT_PORT, PUNIT_SEMAPHORE) & 0x1)
208
209 static void reset_semaphore(void)
210 {
211         u32 data;
212
213         data = intel_mid_msgbus_read32(PUNIT_PORT, PUNIT_SEMAPHORE);
214         smp_mb();
215         data = data & 0xfffffffc;
216         intel_mid_msgbus_write32(PUNIT_PORT, PUNIT_SEMAPHORE, data);
217         smp_mb();
218
219 }
220
221 int intel_mid_dw_i2c_acquire_ownership(void)
222 {
223         u32 ret = 0;
224         u32 data = 0; /* data sent to PUNIT */
225         u32 cmd;
226         u32 cmdext;
227         int timeout = 1000;
228
229         if (DW_I2C_NEED_QOS)
230                 pm_qos_update_request(&pm_qos, CSTATE_EXIT_LATENCY_C1 - 1);
231
232         /*
233          * We need disable irq. Otherwise, the main thread
234          * might be preempted and the other thread jumps to
235          * disable irq for a long time. Another case is
236          * some irq handlers might trigger power voltage change
237          */
238         BUG_ON(irqs_disabled());
239         local_irq_disable();
240
241         /* host driver writes 0x2 to side band register 0x7 */
242         intel_mid_msgbus_write32(PUNIT_PORT, PUNIT_SEMAPHORE, 0x2);
243         smp_mb();
244
245         /* host driver sends 0xE0 opcode to PUNIT and writes 0 register */
246         cmd = (PUNIT_DOORBELL_OPCODE << 24) | (PUNIT_PORT << 16) |
247         ((PUNIT_DOORBELL_REG & 0xFF) << 8) | PCI_ROOT_MSGBUS_DWORD_ENABLE;
248         cmdext = PUNIT_DOORBELL_REG & 0xffffff00;
249
250         if (cmdext)
251                 intel_mid_msgbus_write32_raw_ext(cmd, cmdext, data);
252         else
253                 intel_mid_msgbus_write32_raw(cmd, data);
254
255         /* host driver waits for bit 0 to be set in side band 0x7 */
256         while (GET_SEM() != 0x1) {
257                 udelay(100);
258                 timeout--;
259                 if (timeout <= 0) {
260                         pr_err("Timeout: semaphore timed out, reset sem\n");
261                         ret = -ETIMEDOUT;
262                         reset_semaphore();
263                         /*Delay 1ms in case race with punit*/
264                         udelay(1000);
265                         if (GET_SEM() != 0) {
266                                 /*Reset again as kernel might race with punit*/
267                                 reset_semaphore();
268                         }
269                         pr_err("PUNIT SEM: %d\n",
270                                         intel_mid_msgbus_read32(PUNIT_PORT,
271                                                 PUNIT_SEMAPHORE));
272                         local_irq_enable();
273
274                         if (DW_I2C_NEED_QOS) {
275                                 pm_qos_update_request(&pm_qos,
276                                          PM_QOS_DEFAULT_VALUE);
277                         }
278
279                         return ret;
280                 }
281         }
282         smp_mb();
283
284         return ret;
285 }
286 EXPORT_SYMBOL(intel_mid_dw_i2c_acquire_ownership);
287
288 int intel_mid_dw_i2c_release_ownership(void)
289 {
290         reset_semaphore();
291         local_irq_enable();
292
293         if (DW_I2C_NEED_QOS)
294                 pm_qos_update_request(&pm_qos, PM_QOS_DEFAULT_VALUE);
295
296         return 0;
297 }
298 EXPORT_SYMBOL(intel_mid_dw_i2c_release_ownership);