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