Commit 05454c26eb3587b56abc5eb139797ac5afb6d77a
Committed by
H. Peter Anvin
1 parent
d8059302b3
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
intel_mid: Renamed *mrst* to *intel_mid*
Following files contains code that is common to all intel mid soc's. So renamed them as below. mrst/mrst.c -> intel-mid/intel-mid.c mrst/vrtc.c -> intel-mid/intel_mid_vrtc.c mrst/early_printk_mrst.c -> intel-mid/intel_mid_vrtc.c pci/mrst.c -> pci/intel_mid_pci.c Also, renamed the corresponding header files and made changes to the driver files that included these header files. To ensure that there are no functional changes, I have compared the objdump of renamed files before and after rename and found that the only difference is file name change. Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com> Link: http://lkml.kernel.org/r/1382049336-21316-4-git-send-email-david.a.cohen@linux.intel.com Signed-off-by: David Cohen <david.a.cohen@linux.intel.com> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Showing 25 changed files with 1972 additions and 1971 deletions Side-by-side Diff
- arch/x86/include/asm/intel-mid.h
- arch/x86/include/asm/intel_mid_vrtc.h
- arch/x86/include/asm/mrst-vrtc.h
- arch/x86/include/asm/mrst.h
- arch/x86/kernel/apb_timer.c
- arch/x86/kernel/early_printk.c
- arch/x86/kernel/rtc.c
- arch/x86/pci/Makefile
- arch/x86/pci/intel_mid_pci.c
- arch/x86/pci/mrst.c
- arch/x86/platform/Makefile
- arch/x86/platform/intel-mid/Makefile
- arch/x86/platform/intel-mid/early_printk_intel_mid.c
- arch/x86/platform/intel-mid/intel-mid.c
- arch/x86/platform/intel-mid/intel_mid_vrtc.c
- arch/x86/platform/mrst/Makefile
- arch/x86/platform/mrst/early_printk_mrst.c
- arch/x86/platform/mrst/mrst.c
- arch/x86/platform/mrst/vrtc.c
- drivers/gpu/drm/gma500/mdfld_dsi_output.h
- drivers/gpu/drm/gma500/oaktrail_device.c
- drivers/gpu/drm/gma500/oaktrail_lvds.c
- drivers/platform/x86/intel_scu_ipc.c
- drivers/rtc/rtc-mrst.c
- drivers/watchdog/intel_scu_watchdog.c
arch/x86/include/asm/intel-mid.h
1 | +/* | |
2 | + * intel-mid.h: Intel MID specific setup code | |
3 | + * | |
4 | + * (C) Copyright 2009 Intel Corporation | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or | |
7 | + * modify it under the terms of the GNU General Public License | |
8 | + * as published by the Free Software Foundation; version 2 | |
9 | + * of the License. | |
10 | + */ | |
11 | +#ifndef _ASM_X86_INTEL_MID_H | |
12 | +#define _ASM_X86_INTEL_MID_H | |
13 | + | |
14 | +#include <linux/sfi.h> | |
15 | + | |
16 | +extern int pci_mrst_init(void); | |
17 | +extern int __init sfi_parse_mrtc(struct sfi_table_header *table); | |
18 | +extern int sfi_mrtc_num; | |
19 | +extern struct sfi_rtc_table_entry sfi_mrtc_array[]; | |
20 | + | |
21 | +/* | |
22 | + * Medfield is the follow-up of Moorestown, it combines two chip solution into | |
23 | + * one. Other than that it also added always-on and constant tsc and lapic | |
24 | + * timers. Medfield is the platform name, and the chip name is called Penwell | |
25 | + * we treat Medfield/Penwell as a variant of Moorestown. Penwell can be | |
26 | + * identified via MSRs. | |
27 | + */ | |
28 | +enum mrst_cpu_type { | |
29 | + /* 1 was Moorestown */ | |
30 | + MRST_CPU_CHIP_PENWELL = 2, | |
31 | +}; | |
32 | + | |
33 | +extern enum mrst_cpu_type __mrst_cpu_chip; | |
34 | + | |
35 | +#ifdef CONFIG_X86_INTEL_MID | |
36 | + | |
37 | +static inline enum mrst_cpu_type mrst_identify_cpu(void) | |
38 | +{ | |
39 | + return __mrst_cpu_chip; | |
40 | +} | |
41 | + | |
42 | +#else /* !CONFIG_X86_INTEL_MID */ | |
43 | + | |
44 | +#define mrst_identify_cpu() (0) | |
45 | + | |
46 | +#endif /* !CONFIG_X86_INTEL_MID */ | |
47 | + | |
48 | +enum mrst_timer_options { | |
49 | + MRST_TIMER_DEFAULT, | |
50 | + MRST_TIMER_APBT_ONLY, | |
51 | + MRST_TIMER_LAPIC_APBT, | |
52 | +}; | |
53 | + | |
54 | +extern enum mrst_timer_options mrst_timer_options; | |
55 | + | |
56 | +/* | |
57 | + * Penwell uses spread spectrum clock, so the freq number is not exactly | |
58 | + * the same as reported by MSR based on SDM. | |
59 | + */ | |
60 | +#define PENWELL_FSB_FREQ_83SKU 83200 | |
61 | +#define PENWELL_FSB_FREQ_100SKU 99840 | |
62 | + | |
63 | +#define SFI_MTMR_MAX_NUM 8 | |
64 | +#define SFI_MRTC_MAX 8 | |
65 | + | |
66 | +extern struct console early_mrst_console; | |
67 | +extern void mrst_early_console_init(void); | |
68 | + | |
69 | +extern struct console early_hsu_console; | |
70 | +extern void hsu_early_console_init(const char *); | |
71 | + | |
72 | +extern void intel_scu_devices_create(void); | |
73 | +extern void intel_scu_devices_destroy(void); | |
74 | + | |
75 | +/* VRTC timer */ | |
76 | +#define MRST_VRTC_MAP_SZ (1024) | |
77 | +/*#define MRST_VRTC_PGOFFSET (0xc00) */ | |
78 | + | |
79 | +extern void mrst_rtc_init(void); | |
80 | + | |
81 | +#endif /* _ASM_X86_INTEL_MID_H */ |
arch/x86/include/asm/intel_mid_vrtc.h
1 | +#ifndef _INTEL_MID_VRTC_H | |
2 | +#define _INTEL_MID_VRTC_H | |
3 | + | |
4 | +extern unsigned char vrtc_cmos_read(unsigned char reg); | |
5 | +extern void vrtc_cmos_write(unsigned char val, unsigned char reg); | |
6 | +extern void vrtc_get_time(struct timespec *now); | |
7 | +extern int vrtc_set_mmss(const struct timespec *now); | |
8 | + | |
9 | +#endif |
arch/x86/include/asm/mrst-vrtc.h
1 | -#ifndef _MRST_VRTC_H | |
2 | -#define _MRST_VRTC_H | |
3 | - | |
4 | -extern unsigned char vrtc_cmos_read(unsigned char reg); | |
5 | -extern void vrtc_cmos_write(unsigned char val, unsigned char reg); | |
6 | -extern void vrtc_get_time(struct timespec *now); | |
7 | -extern int vrtc_set_mmss(const struct timespec *now); | |
8 | - | |
9 | -#endif |
arch/x86/include/asm/mrst.h
1 | -/* | |
2 | - * mrst.h: Intel Moorestown platform specific setup code | |
3 | - * | |
4 | - * (C) Copyright 2009 Intel Corporation | |
5 | - * | |
6 | - * This program is free software; you can redistribute it and/or | |
7 | - * modify it under the terms of the GNU General Public License | |
8 | - * as published by the Free Software Foundation; version 2 | |
9 | - * of the License. | |
10 | - */ | |
11 | -#ifndef _ASM_X86_MRST_H | |
12 | -#define _ASM_X86_MRST_H | |
13 | - | |
14 | -#include <linux/sfi.h> | |
15 | - | |
16 | -extern int pci_mrst_init(void); | |
17 | -extern int __init sfi_parse_mrtc(struct sfi_table_header *table); | |
18 | -extern int sfi_mrtc_num; | |
19 | -extern struct sfi_rtc_table_entry sfi_mrtc_array[]; | |
20 | - | |
21 | -/* | |
22 | - * Medfield is the follow-up of Moorestown, it combines two chip solution into | |
23 | - * one. Other than that it also added always-on and constant tsc and lapic | |
24 | - * timers. Medfield is the platform name, and the chip name is called Penwell | |
25 | - * we treat Medfield/Penwell as a variant of Moorestown. Penwell can be | |
26 | - * identified via MSRs. | |
27 | - */ | |
28 | -enum mrst_cpu_type { | |
29 | - /* 1 was Moorestown */ | |
30 | - MRST_CPU_CHIP_PENWELL = 2, | |
31 | -}; | |
32 | - | |
33 | -extern enum mrst_cpu_type __mrst_cpu_chip; | |
34 | - | |
35 | -#ifdef CONFIG_X86_INTEL_MID | |
36 | - | |
37 | -static inline enum mrst_cpu_type mrst_identify_cpu(void) | |
38 | -{ | |
39 | - return __mrst_cpu_chip; | |
40 | -} | |
41 | - | |
42 | -#else /* !CONFIG_X86_INTEL_MID */ | |
43 | - | |
44 | -#define mrst_identify_cpu() (0) | |
45 | - | |
46 | -#endif /* !CONFIG_X86_INTEL_MID */ | |
47 | - | |
48 | -enum mrst_timer_options { | |
49 | - MRST_TIMER_DEFAULT, | |
50 | - MRST_TIMER_APBT_ONLY, | |
51 | - MRST_TIMER_LAPIC_APBT, | |
52 | -}; | |
53 | - | |
54 | -extern enum mrst_timer_options mrst_timer_options; | |
55 | - | |
56 | -/* | |
57 | - * Penwell uses spread spectrum clock, so the freq number is not exactly | |
58 | - * the same as reported by MSR based on SDM. | |
59 | - */ | |
60 | -#define PENWELL_FSB_FREQ_83SKU 83200 | |
61 | -#define PENWELL_FSB_FREQ_100SKU 99840 | |
62 | - | |
63 | -#define SFI_MTMR_MAX_NUM 8 | |
64 | -#define SFI_MRTC_MAX 8 | |
65 | - | |
66 | -extern struct console early_mrst_console; | |
67 | -extern void mrst_early_console_init(void); | |
68 | - | |
69 | -extern struct console early_hsu_console; | |
70 | -extern void hsu_early_console_init(const char *); | |
71 | - | |
72 | -extern void intel_scu_devices_create(void); | |
73 | -extern void intel_scu_devices_destroy(void); | |
74 | - | |
75 | -/* VRTC timer */ | |
76 | -#define MRST_VRTC_MAP_SZ (1024) | |
77 | -/*#define MRST_VRTC_PGOFFSET (0xc00) */ | |
78 | - | |
79 | -extern void mrst_rtc_init(void); | |
80 | - | |
81 | -#endif /* _ASM_X86_MRST_H */ |
arch/x86/kernel/apb_timer.c
arch/x86/kernel/early_printk.c
arch/x86/kernel/rtc.c
arch/x86/pci/Makefile
arch/x86/pci/intel_mid_pci.c
1 | +/* | |
2 | + * Intel MID PCI support | |
3 | + * Copyright (c) 2008 Intel Corporation | |
4 | + * Jesse Barnes <jesse.barnes@intel.com> | |
5 | + * | |
6 | + * Moorestown has an interesting PCI implementation: | |
7 | + * - configuration space is memory mapped (as defined by MCFG) | |
8 | + * - Lincroft devices also have a real, type 1 configuration space | |
9 | + * - Early Lincroft silicon has a type 1 access bug that will cause | |
10 | + * a hang if non-existent devices are accessed | |
11 | + * - some devices have the "fixed BAR" capability, which means | |
12 | + * they can't be relocated or modified; check for that during | |
13 | + * BAR sizing | |
14 | + * | |
15 | + * So, we use the MCFG space for all reads and writes, but also send | |
16 | + * Lincroft writes to type 1 space. But only read/write if the device | |
17 | + * actually exists, otherwise return all 1s for reads and bit bucket | |
18 | + * the writes. | |
19 | + */ | |
20 | + | |
21 | +#include <linux/sched.h> | |
22 | +#include <linux/pci.h> | |
23 | +#include <linux/ioport.h> | |
24 | +#include <linux/init.h> | |
25 | +#include <linux/dmi.h> | |
26 | +#include <linux/acpi.h> | |
27 | +#include <linux/io.h> | |
28 | +#include <linux/smp.h> | |
29 | + | |
30 | +#include <asm/segment.h> | |
31 | +#include <asm/pci_x86.h> | |
32 | +#include <asm/hw_irq.h> | |
33 | +#include <asm/io_apic.h> | |
34 | + | |
35 | +#define PCIE_CAP_OFFSET 0x100 | |
36 | + | |
37 | +/* Fixed BAR fields */ | |
38 | +#define PCIE_VNDR_CAP_ID_FIXED_BAR 0x00 /* Fixed BAR (TBD) */ | |
39 | +#define PCI_FIXED_BAR_0_SIZE 0x04 | |
40 | +#define PCI_FIXED_BAR_1_SIZE 0x08 | |
41 | +#define PCI_FIXED_BAR_2_SIZE 0x0c | |
42 | +#define PCI_FIXED_BAR_3_SIZE 0x10 | |
43 | +#define PCI_FIXED_BAR_4_SIZE 0x14 | |
44 | +#define PCI_FIXED_BAR_5_SIZE 0x1c | |
45 | + | |
46 | +static int pci_soc_mode; | |
47 | + | |
48 | +/** | |
49 | + * fixed_bar_cap - return the offset of the fixed BAR cap if found | |
50 | + * @bus: PCI bus | |
51 | + * @devfn: device in question | |
52 | + * | |
53 | + * Look for the fixed BAR cap on @bus and @devfn, returning its offset | |
54 | + * if found or 0 otherwise. | |
55 | + */ | |
56 | +static int fixed_bar_cap(struct pci_bus *bus, unsigned int devfn) | |
57 | +{ | |
58 | + int pos; | |
59 | + u32 pcie_cap = 0, cap_data; | |
60 | + | |
61 | + pos = PCIE_CAP_OFFSET; | |
62 | + | |
63 | + if (!raw_pci_ext_ops) | |
64 | + return 0; | |
65 | + | |
66 | + while (pos) { | |
67 | + if (raw_pci_ext_ops->read(pci_domain_nr(bus), bus->number, | |
68 | + devfn, pos, 4, &pcie_cap)) | |
69 | + return 0; | |
70 | + | |
71 | + if (PCI_EXT_CAP_ID(pcie_cap) == 0x0000 || | |
72 | + PCI_EXT_CAP_ID(pcie_cap) == 0xffff) | |
73 | + break; | |
74 | + | |
75 | + if (PCI_EXT_CAP_ID(pcie_cap) == PCI_EXT_CAP_ID_VNDR) { | |
76 | + raw_pci_ext_ops->read(pci_domain_nr(bus), bus->number, | |
77 | + devfn, pos + 4, 4, &cap_data); | |
78 | + if ((cap_data & 0xffff) == PCIE_VNDR_CAP_ID_FIXED_BAR) | |
79 | + return pos; | |
80 | + } | |
81 | + | |
82 | + pos = PCI_EXT_CAP_NEXT(pcie_cap); | |
83 | + } | |
84 | + | |
85 | + return 0; | |
86 | +} | |
87 | + | |
88 | +static int pci_device_update_fixed(struct pci_bus *bus, unsigned int devfn, | |
89 | + int reg, int len, u32 val, int offset) | |
90 | +{ | |
91 | + u32 size; | |
92 | + unsigned int domain, busnum; | |
93 | + int bar = (reg - PCI_BASE_ADDRESS_0) >> 2; | |
94 | + | |
95 | + domain = pci_domain_nr(bus); | |
96 | + busnum = bus->number; | |
97 | + | |
98 | + if (val == ~0 && len == 4) { | |
99 | + unsigned long decode; | |
100 | + | |
101 | + raw_pci_ext_ops->read(domain, busnum, devfn, | |
102 | + offset + 8 + (bar * 4), 4, &size); | |
103 | + | |
104 | + /* Turn the size into a decode pattern for the sizing code */ | |
105 | + if (size) { | |
106 | + decode = size - 1; | |
107 | + decode |= decode >> 1; | |
108 | + decode |= decode >> 2; | |
109 | + decode |= decode >> 4; | |
110 | + decode |= decode >> 8; | |
111 | + decode |= decode >> 16; | |
112 | + decode++; | |
113 | + decode = ~(decode - 1); | |
114 | + } else { | |
115 | + decode = 0; | |
116 | + } | |
117 | + | |
118 | + /* | |
119 | + * If val is all ones, the core code is trying to size the reg, | |
120 | + * so update the mmconfig space with the real size. | |
121 | + * | |
122 | + * Note: this assumes the fixed size we got is a power of two. | |
123 | + */ | |
124 | + return raw_pci_ext_ops->write(domain, busnum, devfn, reg, 4, | |
125 | + decode); | |
126 | + } | |
127 | + | |
128 | + /* This is some other kind of BAR write, so just do it. */ | |
129 | + return raw_pci_ext_ops->write(domain, busnum, devfn, reg, len, val); | |
130 | +} | |
131 | + | |
132 | +/** | |
133 | + * type1_access_ok - check whether to use type 1 | |
134 | + * @bus: bus number | |
135 | + * @devfn: device & function in question | |
136 | + * | |
137 | + * If the bus is on a Lincroft chip and it exists, or is not on a Lincroft at | |
138 | + * all, the we can go ahead with any reads & writes. If it's on a Lincroft, | |
139 | + * but doesn't exist, avoid the access altogether to keep the chip from | |
140 | + * hanging. | |
141 | + */ | |
142 | +static bool type1_access_ok(unsigned int bus, unsigned int devfn, int reg) | |
143 | +{ | |
144 | + /* | |
145 | + * This is a workaround for A0 LNC bug where PCI status register does | |
146 | + * not have new CAP bit set. can not be written by SW either. | |
147 | + * | |
148 | + * PCI header type in real LNC indicates a single function device, this | |
149 | + * will prevent probing other devices under the same function in PCI | |
150 | + * shim. Therefore, use the header type in shim instead. | |
151 | + */ | |
152 | + if (reg >= 0x100 || reg == PCI_STATUS || reg == PCI_HEADER_TYPE) | |
153 | + return 0; | |
154 | + if (bus == 0 && (devfn == PCI_DEVFN(2, 0) | |
155 | + || devfn == PCI_DEVFN(0, 0) | |
156 | + || devfn == PCI_DEVFN(3, 0))) | |
157 | + return 1; | |
158 | + return 0; /* Langwell on others */ | |
159 | +} | |
160 | + | |
161 | +static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, | |
162 | + int size, u32 *value) | |
163 | +{ | |
164 | + if (type1_access_ok(bus->number, devfn, where)) | |
165 | + return pci_direct_conf1.read(pci_domain_nr(bus), bus->number, | |
166 | + devfn, where, size, value); | |
167 | + return raw_pci_ext_ops->read(pci_domain_nr(bus), bus->number, | |
168 | + devfn, where, size, value); | |
169 | +} | |
170 | + | |
171 | +static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, | |
172 | + int size, u32 value) | |
173 | +{ | |
174 | + int offset; | |
175 | + | |
176 | + /* | |
177 | + * On MRST, there is no PCI ROM BAR, this will cause a subsequent read | |
178 | + * to ROM BAR return 0 then being ignored. | |
179 | + */ | |
180 | + if (where == PCI_ROM_ADDRESS) | |
181 | + return 0; | |
182 | + | |
183 | + /* | |
184 | + * Devices with fixed BARs need special handling: | |
185 | + * - BAR sizing code will save, write ~0, read size, restore | |
186 | + * - so writes to fixed BARs need special handling | |
187 | + * - other writes to fixed BAR devices should go through mmconfig | |
188 | + */ | |
189 | + offset = fixed_bar_cap(bus, devfn); | |
190 | + if (offset && | |
191 | + (where >= PCI_BASE_ADDRESS_0 && where <= PCI_BASE_ADDRESS_5)) { | |
192 | + return pci_device_update_fixed(bus, devfn, where, size, value, | |
193 | + offset); | |
194 | + } | |
195 | + | |
196 | + /* | |
197 | + * On Moorestown update both real & mmconfig space | |
198 | + * Note: early Lincroft silicon can't handle type 1 accesses to | |
199 | + * non-existent devices, so just eat the write in that case. | |
200 | + */ | |
201 | + if (type1_access_ok(bus->number, devfn, where)) | |
202 | + return pci_direct_conf1.write(pci_domain_nr(bus), bus->number, | |
203 | + devfn, where, size, value); | |
204 | + return raw_pci_ext_ops->write(pci_domain_nr(bus), bus->number, devfn, | |
205 | + where, size, value); | |
206 | +} | |
207 | + | |
208 | +static int mrst_pci_irq_enable(struct pci_dev *dev) | |
209 | +{ | |
210 | + u8 pin; | |
211 | + struct io_apic_irq_attr irq_attr; | |
212 | + | |
213 | + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); | |
214 | + | |
215 | + /* | |
216 | + * MRST only have IOAPIC, the PCI irq lines are 1:1 mapped to | |
217 | + * IOAPIC RTE entries, so we just enable RTE for the device. | |
218 | + */ | |
219 | + irq_attr.ioapic = mp_find_ioapic(dev->irq); | |
220 | + irq_attr.ioapic_pin = dev->irq; | |
221 | + irq_attr.trigger = 1; /* level */ | |
222 | + irq_attr.polarity = 1; /* active low */ | |
223 | + io_apic_set_pci_routing(&dev->dev, dev->irq, &irq_attr); | |
224 | + | |
225 | + return 0; | |
226 | +} | |
227 | + | |
228 | +struct pci_ops pci_mrst_ops = { | |
229 | + .read = pci_read, | |
230 | + .write = pci_write, | |
231 | +}; | |
232 | + | |
233 | +/** | |
234 | + * pci_mrst_init - installs pci_mrst_ops | |
235 | + * | |
236 | + * Moorestown has an interesting PCI implementation (see above). | |
237 | + * Called when the early platform detection installs it. | |
238 | + */ | |
239 | +int __init pci_mrst_init(void) | |
240 | +{ | |
241 | + pr_info("Intel MID platform detected, using MID PCI ops\n"); | |
242 | + pci_mmcfg_late_init(); | |
243 | + pcibios_enable_irq = mrst_pci_irq_enable; | |
244 | + pci_root_ops = pci_mrst_ops; | |
245 | + pci_soc_mode = 1; | |
246 | + /* Continue with standard init */ | |
247 | + return 1; | |
248 | +} | |
249 | + | |
250 | +/* | |
251 | + * Langwell devices are not true PCI devices; they are not subject to 10 ms | |
252 | + * d3 to d0 delay required by PCI spec. | |
253 | + */ | |
254 | +static void pci_d3delay_fixup(struct pci_dev *dev) | |
255 | +{ | |
256 | + /* | |
257 | + * PCI fixups are effectively decided compile time. If we have a dual | |
258 | + * SoC/non-SoC kernel we don't want to mangle d3 on non-SoC devices. | |
259 | + */ | |
260 | + if (!pci_soc_mode) | |
261 | + return; | |
262 | + /* | |
263 | + * True PCI devices in Lincroft should allow type 1 access, the rest | |
264 | + * are Langwell fake PCI devices. | |
265 | + */ | |
266 | + if (type1_access_ok(dev->bus->number, dev->devfn, PCI_DEVICE_ID)) | |
267 | + return; | |
268 | + dev->d3_delay = 0; | |
269 | +} | |
270 | +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_d3delay_fixup); | |
271 | + | |
272 | +static void mrst_power_off_unused_dev(struct pci_dev *dev) | |
273 | +{ | |
274 | + pci_set_power_state(dev, PCI_D3hot); | |
275 | +} | |
276 | +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0801, mrst_power_off_unused_dev); | |
277 | +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0809, mrst_power_off_unused_dev); | |
278 | +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x080C, mrst_power_off_unused_dev); | |
279 | +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0812, mrst_power_off_unused_dev); | |
280 | +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0815, mrst_power_off_unused_dev); | |
281 | + | |
282 | +/* | |
283 | + * Langwell devices reside at fixed offsets, don't try to move them. | |
284 | + */ | |
285 | +static void pci_fixed_bar_fixup(struct pci_dev *dev) | |
286 | +{ | |
287 | + unsigned long offset; | |
288 | + u32 size; | |
289 | + int i; | |
290 | + | |
291 | + if (!pci_soc_mode) | |
292 | + return; | |
293 | + | |
294 | + /* Must have extended configuration space */ | |
295 | + if (dev->cfg_size < PCIE_CAP_OFFSET + 4) | |
296 | + return; | |
297 | + | |
298 | + /* Fixup the BAR sizes for fixed BAR devices and make them unmoveable */ | |
299 | + offset = fixed_bar_cap(dev->bus, dev->devfn); | |
300 | + if (!offset || PCI_DEVFN(2, 0) == dev->devfn || | |
301 | + PCI_DEVFN(2, 2) == dev->devfn) | |
302 | + return; | |
303 | + | |
304 | + for (i = 0; i < PCI_ROM_RESOURCE; i++) { | |
305 | + pci_read_config_dword(dev, offset + 8 + (i * 4), &size); | |
306 | + dev->resource[i].end = dev->resource[i].start + size - 1; | |
307 | + dev->resource[i].flags |= IORESOURCE_PCI_FIXED; | |
308 | + } | |
309 | +} | |
310 | +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixed_bar_fixup); |
arch/x86/pci/mrst.c
1 | -/* | |
2 | - * Moorestown PCI support | |
3 | - * Copyright (c) 2008 Intel Corporation | |
4 | - * Jesse Barnes <jesse.barnes@intel.com> | |
5 | - * | |
6 | - * Moorestown has an interesting PCI implementation: | |
7 | - * - configuration space is memory mapped (as defined by MCFG) | |
8 | - * - Lincroft devices also have a real, type 1 configuration space | |
9 | - * - Early Lincroft silicon has a type 1 access bug that will cause | |
10 | - * a hang if non-existent devices are accessed | |
11 | - * - some devices have the "fixed BAR" capability, which means | |
12 | - * they can't be relocated or modified; check for that during | |
13 | - * BAR sizing | |
14 | - * | |
15 | - * So, we use the MCFG space for all reads and writes, but also send | |
16 | - * Lincroft writes to type 1 space. But only read/write if the device | |
17 | - * actually exists, otherwise return all 1s for reads and bit bucket | |
18 | - * the writes. | |
19 | - */ | |
20 | - | |
21 | -#include <linux/sched.h> | |
22 | -#include <linux/pci.h> | |
23 | -#include <linux/ioport.h> | |
24 | -#include <linux/init.h> | |
25 | -#include <linux/dmi.h> | |
26 | -#include <linux/acpi.h> | |
27 | -#include <linux/io.h> | |
28 | -#include <linux/smp.h> | |
29 | - | |
30 | -#include <asm/segment.h> | |
31 | -#include <asm/pci_x86.h> | |
32 | -#include <asm/hw_irq.h> | |
33 | -#include <asm/io_apic.h> | |
34 | - | |
35 | -#define PCIE_CAP_OFFSET 0x100 | |
36 | - | |
37 | -/* Fixed BAR fields */ | |
38 | -#define PCIE_VNDR_CAP_ID_FIXED_BAR 0x00 /* Fixed BAR (TBD) */ | |
39 | -#define PCI_FIXED_BAR_0_SIZE 0x04 | |
40 | -#define PCI_FIXED_BAR_1_SIZE 0x08 | |
41 | -#define PCI_FIXED_BAR_2_SIZE 0x0c | |
42 | -#define PCI_FIXED_BAR_3_SIZE 0x10 | |
43 | -#define PCI_FIXED_BAR_4_SIZE 0x14 | |
44 | -#define PCI_FIXED_BAR_5_SIZE 0x1c | |
45 | - | |
46 | -static int pci_soc_mode; | |
47 | - | |
48 | -/** | |
49 | - * fixed_bar_cap - return the offset of the fixed BAR cap if found | |
50 | - * @bus: PCI bus | |
51 | - * @devfn: device in question | |
52 | - * | |
53 | - * Look for the fixed BAR cap on @bus and @devfn, returning its offset | |
54 | - * if found or 0 otherwise. | |
55 | - */ | |
56 | -static int fixed_bar_cap(struct pci_bus *bus, unsigned int devfn) | |
57 | -{ | |
58 | - int pos; | |
59 | - u32 pcie_cap = 0, cap_data; | |
60 | - | |
61 | - pos = PCIE_CAP_OFFSET; | |
62 | - | |
63 | - if (!raw_pci_ext_ops) | |
64 | - return 0; | |
65 | - | |
66 | - while (pos) { | |
67 | - if (raw_pci_ext_ops->read(pci_domain_nr(bus), bus->number, | |
68 | - devfn, pos, 4, &pcie_cap)) | |
69 | - return 0; | |
70 | - | |
71 | - if (PCI_EXT_CAP_ID(pcie_cap) == 0x0000 || | |
72 | - PCI_EXT_CAP_ID(pcie_cap) == 0xffff) | |
73 | - break; | |
74 | - | |
75 | - if (PCI_EXT_CAP_ID(pcie_cap) == PCI_EXT_CAP_ID_VNDR) { | |
76 | - raw_pci_ext_ops->read(pci_domain_nr(bus), bus->number, | |
77 | - devfn, pos + 4, 4, &cap_data); | |
78 | - if ((cap_data & 0xffff) == PCIE_VNDR_CAP_ID_FIXED_BAR) | |
79 | - return pos; | |
80 | - } | |
81 | - | |
82 | - pos = PCI_EXT_CAP_NEXT(pcie_cap); | |
83 | - } | |
84 | - | |
85 | - return 0; | |
86 | -} | |
87 | - | |
88 | -static int pci_device_update_fixed(struct pci_bus *bus, unsigned int devfn, | |
89 | - int reg, int len, u32 val, int offset) | |
90 | -{ | |
91 | - u32 size; | |
92 | - unsigned int domain, busnum; | |
93 | - int bar = (reg - PCI_BASE_ADDRESS_0) >> 2; | |
94 | - | |
95 | - domain = pci_domain_nr(bus); | |
96 | - busnum = bus->number; | |
97 | - | |
98 | - if (val == ~0 && len == 4) { | |
99 | - unsigned long decode; | |
100 | - | |
101 | - raw_pci_ext_ops->read(domain, busnum, devfn, | |
102 | - offset + 8 + (bar * 4), 4, &size); | |
103 | - | |
104 | - /* Turn the size into a decode pattern for the sizing code */ | |
105 | - if (size) { | |
106 | - decode = size - 1; | |
107 | - decode |= decode >> 1; | |
108 | - decode |= decode >> 2; | |
109 | - decode |= decode >> 4; | |
110 | - decode |= decode >> 8; | |
111 | - decode |= decode >> 16; | |
112 | - decode++; | |
113 | - decode = ~(decode - 1); | |
114 | - } else { | |
115 | - decode = 0; | |
116 | - } | |
117 | - | |
118 | - /* | |
119 | - * If val is all ones, the core code is trying to size the reg, | |
120 | - * so update the mmconfig space with the real size. | |
121 | - * | |
122 | - * Note: this assumes the fixed size we got is a power of two. | |
123 | - */ | |
124 | - return raw_pci_ext_ops->write(domain, busnum, devfn, reg, 4, | |
125 | - decode); | |
126 | - } | |
127 | - | |
128 | - /* This is some other kind of BAR write, so just do it. */ | |
129 | - return raw_pci_ext_ops->write(domain, busnum, devfn, reg, len, val); | |
130 | -} | |
131 | - | |
132 | -/** | |
133 | - * type1_access_ok - check whether to use type 1 | |
134 | - * @bus: bus number | |
135 | - * @devfn: device & function in question | |
136 | - * | |
137 | - * If the bus is on a Lincroft chip and it exists, or is not on a Lincroft at | |
138 | - * all, the we can go ahead with any reads & writes. If it's on a Lincroft, | |
139 | - * but doesn't exist, avoid the access altogether to keep the chip from | |
140 | - * hanging. | |
141 | - */ | |
142 | -static bool type1_access_ok(unsigned int bus, unsigned int devfn, int reg) | |
143 | -{ | |
144 | - /* | |
145 | - * This is a workaround for A0 LNC bug where PCI status register does | |
146 | - * not have new CAP bit set. can not be written by SW either. | |
147 | - * | |
148 | - * PCI header type in real LNC indicates a single function device, this | |
149 | - * will prevent probing other devices under the same function in PCI | |
150 | - * shim. Therefore, use the header type in shim instead. | |
151 | - */ | |
152 | - if (reg >= 0x100 || reg == PCI_STATUS || reg == PCI_HEADER_TYPE) | |
153 | - return 0; | |
154 | - if (bus == 0 && (devfn == PCI_DEVFN(2, 0) | |
155 | - || devfn == PCI_DEVFN(0, 0) | |
156 | - || devfn == PCI_DEVFN(3, 0))) | |
157 | - return 1; | |
158 | - return 0; /* Langwell on others */ | |
159 | -} | |
160 | - | |
161 | -static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, | |
162 | - int size, u32 *value) | |
163 | -{ | |
164 | - if (type1_access_ok(bus->number, devfn, where)) | |
165 | - return pci_direct_conf1.read(pci_domain_nr(bus), bus->number, | |
166 | - devfn, where, size, value); | |
167 | - return raw_pci_ext_ops->read(pci_domain_nr(bus), bus->number, | |
168 | - devfn, where, size, value); | |
169 | -} | |
170 | - | |
171 | -static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, | |
172 | - int size, u32 value) | |
173 | -{ | |
174 | - int offset; | |
175 | - | |
176 | - /* | |
177 | - * On MRST, there is no PCI ROM BAR, this will cause a subsequent read | |
178 | - * to ROM BAR return 0 then being ignored. | |
179 | - */ | |
180 | - if (where == PCI_ROM_ADDRESS) | |
181 | - return 0; | |
182 | - | |
183 | - /* | |
184 | - * Devices with fixed BARs need special handling: | |
185 | - * - BAR sizing code will save, write ~0, read size, restore | |
186 | - * - so writes to fixed BARs need special handling | |
187 | - * - other writes to fixed BAR devices should go through mmconfig | |
188 | - */ | |
189 | - offset = fixed_bar_cap(bus, devfn); | |
190 | - if (offset && | |
191 | - (where >= PCI_BASE_ADDRESS_0 && where <= PCI_BASE_ADDRESS_5)) { | |
192 | - return pci_device_update_fixed(bus, devfn, where, size, value, | |
193 | - offset); | |
194 | - } | |
195 | - | |
196 | - /* | |
197 | - * On Moorestown update both real & mmconfig space | |
198 | - * Note: early Lincroft silicon can't handle type 1 accesses to | |
199 | - * non-existent devices, so just eat the write in that case. | |
200 | - */ | |
201 | - if (type1_access_ok(bus->number, devfn, where)) | |
202 | - return pci_direct_conf1.write(pci_domain_nr(bus), bus->number, | |
203 | - devfn, where, size, value); | |
204 | - return raw_pci_ext_ops->write(pci_domain_nr(bus), bus->number, devfn, | |
205 | - where, size, value); | |
206 | -} | |
207 | - | |
208 | -static int mrst_pci_irq_enable(struct pci_dev *dev) | |
209 | -{ | |
210 | - u8 pin; | |
211 | - struct io_apic_irq_attr irq_attr; | |
212 | - | |
213 | - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); | |
214 | - | |
215 | - /* | |
216 | - * MRST only have IOAPIC, the PCI irq lines are 1:1 mapped to | |
217 | - * IOAPIC RTE entries, so we just enable RTE for the device. | |
218 | - */ | |
219 | - irq_attr.ioapic = mp_find_ioapic(dev->irq); | |
220 | - irq_attr.ioapic_pin = dev->irq; | |
221 | - irq_attr.trigger = 1; /* level */ | |
222 | - irq_attr.polarity = 1; /* active low */ | |
223 | - io_apic_set_pci_routing(&dev->dev, dev->irq, &irq_attr); | |
224 | - | |
225 | - return 0; | |
226 | -} | |
227 | - | |
228 | -struct pci_ops pci_mrst_ops = { | |
229 | - .read = pci_read, | |
230 | - .write = pci_write, | |
231 | -}; | |
232 | - | |
233 | -/** | |
234 | - * pci_mrst_init - installs pci_mrst_ops | |
235 | - * | |
236 | - * Moorestown has an interesting PCI implementation (see above). | |
237 | - * Called when the early platform detection installs it. | |
238 | - */ | |
239 | -int __init pci_mrst_init(void) | |
240 | -{ | |
241 | - pr_info("Intel MID platform detected, using MID PCI ops\n"); | |
242 | - pci_mmcfg_late_init(); | |
243 | - pcibios_enable_irq = mrst_pci_irq_enable; | |
244 | - pci_root_ops = pci_mrst_ops; | |
245 | - pci_soc_mode = 1; | |
246 | - /* Continue with standard init */ | |
247 | - return 1; | |
248 | -} | |
249 | - | |
250 | -/* | |
251 | - * Langwell devices are not true PCI devices; they are not subject to 10 ms | |
252 | - * d3 to d0 delay required by PCI spec. | |
253 | - */ | |
254 | -static void pci_d3delay_fixup(struct pci_dev *dev) | |
255 | -{ | |
256 | - /* | |
257 | - * PCI fixups are effectively decided compile time. If we have a dual | |
258 | - * SoC/non-SoC kernel we don't want to mangle d3 on non-SoC devices. | |
259 | - */ | |
260 | - if (!pci_soc_mode) | |
261 | - return; | |
262 | - /* | |
263 | - * True PCI devices in Lincroft should allow type 1 access, the rest | |
264 | - * are Langwell fake PCI devices. | |
265 | - */ | |
266 | - if (type1_access_ok(dev->bus->number, dev->devfn, PCI_DEVICE_ID)) | |
267 | - return; | |
268 | - dev->d3_delay = 0; | |
269 | -} | |
270 | -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_d3delay_fixup); | |
271 | - | |
272 | -static void mrst_power_off_unused_dev(struct pci_dev *dev) | |
273 | -{ | |
274 | - pci_set_power_state(dev, PCI_D3hot); | |
275 | -} | |
276 | -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0801, mrst_power_off_unused_dev); | |
277 | -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0809, mrst_power_off_unused_dev); | |
278 | -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x080C, mrst_power_off_unused_dev); | |
279 | -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0812, mrst_power_off_unused_dev); | |
280 | -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0815, mrst_power_off_unused_dev); | |
281 | - | |
282 | -/* | |
283 | - * Langwell devices reside at fixed offsets, don't try to move them. | |
284 | - */ | |
285 | -static void pci_fixed_bar_fixup(struct pci_dev *dev) | |
286 | -{ | |
287 | - unsigned long offset; | |
288 | - u32 size; | |
289 | - int i; | |
290 | - | |
291 | - if (!pci_soc_mode) | |
292 | - return; | |
293 | - | |
294 | - /* Must have extended configuration space */ | |
295 | - if (dev->cfg_size < PCIE_CAP_OFFSET + 4) | |
296 | - return; | |
297 | - | |
298 | - /* Fixup the BAR sizes for fixed BAR devices and make them unmoveable */ | |
299 | - offset = fixed_bar_cap(dev->bus, dev->devfn); | |
300 | - if (!offset || PCI_DEVFN(2, 0) == dev->devfn || | |
301 | - PCI_DEVFN(2, 2) == dev->devfn) | |
302 | - return; | |
303 | - | |
304 | - for (i = 0; i < PCI_ROM_RESOURCE; i++) { | |
305 | - pci_read_config_dword(dev, offset + 8 + (i * 4), &size); | |
306 | - dev->resource[i].end = dev->resource[i].start + size - 1; | |
307 | - dev->resource[i].flags |= IORESOURCE_PCI_FIXED; | |
308 | - } | |
309 | -} | |
310 | -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixed_bar_fixup); |
arch/x86/platform/Makefile
arch/x86/platform/intel-mid/Makefile
arch/x86/platform/intel-mid/early_printk_intel_mid.c
1 | +/* | |
2 | + * early_printk_intel_mid.c - early consoles for Intel MID platforms | |
3 | + * | |
4 | + * Copyright (c) 2008-2010, Intel Corporation | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or | |
7 | + * modify it under the terms of the GNU General Public License | |
8 | + * as published by the Free Software Foundation; version 2 | |
9 | + * of the License. | |
10 | + */ | |
11 | + | |
12 | +/* | |
13 | + * This file implements two early consoles named mrst and hsu. | |
14 | + * mrst is based on Maxim3110 spi-uart device, it exists in both | |
15 | + * Moorestown and Medfield platforms, while hsu is based on a High | |
16 | + * Speed UART device which only exists in the Medfield platform | |
17 | + */ | |
18 | + | |
19 | +#include <linux/serial_reg.h> | |
20 | +#include <linux/serial_mfd.h> | |
21 | +#include <linux/kmsg_dump.h> | |
22 | +#include <linux/console.h> | |
23 | +#include <linux/kernel.h> | |
24 | +#include <linux/delay.h> | |
25 | +#include <linux/init.h> | |
26 | +#include <linux/io.h> | |
27 | + | |
28 | +#include <asm/fixmap.h> | |
29 | +#include <asm/pgtable.h> | |
30 | +#include <asm/intel-mid.h> | |
31 | + | |
32 | +#define MRST_SPI_TIMEOUT 0x200000 | |
33 | +#define MRST_REGBASE_SPI0 0xff128000 | |
34 | +#define MRST_REGBASE_SPI1 0xff128400 | |
35 | +#define MRST_CLK_SPI0_REG 0xff11d86c | |
36 | + | |
37 | +/* Bit fields in CTRLR0 */ | |
38 | +#define SPI_DFS_OFFSET 0 | |
39 | + | |
40 | +#define SPI_FRF_OFFSET 4 | |
41 | +#define SPI_FRF_SPI 0x0 | |
42 | +#define SPI_FRF_SSP 0x1 | |
43 | +#define SPI_FRF_MICROWIRE 0x2 | |
44 | +#define SPI_FRF_RESV 0x3 | |
45 | + | |
46 | +#define SPI_MODE_OFFSET 6 | |
47 | +#define SPI_SCPH_OFFSET 6 | |
48 | +#define SPI_SCOL_OFFSET 7 | |
49 | +#define SPI_TMOD_OFFSET 8 | |
50 | +#define SPI_TMOD_TR 0x0 /* xmit & recv */ | |
51 | +#define SPI_TMOD_TO 0x1 /* xmit only */ | |
52 | +#define SPI_TMOD_RO 0x2 /* recv only */ | |
53 | +#define SPI_TMOD_EPROMREAD 0x3 /* eeprom read mode */ | |
54 | + | |
55 | +#define SPI_SLVOE_OFFSET 10 | |
56 | +#define SPI_SRL_OFFSET 11 | |
57 | +#define SPI_CFS_OFFSET 12 | |
58 | + | |
59 | +/* Bit fields in SR, 7 bits */ | |
60 | +#define SR_MASK 0x7f /* cover 7 bits */ | |
61 | +#define SR_BUSY (1 << 0) | |
62 | +#define SR_TF_NOT_FULL (1 << 1) | |
63 | +#define SR_TF_EMPT (1 << 2) | |
64 | +#define SR_RF_NOT_EMPT (1 << 3) | |
65 | +#define SR_RF_FULL (1 << 4) | |
66 | +#define SR_TX_ERR (1 << 5) | |
67 | +#define SR_DCOL (1 << 6) | |
68 | + | |
69 | +struct dw_spi_reg { | |
70 | + u32 ctrl0; | |
71 | + u32 ctrl1; | |
72 | + u32 ssienr; | |
73 | + u32 mwcr; | |
74 | + u32 ser; | |
75 | + u32 baudr; | |
76 | + u32 txfltr; | |
77 | + u32 rxfltr; | |
78 | + u32 txflr; | |
79 | + u32 rxflr; | |
80 | + u32 sr; | |
81 | + u32 imr; | |
82 | + u32 isr; | |
83 | + u32 risr; | |
84 | + u32 txoicr; | |
85 | + u32 rxoicr; | |
86 | + u32 rxuicr; | |
87 | + u32 msticr; | |
88 | + u32 icr; | |
89 | + u32 dmacr; | |
90 | + u32 dmatdlr; | |
91 | + u32 dmardlr; | |
92 | + u32 idr; | |
93 | + u32 version; | |
94 | + | |
95 | + /* Currently operates as 32 bits, though only the low 16 bits matter */ | |
96 | + u32 dr; | |
97 | +} __packed; | |
98 | + | |
99 | +#define dw_readl(dw, name) __raw_readl(&(dw)->name) | |
100 | +#define dw_writel(dw, name, val) __raw_writel((val), &(dw)->name) | |
101 | + | |
102 | +/* Default use SPI0 register for mrst, we will detect Penwell and use SPI1 */ | |
103 | +static unsigned long mrst_spi_paddr = MRST_REGBASE_SPI0; | |
104 | + | |
105 | +static u32 *pclk_spi0; | |
106 | +/* Always contains an accessible address, start with 0 */ | |
107 | +static struct dw_spi_reg *pspi; | |
108 | + | |
109 | +static struct kmsg_dumper dw_dumper; | |
110 | +static int dumper_registered; | |
111 | + | |
112 | +static void dw_kmsg_dump(struct kmsg_dumper *dumper, | |
113 | + enum kmsg_dump_reason reason) | |
114 | +{ | |
115 | + static char line[1024]; | |
116 | + size_t len; | |
117 | + | |
118 | + /* When run to this, we'd better re-init the HW */ | |
119 | + mrst_early_console_init(); | |
120 | + | |
121 | + while (kmsg_dump_get_line(dumper, true, line, sizeof(line), &len)) | |
122 | + early_mrst_console.write(&early_mrst_console, line, len); | |
123 | +} | |
124 | + | |
125 | +/* Set the ratio rate to 115200, 8n1, IRQ disabled */ | |
126 | +static void max3110_write_config(void) | |
127 | +{ | |
128 | + u16 config; | |
129 | + | |
130 | + config = 0xc001; | |
131 | + dw_writel(pspi, dr, config); | |
132 | +} | |
133 | + | |
134 | +/* Translate char to a eligible word and send to max3110 */ | |
135 | +static void max3110_write_data(char c) | |
136 | +{ | |
137 | + u16 data; | |
138 | + | |
139 | + data = 0x8000 | c; | |
140 | + dw_writel(pspi, dr, data); | |
141 | +} | |
142 | + | |
143 | +void mrst_early_console_init(void) | |
144 | +{ | |
145 | + u32 ctrlr0 = 0; | |
146 | + u32 spi0_cdiv; | |
147 | + u32 freq; /* Freqency info only need be searched once */ | |
148 | + | |
149 | + /* Base clk is 100 MHz, the actual clk = 100M / (clk_divider + 1) */ | |
150 | + pclk_spi0 = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE, | |
151 | + MRST_CLK_SPI0_REG); | |
152 | + spi0_cdiv = ((*pclk_spi0) & 0xe00) >> 9; | |
153 | + freq = 100000000 / (spi0_cdiv + 1); | |
154 | + | |
155 | + if (mrst_identify_cpu() == MRST_CPU_CHIP_PENWELL) | |
156 | + mrst_spi_paddr = MRST_REGBASE_SPI1; | |
157 | + | |
158 | + pspi = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE, | |
159 | + mrst_spi_paddr); | |
160 | + | |
161 | + /* Disable SPI controller */ | |
162 | + dw_writel(pspi, ssienr, 0); | |
163 | + | |
164 | + /* Set control param, 8 bits, transmit only mode */ | |
165 | + ctrlr0 = dw_readl(pspi, ctrl0); | |
166 | + | |
167 | + ctrlr0 &= 0xfcc0; | |
168 | + ctrlr0 |= 0xf | (SPI_FRF_SPI << SPI_FRF_OFFSET) | |
169 | + | (SPI_TMOD_TO << SPI_TMOD_OFFSET); | |
170 | + dw_writel(pspi, ctrl0, ctrlr0); | |
171 | + | |
172 | + /* | |
173 | + * Change the spi0 clk to comply with 115200 bps, use 100000 to | |
174 | + * calculate the clk dividor to make the clock a little slower | |
175 | + * than real baud rate. | |
176 | + */ | |
177 | + dw_writel(pspi, baudr, freq/100000); | |
178 | + | |
179 | + /* Disable all INT for early phase */ | |
180 | + dw_writel(pspi, imr, 0x0); | |
181 | + | |
182 | + /* Set the cs to spi-uart */ | |
183 | + dw_writel(pspi, ser, 0x2); | |
184 | + | |
185 | + /* Enable the HW, the last step for HW init */ | |
186 | + dw_writel(pspi, ssienr, 0x1); | |
187 | + | |
188 | + /* Set the default configuration */ | |
189 | + max3110_write_config(); | |
190 | + | |
191 | + /* Register the kmsg dumper */ | |
192 | + if (!dumper_registered) { | |
193 | + dw_dumper.dump = dw_kmsg_dump; | |
194 | + kmsg_dump_register(&dw_dumper); | |
195 | + dumper_registered = 1; | |
196 | + } | |
197 | +} | |
198 | + | |
199 | +/* Slave select should be called in the read/write function */ | |
200 | +static void early_mrst_spi_putc(char c) | |
201 | +{ | |
202 | + unsigned int timeout; | |
203 | + u32 sr; | |
204 | + | |
205 | + timeout = MRST_SPI_TIMEOUT; | |
206 | + /* Early putc needs to make sure the TX FIFO is not full */ | |
207 | + while (--timeout) { | |
208 | + sr = dw_readl(pspi, sr); | |
209 | + if (!(sr & SR_TF_NOT_FULL)) | |
210 | + cpu_relax(); | |
211 | + else | |
212 | + break; | |
213 | + } | |
214 | + | |
215 | + if (!timeout) | |
216 | + pr_warn("MRST earlycon: timed out\n"); | |
217 | + else | |
218 | + max3110_write_data(c); | |
219 | +} | |
220 | + | |
221 | +/* Early SPI only uses polling mode */ | |
222 | +static void early_mrst_spi_write(struct console *con, const char *str, | |
223 | + unsigned n) | |
224 | +{ | |
225 | + int i; | |
226 | + | |
227 | + for (i = 0; i < n && *str; i++) { | |
228 | + if (*str == '\n') | |
229 | + early_mrst_spi_putc('\r'); | |
230 | + early_mrst_spi_putc(*str); | |
231 | + str++; | |
232 | + } | |
233 | +} | |
234 | + | |
235 | +struct console early_mrst_console = { | |
236 | + .name = "earlymrst", | |
237 | + .write = early_mrst_spi_write, | |
238 | + .flags = CON_PRINTBUFFER, | |
239 | + .index = -1, | |
240 | +}; | |
241 | + | |
242 | +/* | |
243 | + * Following is the early console based on Medfield HSU (High | |
244 | + * Speed UART) device. | |
245 | + */ | |
246 | +#define HSU_PORT_BASE 0xffa28080 | |
247 | + | |
248 | +static void __iomem *phsu; | |
249 | + | |
250 | +void hsu_early_console_init(const char *s) | |
251 | +{ | |
252 | + unsigned long paddr, port = 0; | |
253 | + u8 lcr; | |
254 | + | |
255 | + /* | |
256 | + * Select the early HSU console port if specified by user in the | |
257 | + * kernel command line. | |
258 | + */ | |
259 | + if (*s && !kstrtoul(s, 10, &port)) | |
260 | + port = clamp_val(port, 0, 2); | |
261 | + | |
262 | + paddr = HSU_PORT_BASE + port * 0x80; | |
263 | + phsu = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE, paddr); | |
264 | + | |
265 | + /* Disable FIFO */ | |
266 | + writeb(0x0, phsu + UART_FCR); | |
267 | + | |
268 | + /* Set to default 115200 bps, 8n1 */ | |
269 | + lcr = readb(phsu + UART_LCR); | |
270 | + writeb((0x80 | lcr), phsu + UART_LCR); | |
271 | + writeb(0x18, phsu + UART_DLL); | |
272 | + writeb(lcr, phsu + UART_LCR); | |
273 | + writel(0x3600, phsu + UART_MUL*4); | |
274 | + | |
275 | + writeb(0x8, phsu + UART_MCR); | |
276 | + writeb(0x7, phsu + UART_FCR); | |
277 | + writeb(0x3, phsu + UART_LCR); | |
278 | + | |
279 | + /* Clear IRQ status */ | |
280 | + readb(phsu + UART_LSR); | |
281 | + readb(phsu + UART_RX); | |
282 | + readb(phsu + UART_IIR); | |
283 | + readb(phsu + UART_MSR); | |
284 | + | |
285 | + /* Enable FIFO */ | |
286 | + writeb(0x7, phsu + UART_FCR); | |
287 | +} | |
288 | + | |
289 | +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) | |
290 | + | |
291 | +static void early_hsu_putc(char ch) | |
292 | +{ | |
293 | + unsigned int timeout = 10000; /* 10ms */ | |
294 | + u8 status; | |
295 | + | |
296 | + while (--timeout) { | |
297 | + status = readb(phsu + UART_LSR); | |
298 | + if (status & BOTH_EMPTY) | |
299 | + break; | |
300 | + udelay(1); | |
301 | + } | |
302 | + | |
303 | + /* Only write the char when there was no timeout */ | |
304 | + if (timeout) | |
305 | + writeb(ch, phsu + UART_TX); | |
306 | +} | |
307 | + | |
308 | +static void early_hsu_write(struct console *con, const char *str, unsigned n) | |
309 | +{ | |
310 | + int i; | |
311 | + | |
312 | + for (i = 0; i < n && *str; i++) { | |
313 | + if (*str == '\n') | |
314 | + early_hsu_putc('\r'); | |
315 | + early_hsu_putc(*str); | |
316 | + str++; | |
317 | + } | |
318 | +} | |
319 | + | |
320 | +struct console early_hsu_console = { | |
321 | + .name = "earlyhsu", | |
322 | + .write = early_hsu_write, | |
323 | + .flags = CON_PRINTBUFFER, | |
324 | + .index = -1, | |
325 | +}; |
arch/x86/platform/intel-mid/intel-mid.c
Changes suppressed. Click to show
1 | +/* | |
2 | + * intel-mid.c: Intel MID platform setup code | |
3 | + * | |
4 | + * (C) Copyright 2008, 2012 Intel Corporation | |
5 | + * Author: Jacob Pan (jacob.jun.pan@intel.com) | |
6 | + * Author: Sathyanarayanan Kuppuswamy <sathyanarayanan.kuppuswamy@intel.com> | |
7 | + * | |
8 | + * This program is free software; you can redistribute it and/or | |
9 | + * modify it under the terms of the GNU General Public License | |
10 | + * as published by the Free Software Foundation; version 2 | |
11 | + * of the License. | |
12 | + */ | |
13 | + | |
14 | +#define pr_fmt(fmt) "mrst: " fmt | |
15 | + | |
16 | +#include <linux/init.h> | |
17 | +#include <linux/kernel.h> | |
18 | +#include <linux/interrupt.h> | |
19 | +#include <linux/scatterlist.h> | |
20 | +#include <linux/sfi.h> | |
21 | +#include <linux/intel_pmic_gpio.h> | |
22 | +#include <linux/spi/spi.h> | |
23 | +#include <linux/i2c.h> | |
24 | +#include <linux/platform_data/pca953x.h> | |
25 | +#include <linux/gpio_keys.h> | |
26 | +#include <linux/input.h> | |
27 | +#include <linux/platform_device.h> | |
28 | +#include <linux/irq.h> | |
29 | +#include <linux/module.h> | |
30 | +#include <linux/notifier.h> | |
31 | +#include <linux/mfd/intel_msic.h> | |
32 | +#include <linux/gpio.h> | |
33 | +#include <linux/i2c/tc35876x.h> | |
34 | + | |
35 | +#include <asm/setup.h> | |
36 | +#include <asm/mpspec_def.h> | |
37 | +#include <asm/hw_irq.h> | |
38 | +#include <asm/apic.h> | |
39 | +#include <asm/io_apic.h> | |
40 | +#include <asm/intel-mid.h> | |
41 | +#include <asm/intel_mid_vrtc.h> | |
42 | +#include <asm/io.h> | |
43 | +#include <asm/i8259.h> | |
44 | +#include <asm/intel_scu_ipc.h> | |
45 | +#include <asm/apb_timer.h> | |
46 | +#include <asm/reboot.h> | |
47 | + | |
48 | +/* | |
49 | + * the clockevent devices on Moorestown/Medfield can be APBT or LAPIC clock, | |
50 | + * cmdline option x86_mrst_timer can be used to override the configuration | |
51 | + * to prefer one or the other. | |
52 | + * at runtime, there are basically three timer configurations: | |
53 | + * 1. per cpu apbt clock only | |
54 | + * 2. per cpu always-on lapic clocks only, this is Penwell/Medfield only | |
55 | + * 3. per cpu lapic clock (C3STOP) and one apbt clock, with broadcast. | |
56 | + * | |
57 | + * by default (without cmdline option), platform code first detects cpu type | |
58 | + * to see if we are on lincroft or penwell, then set up both lapic or apbt | |
59 | + * clocks accordingly. | |
60 | + * i.e. by default, medfield uses configuration #2, moorestown uses #1. | |
61 | + * config #3 is supported but not recommended on medfield. | |
62 | + * | |
63 | + * rating and feature summary: | |
64 | + * lapic (with C3STOP) --------- 100 | |
65 | + * apbt (always-on) ------------ 110 | |
66 | + * lapic (always-on,ARAT) ------ 150 | |
67 | + */ | |
68 | + | |
69 | +enum mrst_timer_options mrst_timer_options; | |
70 | + | |
71 | +static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM]; | |
72 | +static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM]; | |
73 | +enum mrst_cpu_type __mrst_cpu_chip; | |
74 | +EXPORT_SYMBOL_GPL(__mrst_cpu_chip); | |
75 | + | |
76 | +int sfi_mtimer_num; | |
77 | + | |
78 | +struct sfi_rtc_table_entry sfi_mrtc_array[SFI_MRTC_MAX]; | |
79 | +EXPORT_SYMBOL_GPL(sfi_mrtc_array); | |
80 | +int sfi_mrtc_num; | |
81 | + | |
82 | +static void mrst_power_off(void) | |
83 | +{ | |
84 | +} | |
85 | + | |
86 | +static void mrst_reboot(void) | |
87 | +{ | |
88 | + intel_scu_ipc_simple_command(IPCMSG_COLD_BOOT, 0); | |
89 | +} | |
90 | + | |
91 | +/* parse all the mtimer info to a static mtimer array */ | |
92 | +static int __init sfi_parse_mtmr(struct sfi_table_header *table) | |
93 | +{ | |
94 | + struct sfi_table_simple *sb; | |
95 | + struct sfi_timer_table_entry *pentry; | |
96 | + struct mpc_intsrc mp_irq; | |
97 | + int totallen; | |
98 | + | |
99 | + sb = (struct sfi_table_simple *)table; | |
100 | + if (!sfi_mtimer_num) { | |
101 | + sfi_mtimer_num = SFI_GET_NUM_ENTRIES(sb, | |
102 | + struct sfi_timer_table_entry); | |
103 | + pentry = (struct sfi_timer_table_entry *) sb->pentry; | |
104 | + totallen = sfi_mtimer_num * sizeof(*pentry); | |
105 | + memcpy(sfi_mtimer_array, pentry, totallen); | |
106 | + } | |
107 | + | |
108 | + pr_debug("SFI MTIMER info (num = %d):\n", sfi_mtimer_num); | |
109 | + pentry = sfi_mtimer_array; | |
110 | + for (totallen = 0; totallen < sfi_mtimer_num; totallen++, pentry++) { | |
111 | + pr_debug("timer[%d]: paddr = 0x%08x, freq = %dHz," | |
112 | + " irq = %d\n", totallen, (u32)pentry->phys_addr, | |
113 | + pentry->freq_hz, pentry->irq); | |
114 | + if (!pentry->irq) | |
115 | + continue; | |
116 | + mp_irq.type = MP_INTSRC; | |
117 | + mp_irq.irqtype = mp_INT; | |
118 | +/* triggering mode edge bit 2-3, active high polarity bit 0-1 */ | |
119 | + mp_irq.irqflag = 5; | |
120 | + mp_irq.srcbus = MP_BUS_ISA; | |
121 | + mp_irq.srcbusirq = pentry->irq; /* IRQ */ | |
122 | + mp_irq.dstapic = MP_APIC_ALL; | |
123 | + mp_irq.dstirq = pentry->irq; | |
124 | + mp_save_irq(&mp_irq); | |
125 | + } | |
126 | + | |
127 | + return 0; | |
128 | +} | |
129 | + | |
130 | +struct sfi_timer_table_entry *sfi_get_mtmr(int hint) | |
131 | +{ | |
132 | + int i; | |
133 | + if (hint < sfi_mtimer_num) { | |
134 | + if (!sfi_mtimer_usage[hint]) { | |
135 | + pr_debug("hint taken for timer %d irq %d\n", | |
136 | + hint, sfi_mtimer_array[hint].irq); | |
137 | + sfi_mtimer_usage[hint] = 1; | |
138 | + return &sfi_mtimer_array[hint]; | |
139 | + } | |
140 | + } | |
141 | + /* take the first timer available */ | |
142 | + for (i = 0; i < sfi_mtimer_num;) { | |
143 | + if (!sfi_mtimer_usage[i]) { | |
144 | + sfi_mtimer_usage[i] = 1; | |
145 | + return &sfi_mtimer_array[i]; | |
146 | + } | |
147 | + i++; | |
148 | + } | |
149 | + return NULL; | |
150 | +} | |
151 | + | |
152 | +void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr) | |
153 | +{ | |
154 | + int i; | |
155 | + for (i = 0; i < sfi_mtimer_num;) { | |
156 | + if (mtmr->irq == sfi_mtimer_array[i].irq) { | |
157 | + sfi_mtimer_usage[i] = 0; | |
158 | + return; | |
159 | + } | |
160 | + i++; | |
161 | + } | |
162 | +} | |
163 | + | |
164 | +/* parse all the mrtc info to a global mrtc array */ | |
165 | +int __init sfi_parse_mrtc(struct sfi_table_header *table) | |
166 | +{ | |
167 | + struct sfi_table_simple *sb; | |
168 | + struct sfi_rtc_table_entry *pentry; | |
169 | + struct mpc_intsrc mp_irq; | |
170 | + | |
171 | + int totallen; | |
172 | + | |
173 | + sb = (struct sfi_table_simple *)table; | |
174 | + if (!sfi_mrtc_num) { | |
175 | + sfi_mrtc_num = SFI_GET_NUM_ENTRIES(sb, | |
176 | + struct sfi_rtc_table_entry); | |
177 | + pentry = (struct sfi_rtc_table_entry *)sb->pentry; | |
178 | + totallen = sfi_mrtc_num * sizeof(*pentry); | |
179 | + memcpy(sfi_mrtc_array, pentry, totallen); | |
180 | + } | |
181 | + | |
182 | + pr_debug("SFI RTC info (num = %d):\n", sfi_mrtc_num); | |
183 | + pentry = sfi_mrtc_array; | |
184 | + for (totallen = 0; totallen < sfi_mrtc_num; totallen++, pentry++) { | |
185 | + pr_debug("RTC[%d]: paddr = 0x%08x, irq = %d\n", | |
186 | + totallen, (u32)pentry->phys_addr, pentry->irq); | |
187 | + mp_irq.type = MP_INTSRC; | |
188 | + mp_irq.irqtype = mp_INT; | |
189 | + mp_irq.irqflag = 0xf; /* level trigger and active low */ | |
190 | + mp_irq.srcbus = MP_BUS_ISA; | |
191 | + mp_irq.srcbusirq = pentry->irq; /* IRQ */ | |
192 | + mp_irq.dstapic = MP_APIC_ALL; | |
193 | + mp_irq.dstirq = pentry->irq; | |
194 | + mp_save_irq(&mp_irq); | |
195 | + } | |
196 | + return 0; | |
197 | +} | |
198 | + | |
199 | +static unsigned long __init mrst_calibrate_tsc(void) | |
200 | +{ | |
201 | + unsigned long fast_calibrate; | |
202 | + u32 lo, hi, ratio, fsb; | |
203 | + | |
204 | + rdmsr(MSR_IA32_PERF_STATUS, lo, hi); | |
205 | + pr_debug("IA32 perf status is 0x%x, 0x%0x\n", lo, hi); | |
206 | + ratio = (hi >> 8) & 0x1f; | |
207 | + pr_debug("ratio is %d\n", ratio); | |
208 | + if (!ratio) { | |
209 | + pr_err("read a zero ratio, should be incorrect!\n"); | |
210 | + pr_err("force tsc ratio to 16 ...\n"); | |
211 | + ratio = 16; | |
212 | + } | |
213 | + rdmsr(MSR_FSB_FREQ, lo, hi); | |
214 | + if ((lo & 0x7) == 0x7) | |
215 | + fsb = PENWELL_FSB_FREQ_83SKU; | |
216 | + else | |
217 | + fsb = PENWELL_FSB_FREQ_100SKU; | |
218 | + fast_calibrate = ratio * fsb; | |
219 | + pr_debug("read penwell tsc %lu khz\n", fast_calibrate); | |
220 | + lapic_timer_frequency = fsb * 1000 / HZ; | |
221 | + /* mark tsc clocksource as reliable */ | |
222 | + set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE); | |
223 | + | |
224 | + if (fast_calibrate) | |
225 | + return fast_calibrate; | |
226 | + | |
227 | + return 0; | |
228 | +} | |
229 | + | |
230 | +static void __init mrst_time_init(void) | |
231 | +{ | |
232 | + sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr); | |
233 | + switch (mrst_timer_options) { | |
234 | + case MRST_TIMER_APBT_ONLY: | |
235 | + break; | |
236 | + case MRST_TIMER_LAPIC_APBT: | |
237 | + x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock; | |
238 | + x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock; | |
239 | + break; | |
240 | + default: | |
241 | + if (!boot_cpu_has(X86_FEATURE_ARAT)) | |
242 | + break; | |
243 | + x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock; | |
244 | + x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock; | |
245 | + return; | |
246 | + } | |
247 | + /* we need at least one APB timer */ | |
248 | + pre_init_apic_IRQ0(); | |
249 | + apbt_time_init(); | |
250 | +} | |
251 | + | |
252 | +static void mrst_arch_setup(void) | |
253 | +{ | |
254 | + if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27) | |
255 | + __mrst_cpu_chip = MRST_CPU_CHIP_PENWELL; | |
256 | + else { | |
257 | + pr_err("Unknown Intel MID CPU (%d:%d), default to Penwell\n", | |
258 | + boot_cpu_data.x86, boot_cpu_data.x86_model); | |
259 | + __mrst_cpu_chip = MRST_CPU_CHIP_PENWELL; | |
260 | + } | |
261 | +} | |
262 | + | |
263 | +/* MID systems don't have i8042 controller */ | |
264 | +static int mrst_i8042_detect(void) | |
265 | +{ | |
266 | + return 0; | |
267 | +} | |
268 | + | |
269 | +/* | |
270 | + * Moorestown does not have external NMI source nor port 0x61 to report | |
271 | + * NMI status. The possible NMI sources are from pmu as a result of NMI | |
272 | + * watchdog or lock debug. Reading io port 0x61 results in 0xff which | |
273 | + * misled NMI handler. | |
274 | + */ | |
275 | +static unsigned char mrst_get_nmi_reason(void) | |
276 | +{ | |
277 | + return 0; | |
278 | +} | |
279 | + | |
280 | +/* | |
281 | + * Moorestown specific x86_init function overrides and early setup | |
282 | + * calls. | |
283 | + */ | |
284 | +void __init x86_mrst_early_setup(void) | |
285 | +{ | |
286 | + x86_init.resources.probe_roms = x86_init_noop; | |
287 | + x86_init.resources.reserve_resources = x86_init_noop; | |
288 | + | |
289 | + x86_init.timers.timer_init = mrst_time_init; | |
290 | + x86_init.timers.setup_percpu_clockev = x86_init_noop; | |
291 | + | |
292 | + x86_init.irqs.pre_vector_init = x86_init_noop; | |
293 | + | |
294 | + x86_init.oem.arch_setup = mrst_arch_setup; | |
295 | + | |
296 | + x86_cpuinit.setup_percpu_clockev = apbt_setup_secondary_clock; | |
297 | + | |
298 | + x86_platform.calibrate_tsc = mrst_calibrate_tsc; | |
299 | + x86_platform.i8042_detect = mrst_i8042_detect; | |
300 | + x86_init.timers.wallclock_init = mrst_rtc_init; | |
301 | + x86_platform.get_nmi_reason = mrst_get_nmi_reason; | |
302 | + | |
303 | + x86_init.pci.init = pci_mrst_init; | |
304 | + x86_init.pci.fixup_irqs = x86_init_noop; | |
305 | + | |
306 | + legacy_pic = &null_legacy_pic; | |
307 | + | |
308 | + /* Moorestown specific power_off/restart method */ | |
309 | + pm_power_off = mrst_power_off; | |
310 | + machine_ops.emergency_restart = mrst_reboot; | |
311 | + | |
312 | + /* Avoid searching for BIOS MP tables */ | |
313 | + x86_init.mpparse.find_smp_config = x86_init_noop; | |
314 | + x86_init.mpparse.get_smp_config = x86_init_uint_noop; | |
315 | + set_bit(MP_BUS_ISA, mp_bus_not_pci); | |
316 | +} | |
317 | + | |
318 | +/* | |
319 | + * if user does not want to use per CPU apb timer, just give it a lower rating | |
320 | + * than local apic timer and skip the late per cpu timer init. | |
321 | + */ | |
322 | +static inline int __init setup_x86_mrst_timer(char *arg) | |
323 | +{ | |
324 | + if (!arg) | |
325 | + return -EINVAL; | |
326 | + | |
327 | + if (strcmp("apbt_only", arg) == 0) | |
328 | + mrst_timer_options = MRST_TIMER_APBT_ONLY; | |
329 | + else if (strcmp("lapic_and_apbt", arg) == 0) | |
330 | + mrst_timer_options = MRST_TIMER_LAPIC_APBT; | |
331 | + else { | |
332 | + pr_warn("X86 MRST timer option %s not recognised" | |
333 | + " use x86_mrst_timer=apbt_only or lapic_and_apbt\n", | |
334 | + arg); | |
335 | + return -EINVAL; | |
336 | + } | |
337 | + return 0; | |
338 | +} | |
339 | +__setup("x86_mrst_timer=", setup_x86_mrst_timer); | |
340 | + | |
341 | +/* | |
342 | + * Parsing GPIO table first, since the DEVS table will need this table | |
343 | + * to map the pin name to the actual pin. | |
344 | + */ | |
345 | +static struct sfi_gpio_table_entry *gpio_table; | |
346 | +static int gpio_num_entry; | |
347 | + | |
348 | +static int __init sfi_parse_gpio(struct sfi_table_header *table) | |
349 | +{ | |
350 | + struct sfi_table_simple *sb; | |
351 | + struct sfi_gpio_table_entry *pentry; | |
352 | + int num, i; | |
353 | + | |
354 | + if (gpio_table) | |
355 | + return 0; | |
356 | + sb = (struct sfi_table_simple *)table; | |
357 | + num = SFI_GET_NUM_ENTRIES(sb, struct sfi_gpio_table_entry); | |
358 | + pentry = (struct sfi_gpio_table_entry *)sb->pentry; | |
359 | + | |
360 | + gpio_table = kmalloc(num * sizeof(*pentry), GFP_KERNEL); | |
361 | + if (!gpio_table) | |
362 | + return -1; | |
363 | + memcpy(gpio_table, pentry, num * sizeof(*pentry)); | |
364 | + gpio_num_entry = num; | |
365 | + | |
366 | + pr_debug("GPIO pin info:\n"); | |
367 | + for (i = 0; i < num; i++, pentry++) | |
368 | + pr_debug("info[%2d]: controller = %16.16s, pin_name = %16.16s," | |
369 | + " pin = %d\n", i, | |
370 | + pentry->controller_name, | |
371 | + pentry->pin_name, | |
372 | + pentry->pin_no); | |
373 | + return 0; | |
374 | +} | |
375 | + | |
376 | +static int get_gpio_by_name(const char *name) | |
377 | +{ | |
378 | + struct sfi_gpio_table_entry *pentry = gpio_table; | |
379 | + int i; | |
380 | + | |
381 | + if (!pentry) | |
382 | + return -1; | |
383 | + for (i = 0; i < gpio_num_entry; i++, pentry++) { | |
384 | + if (!strncmp(name, pentry->pin_name, SFI_NAME_LEN)) | |
385 | + return pentry->pin_no; | |
386 | + } | |
387 | + return -1; | |
388 | +} | |
389 | + | |
390 | +/* | |
391 | + * Here defines the array of devices platform data that IAFW would export | |
392 | + * through SFI "DEVS" table, we use name and type to match the device and | |
393 | + * its platform data. | |
394 | + */ | |
395 | +struct devs_id { | |
396 | + char name[SFI_NAME_LEN + 1]; | |
397 | + u8 type; | |
398 | + u8 delay; | |
399 | + void *(*get_platform_data)(void *info); | |
400 | +}; | |
401 | + | |
402 | +/* the offset for the mapping of global gpio pin to irq */ | |
403 | +#define MRST_IRQ_OFFSET 0x100 | |
404 | + | |
405 | +static void __init *pmic_gpio_platform_data(void *info) | |
406 | +{ | |
407 | + static struct intel_pmic_gpio_platform_data pmic_gpio_pdata; | |
408 | + int gpio_base = get_gpio_by_name("pmic_gpio_base"); | |
409 | + | |
410 | + if (gpio_base == -1) | |
411 | + gpio_base = 64; | |
412 | + pmic_gpio_pdata.gpio_base = gpio_base; | |
413 | + pmic_gpio_pdata.irq_base = gpio_base + MRST_IRQ_OFFSET; | |
414 | + pmic_gpio_pdata.gpiointr = 0xffffeff8; | |
415 | + | |
416 | + return &pmic_gpio_pdata; | |
417 | +} | |
418 | + | |
419 | +static void __init *max3111_platform_data(void *info) | |
420 | +{ | |
421 | + struct spi_board_info *spi_info = info; | |
422 | + int intr = get_gpio_by_name("max3111_int"); | |
423 | + | |
424 | + spi_info->mode = SPI_MODE_0; | |
425 | + if (intr == -1) | |
426 | + return NULL; | |
427 | + spi_info->irq = intr + MRST_IRQ_OFFSET; | |
428 | + return NULL; | |
429 | +} | |
430 | + | |
431 | +/* we have multiple max7315 on the board ... */ | |
432 | +#define MAX7315_NUM 2 | |
433 | +static void __init *max7315_platform_data(void *info) | |
434 | +{ | |
435 | + static struct pca953x_platform_data max7315_pdata[MAX7315_NUM]; | |
436 | + static int nr; | |
437 | + struct pca953x_platform_data *max7315 = &max7315_pdata[nr]; | |
438 | + struct i2c_board_info *i2c_info = info; | |
439 | + int gpio_base, intr; | |
440 | + char base_pin_name[SFI_NAME_LEN + 1]; | |
441 | + char intr_pin_name[SFI_NAME_LEN + 1]; | |
442 | + | |
443 | + if (nr == MAX7315_NUM) { | |
444 | + pr_err("too many max7315s, we only support %d\n", | |
445 | + MAX7315_NUM); | |
446 | + return NULL; | |
447 | + } | |
448 | + /* we have several max7315 on the board, we only need load several | |
449 | + * instances of the same pca953x driver to cover them | |
450 | + */ | |
451 | + strcpy(i2c_info->type, "max7315"); | |
452 | + if (nr++) { | |
453 | + sprintf(base_pin_name, "max7315_%d_base", nr); | |
454 | + sprintf(intr_pin_name, "max7315_%d_int", nr); | |
455 | + } else { | |
456 | + strcpy(base_pin_name, "max7315_base"); | |
457 | + strcpy(intr_pin_name, "max7315_int"); | |
458 | + } | |
459 | + | |
460 | + gpio_base = get_gpio_by_name(base_pin_name); | |
461 | + intr = get_gpio_by_name(intr_pin_name); | |
462 | + | |
463 | + if (gpio_base == -1) | |
464 | + return NULL; | |
465 | + max7315->gpio_base = gpio_base; | |
466 | + if (intr != -1) { | |
467 | + i2c_info->irq = intr + MRST_IRQ_OFFSET; | |
468 | + max7315->irq_base = gpio_base + MRST_IRQ_OFFSET; | |
469 | + } else { | |
470 | + i2c_info->irq = -1; | |
471 | + max7315->irq_base = -1; | |
472 | + } | |
473 | + return max7315; | |
474 | +} | |
475 | + | |
476 | +static void *tca6416_platform_data(void *info) | |
477 | +{ | |
478 | + static struct pca953x_platform_data tca6416; | |
479 | + struct i2c_board_info *i2c_info = info; | |
480 | + int gpio_base, intr; | |
481 | + char base_pin_name[SFI_NAME_LEN + 1]; | |
482 | + char intr_pin_name[SFI_NAME_LEN + 1]; | |
483 | + | |
484 | + strcpy(i2c_info->type, "tca6416"); | |
485 | + strcpy(base_pin_name, "tca6416_base"); | |
486 | + strcpy(intr_pin_name, "tca6416_int"); | |
487 | + | |
488 | + gpio_base = get_gpio_by_name(base_pin_name); | |
489 | + intr = get_gpio_by_name(intr_pin_name); | |
490 | + | |
491 | + if (gpio_base == -1) | |
492 | + return NULL; | |
493 | + tca6416.gpio_base = gpio_base; | |
494 | + if (intr != -1) { | |
495 | + i2c_info->irq = intr + MRST_IRQ_OFFSET; | |
496 | + tca6416.irq_base = gpio_base + MRST_IRQ_OFFSET; | |
497 | + } else { | |
498 | + i2c_info->irq = -1; | |
499 | + tca6416.irq_base = -1; | |
500 | + } | |
501 | + return &tca6416; | |
502 | +} | |
503 | + | |
504 | +static void *mpu3050_platform_data(void *info) | |
505 | +{ | |
506 | + struct i2c_board_info *i2c_info = info; | |
507 | + int intr = get_gpio_by_name("mpu3050_int"); | |
508 | + | |
509 | + if (intr == -1) | |
510 | + return NULL; | |
511 | + | |
512 | + i2c_info->irq = intr + MRST_IRQ_OFFSET; | |
513 | + return NULL; | |
514 | +} | |
515 | + | |
516 | +static void __init *emc1403_platform_data(void *info) | |
517 | +{ | |
518 | + static short intr2nd_pdata; | |
519 | + struct i2c_board_info *i2c_info = info; | |
520 | + int intr = get_gpio_by_name("thermal_int"); | |
521 | + int intr2nd = get_gpio_by_name("thermal_alert"); | |
522 | + | |
523 | + if (intr == -1 || intr2nd == -1) | |
524 | + return NULL; | |
525 | + | |
526 | + i2c_info->irq = intr + MRST_IRQ_OFFSET; | |
527 | + intr2nd_pdata = intr2nd + MRST_IRQ_OFFSET; | |
528 | + | |
529 | + return &intr2nd_pdata; | |
530 | +} | |
531 | + | |
532 | +static void __init *lis331dl_platform_data(void *info) | |
533 | +{ | |
534 | + static short intr2nd_pdata; | |
535 | + struct i2c_board_info *i2c_info = info; | |
536 | + int intr = get_gpio_by_name("accel_int"); | |
537 | + int intr2nd = get_gpio_by_name("accel_2"); | |
538 | + | |
539 | + if (intr == -1 || intr2nd == -1) | |
540 | + return NULL; | |
541 | + | |
542 | + i2c_info->irq = intr + MRST_IRQ_OFFSET; | |
543 | + intr2nd_pdata = intr2nd + MRST_IRQ_OFFSET; | |
544 | + | |
545 | + return &intr2nd_pdata; | |
546 | +} | |
547 | + | |
548 | +static void __init *no_platform_data(void *info) | |
549 | +{ | |
550 | + return NULL; | |
551 | +} | |
552 | + | |
553 | +static struct resource msic_resources[] = { | |
554 | + { | |
555 | + .start = INTEL_MSIC_IRQ_PHYS_BASE, | |
556 | + .end = INTEL_MSIC_IRQ_PHYS_BASE + 64 - 1, | |
557 | + .flags = IORESOURCE_MEM, | |
558 | + }, | |
559 | +}; | |
560 | + | |
561 | +static struct intel_msic_platform_data msic_pdata; | |
562 | + | |
563 | +static struct platform_device msic_device = { | |
564 | + .name = "intel_msic", | |
565 | + .id = -1, | |
566 | + .dev = { | |
567 | + .platform_data = &msic_pdata, | |
568 | + }, | |
569 | + .num_resources = ARRAY_SIZE(msic_resources), | |
570 | + .resource = msic_resources, | |
571 | +}; | |
572 | + | |
573 | +static inline bool mrst_has_msic(void) | |
574 | +{ | |
575 | + return mrst_identify_cpu() == MRST_CPU_CHIP_PENWELL; | |
576 | +} | |
577 | + | |
578 | +static int msic_scu_status_change(struct notifier_block *nb, | |
579 | + unsigned long code, void *data) | |
580 | +{ | |
581 | + if (code == SCU_DOWN) { | |
582 | + platform_device_unregister(&msic_device); | |
583 | + return 0; | |
584 | + } | |
585 | + | |
586 | + return platform_device_register(&msic_device); | |
587 | +} | |
588 | + | |
589 | +static int __init msic_init(void) | |
590 | +{ | |
591 | + static struct notifier_block msic_scu_notifier = { | |
592 | + .notifier_call = msic_scu_status_change, | |
593 | + }; | |
594 | + | |
595 | + /* | |
596 | + * We need to be sure that the SCU IPC is ready before MSIC device | |
597 | + * can be registered. | |
598 | + */ | |
599 | + if (mrst_has_msic()) | |
600 | + intel_scu_notifier_add(&msic_scu_notifier); | |
601 | + | |
602 | + return 0; | |
603 | +} | |
604 | +arch_initcall(msic_init); | |
605 | + | |
606 | +/* | |
607 | + * msic_generic_platform_data - sets generic platform data for the block | |
608 | + * @info: pointer to the SFI device table entry for this block | |
609 | + * @block: MSIC block | |
610 | + * | |
611 | + * Function sets IRQ number from the SFI table entry for given device to | |
612 | + * the MSIC platform data. | |
613 | + */ | |
614 | +static void *msic_generic_platform_data(void *info, enum intel_msic_block block) | |
615 | +{ | |
616 | + struct sfi_device_table_entry *entry = info; | |
617 | + | |
618 | + BUG_ON(block < 0 || block >= INTEL_MSIC_BLOCK_LAST); | |
619 | + msic_pdata.irq[block] = entry->irq; | |
620 | + | |
621 | + return no_platform_data(info); | |
622 | +} | |
623 | + | |
624 | +static void *msic_battery_platform_data(void *info) | |
625 | +{ | |
626 | + return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_BATTERY); | |
627 | +} | |
628 | + | |
629 | +static void *msic_gpio_platform_data(void *info) | |
630 | +{ | |
631 | + static struct intel_msic_gpio_pdata pdata; | |
632 | + int gpio = get_gpio_by_name("msic_gpio_base"); | |
633 | + | |
634 | + if (gpio < 0) | |
635 | + return NULL; | |
636 | + | |
637 | + pdata.gpio_base = gpio; | |
638 | + msic_pdata.gpio = &pdata; | |
639 | + | |
640 | + return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_GPIO); | |
641 | +} | |
642 | + | |
643 | +static void *msic_audio_platform_data(void *info) | |
644 | +{ | |
645 | + struct platform_device *pdev; | |
646 | + | |
647 | + pdev = platform_device_register_simple("sst-platform", -1, NULL, 0); | |
648 | + if (IS_ERR(pdev)) { | |
649 | + pr_err("failed to create audio platform device\n"); | |
650 | + return NULL; | |
651 | + } | |
652 | + | |
653 | + return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_AUDIO); | |
654 | +} | |
655 | + | |
656 | +static void *msic_power_btn_platform_data(void *info) | |
657 | +{ | |
658 | + return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_POWER_BTN); | |
659 | +} | |
660 | + | |
661 | +static void *msic_ocd_platform_data(void *info) | |
662 | +{ | |
663 | + static struct intel_msic_ocd_pdata pdata; | |
664 | + int gpio = get_gpio_by_name("ocd_gpio"); | |
665 | + | |
666 | + if (gpio < 0) | |
667 | + return NULL; | |
668 | + | |
669 | + pdata.gpio = gpio; | |
670 | + msic_pdata.ocd = &pdata; | |
671 | + | |
672 | + return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_OCD); | |
673 | +} | |
674 | + | |
675 | +static void *msic_thermal_platform_data(void *info) | |
676 | +{ | |
677 | + return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_THERMAL); | |
678 | +} | |
679 | + | |
680 | +/* tc35876x DSI-LVDS bridge chip and panel platform data */ | |
681 | +static void *tc35876x_platform_data(void *data) | |
682 | +{ | |
683 | + static struct tc35876x_platform_data pdata; | |
684 | + | |
685 | + /* gpio pins set to -1 will not be used by the driver */ | |
686 | + pdata.gpio_bridge_reset = get_gpio_by_name("LCMB_RXEN"); | |
687 | + pdata.gpio_panel_bl_en = get_gpio_by_name("6S6P_BL_EN"); | |
688 | + pdata.gpio_panel_vadd = get_gpio_by_name("EN_VREG_LCD_V3P3"); | |
689 | + | |
690 | + return &pdata; | |
691 | +} | |
692 | + | |
693 | +static const struct devs_id __initconst device_ids[] = { | |
694 | + {"bma023", SFI_DEV_TYPE_I2C, 1, &no_platform_data}, | |
695 | + {"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data}, | |
696 | + {"pmic_gpio", SFI_DEV_TYPE_IPC, 1, &pmic_gpio_platform_data}, | |
697 | + {"spi_max3111", SFI_DEV_TYPE_SPI, 0, &max3111_platform_data}, | |
698 | + {"i2c_max7315", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data}, | |
699 | + {"i2c_max7315_2", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data}, | |
700 | + {"tca6416", SFI_DEV_TYPE_I2C, 1, &tca6416_platform_data}, | |
701 | + {"emc1403", SFI_DEV_TYPE_I2C, 1, &emc1403_platform_data}, | |
702 | + {"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data}, | |
703 | + {"pmic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data}, | |
704 | + {"mpu3050", SFI_DEV_TYPE_I2C, 1, &mpu3050_platform_data}, | |
705 | + {"i2c_disp_brig", SFI_DEV_TYPE_I2C, 0, &tc35876x_platform_data}, | |
706 | + | |
707 | + /* MSIC subdevices */ | |
708 | + {"msic_battery", SFI_DEV_TYPE_IPC, 1, &msic_battery_platform_data}, | |
709 | + {"msic_gpio", SFI_DEV_TYPE_IPC, 1, &msic_gpio_platform_data}, | |
710 | + {"msic_audio", SFI_DEV_TYPE_IPC, 1, &msic_audio_platform_data}, | |
711 | + {"msic_power_btn", SFI_DEV_TYPE_IPC, 1, &msic_power_btn_platform_data}, | |
712 | + {"msic_ocd", SFI_DEV_TYPE_IPC, 1, &msic_ocd_platform_data}, | |
713 | + {"msic_thermal", SFI_DEV_TYPE_IPC, 1, &msic_thermal_platform_data}, | |
714 | + | |
715 | + {}, | |
716 | +}; | |
717 | + | |
718 | +#define MAX_IPCDEVS 24 | |
719 | +static struct platform_device *ipc_devs[MAX_IPCDEVS]; | |
720 | +static int ipc_next_dev; | |
721 | + | |
722 | +#define MAX_SCU_SPI 24 | |
723 | +static struct spi_board_info *spi_devs[MAX_SCU_SPI]; | |
724 | +static int spi_next_dev; | |
725 | + | |
726 | +#define MAX_SCU_I2C 24 | |
727 | +static struct i2c_board_info *i2c_devs[MAX_SCU_I2C]; | |
728 | +static int i2c_bus[MAX_SCU_I2C]; | |
729 | +static int i2c_next_dev; | |
730 | + | |
731 | +static void __init intel_scu_device_register(struct platform_device *pdev) | |
732 | +{ | |
733 | + if (ipc_next_dev == MAX_IPCDEVS) | |
734 | + pr_err("too many SCU IPC devices"); | |
735 | + else | |
736 | + ipc_devs[ipc_next_dev++] = pdev; | |
737 | +} | |
738 | + | |
739 | +static void __init intel_scu_spi_device_register(struct spi_board_info *sdev) | |
740 | +{ | |
741 | + struct spi_board_info *new_dev; | |
742 | + | |
743 | + if (spi_next_dev == MAX_SCU_SPI) { | |
744 | + pr_err("too many SCU SPI devices"); | |
745 | + return; | |
746 | + } | |
747 | + | |
748 | + new_dev = kzalloc(sizeof(*sdev), GFP_KERNEL); | |
749 | + if (!new_dev) { | |
750 | + pr_err("failed to alloc mem for delayed spi dev %s\n", | |
751 | + sdev->modalias); | |
752 | + return; | |
753 | + } | |
754 | + memcpy(new_dev, sdev, sizeof(*sdev)); | |
755 | + | |
756 | + spi_devs[spi_next_dev++] = new_dev; | |
757 | +} | |
758 | + | |
759 | +static void __init intel_scu_i2c_device_register(int bus, | |
760 | + struct i2c_board_info *idev) | |
761 | +{ | |
762 | + struct i2c_board_info *new_dev; | |
763 | + | |
764 | + if (i2c_next_dev == MAX_SCU_I2C) { | |
765 | + pr_err("too many SCU I2C devices"); | |
766 | + return; | |
767 | + } | |
768 | + | |
769 | + new_dev = kzalloc(sizeof(*idev), GFP_KERNEL); | |
770 | + if (!new_dev) { | |
771 | + pr_err("failed to alloc mem for delayed i2c dev %s\n", | |
772 | + idev->type); | |
773 | + return; | |
774 | + } | |
775 | + memcpy(new_dev, idev, sizeof(*idev)); | |
776 | + | |
777 | + i2c_bus[i2c_next_dev] = bus; | |
778 | + i2c_devs[i2c_next_dev++] = new_dev; | |
779 | +} | |
780 | + | |
781 | +BLOCKING_NOTIFIER_HEAD(intel_scu_notifier); | |
782 | +EXPORT_SYMBOL_GPL(intel_scu_notifier); | |
783 | + | |
784 | +/* Called by IPC driver */ | |
785 | +void intel_scu_devices_create(void) | |
786 | +{ | |
787 | + int i; | |
788 | + | |
789 | + for (i = 0; i < ipc_next_dev; i++) | |
790 | + platform_device_add(ipc_devs[i]); | |
791 | + | |
792 | + for (i = 0; i < spi_next_dev; i++) | |
793 | + spi_register_board_info(spi_devs[i], 1); | |
794 | + | |
795 | + for (i = 0; i < i2c_next_dev; i++) { | |
796 | + struct i2c_adapter *adapter; | |
797 | + struct i2c_client *client; | |
798 | + | |
799 | + adapter = i2c_get_adapter(i2c_bus[i]); | |
800 | + if (adapter) { | |
801 | + client = i2c_new_device(adapter, i2c_devs[i]); | |
802 | + if (!client) | |
803 | + pr_err("can't create i2c device %s\n", | |
804 | + i2c_devs[i]->type); | |
805 | + } else | |
806 | + i2c_register_board_info(i2c_bus[i], i2c_devs[i], 1); | |
807 | + } | |
808 | + intel_scu_notifier_post(SCU_AVAILABLE, NULL); | |
809 | +} | |
810 | +EXPORT_SYMBOL_GPL(intel_scu_devices_create); | |
811 | + | |
812 | +/* Called by IPC driver */ | |
813 | +void intel_scu_devices_destroy(void) | |
814 | +{ | |
815 | + int i; | |
816 | + | |
817 | + intel_scu_notifier_post(SCU_DOWN, NULL); | |
818 | + | |
819 | + for (i = 0; i < ipc_next_dev; i++) | |
820 | + platform_device_del(ipc_devs[i]); | |
821 | +} | |
822 | +EXPORT_SYMBOL_GPL(intel_scu_devices_destroy); | |
823 | + | |
824 | +static void __init install_irq_resource(struct platform_device *pdev, int irq) | |
825 | +{ | |
826 | + /* Single threaded */ | |
827 | + static struct resource __initdata res = { | |
828 | + .name = "IRQ", | |
829 | + .flags = IORESOURCE_IRQ, | |
830 | + }; | |
831 | + res.start = irq; | |
832 | + platform_device_add_resources(pdev, &res, 1); | |
833 | +} | |
834 | + | |
835 | +static void __init sfi_handle_ipc_dev(struct sfi_device_table_entry *entry) | |
836 | +{ | |
837 | + const struct devs_id *dev = device_ids; | |
838 | + struct platform_device *pdev; | |
839 | + void *pdata = NULL; | |
840 | + | |
841 | + while (dev->name[0]) { | |
842 | + if (dev->type == SFI_DEV_TYPE_IPC && | |
843 | + !strncmp(dev->name, entry->name, SFI_NAME_LEN)) { | |
844 | + pdata = dev->get_platform_data(entry); | |
845 | + break; | |
846 | + } | |
847 | + dev++; | |
848 | + } | |
849 | + | |
850 | + /* | |
851 | + * On Medfield the platform device creation is handled by the MSIC | |
852 | + * MFD driver so we don't need to do it here. | |
853 | + */ | |
854 | + if (mrst_has_msic()) | |
855 | + return; | |
856 | + | |
857 | + pdev = platform_device_alloc(entry->name, 0); | |
858 | + if (pdev == NULL) { | |
859 | + pr_err("out of memory for SFI platform device '%s'.\n", | |
860 | + entry->name); | |
861 | + return; | |
862 | + } | |
863 | + install_irq_resource(pdev, entry->irq); | |
864 | + | |
865 | + pdev->dev.platform_data = pdata; | |
866 | + intel_scu_device_register(pdev); | |
867 | +} | |
868 | + | |
869 | +static void __init sfi_handle_spi_dev(struct spi_board_info *spi_info) | |
870 | +{ | |
871 | + const struct devs_id *dev = device_ids; | |
872 | + void *pdata = NULL; | |
873 | + | |
874 | + while (dev->name[0]) { | |
875 | + if (dev->type == SFI_DEV_TYPE_SPI && | |
876 | + !strncmp(dev->name, spi_info->modalias, | |
877 | + SFI_NAME_LEN)) { | |
878 | + pdata = dev->get_platform_data(spi_info); | |
879 | + break; | |
880 | + } | |
881 | + dev++; | |
882 | + } | |
883 | + spi_info->platform_data = pdata; | |
884 | + if (dev->delay) | |
885 | + intel_scu_spi_device_register(spi_info); | |
886 | + else | |
887 | + spi_register_board_info(spi_info, 1); | |
888 | +} | |
889 | + | |
890 | +static void __init sfi_handle_i2c_dev(int bus, struct i2c_board_info *i2c_info) | |
891 | +{ | |
892 | + const struct devs_id *dev = device_ids; | |
893 | + void *pdata = NULL; | |
894 | + | |
895 | + while (dev->name[0]) { | |
896 | + if (dev->type == SFI_DEV_TYPE_I2C && | |
897 | + !strncmp(dev->name, i2c_info->type, SFI_NAME_LEN)) { | |
898 | + pdata = dev->get_platform_data(i2c_info); | |
899 | + break; | |
900 | + } | |
901 | + dev++; | |
902 | + } | |
903 | + i2c_info->platform_data = pdata; | |
904 | + | |
905 | + if (dev->delay) | |
906 | + intel_scu_i2c_device_register(bus, i2c_info); | |
907 | + else | |
908 | + i2c_register_board_info(bus, i2c_info, 1); | |
909 | +} | |
910 | + | |
911 | + | |
912 | +static int __init sfi_parse_devs(struct sfi_table_header *table) | |
913 | +{ | |
914 | + struct sfi_table_simple *sb; | |
915 | + struct sfi_device_table_entry *pentry; | |
916 | + struct spi_board_info spi_info; | |
917 | + struct i2c_board_info i2c_info; | |
918 | + int num, i, bus; | |
919 | + int ioapic; | |
920 | + struct io_apic_irq_attr irq_attr; | |
921 | + | |
922 | + sb = (struct sfi_table_simple *)table; | |
923 | + num = SFI_GET_NUM_ENTRIES(sb, struct sfi_device_table_entry); | |
924 | + pentry = (struct sfi_device_table_entry *)sb->pentry; | |
925 | + | |
926 | + for (i = 0; i < num; i++, pentry++) { | |
927 | + int irq = pentry->irq; | |
928 | + | |
929 | + if (irq != (u8)0xff) { /* native RTE case */ | |
930 | + /* these SPI2 devices are not exposed to system as PCI | |
931 | + * devices, but they have separate RTE entry in IOAPIC | |
932 | + * so we have to enable them one by one here | |
933 | + */ | |
934 | + ioapic = mp_find_ioapic(irq); | |
935 | + irq_attr.ioapic = ioapic; | |
936 | + irq_attr.ioapic_pin = irq; | |
937 | + irq_attr.trigger = 1; | |
938 | + irq_attr.polarity = 1; | |
939 | + io_apic_set_pci_routing(NULL, irq, &irq_attr); | |
940 | + } else | |
941 | + irq = 0; /* No irq */ | |
942 | + | |
943 | + switch (pentry->type) { | |
944 | + case SFI_DEV_TYPE_IPC: | |
945 | + pr_debug("info[%2d]: IPC bus, name = %16.16s, " | |
946 | + "irq = 0x%2x\n", i, pentry->name, pentry->irq); | |
947 | + sfi_handle_ipc_dev(pentry); | |
948 | + break; | |
949 | + case SFI_DEV_TYPE_SPI: | |
950 | + memset(&spi_info, 0, sizeof(spi_info)); | |
951 | + strncpy(spi_info.modalias, pentry->name, SFI_NAME_LEN); | |
952 | + spi_info.irq = irq; | |
953 | + spi_info.bus_num = pentry->host_num; | |
954 | + spi_info.chip_select = pentry->addr; | |
955 | + spi_info.max_speed_hz = pentry->max_freq; | |
956 | + pr_debug("info[%2d]: SPI bus = %d, name = %16.16s, " | |
957 | + "irq = 0x%2x, max_freq = %d, cs = %d\n", i, | |
958 | + spi_info.bus_num, | |
959 | + spi_info.modalias, | |
960 | + spi_info.irq, | |
961 | + spi_info.max_speed_hz, | |
962 | + spi_info.chip_select); | |
963 | + sfi_handle_spi_dev(&spi_info); | |
964 | + break; | |
965 | + case SFI_DEV_TYPE_I2C: | |
966 | + memset(&i2c_info, 0, sizeof(i2c_info)); | |
967 | + bus = pentry->host_num; | |
968 | + strncpy(i2c_info.type, pentry->name, SFI_NAME_LEN); | |
969 | + i2c_info.irq = irq; | |
970 | + i2c_info.addr = pentry->addr; | |
971 | + pr_debug("info[%2d]: I2C bus = %d, name = %16.16s, " | |
972 | + "irq = 0x%2x, addr = 0x%x\n", i, bus, | |
973 | + i2c_info.type, | |
974 | + i2c_info.irq, | |
975 | + i2c_info.addr); | |
976 | + sfi_handle_i2c_dev(bus, &i2c_info); | |
977 | + break; | |
978 | + case SFI_DEV_TYPE_UART: | |
979 | + case SFI_DEV_TYPE_HSI: | |
980 | + default: | |
981 | + ; | |
982 | + } | |
983 | + } | |
984 | + return 0; | |
985 | +} | |
986 | + | |
987 | +static int __init mrst_platform_init(void) | |
988 | +{ | |
989 | + sfi_table_parse(SFI_SIG_GPIO, NULL, NULL, sfi_parse_gpio); | |
990 | + sfi_table_parse(SFI_SIG_DEVS, NULL, NULL, sfi_parse_devs); | |
991 | + return 0; | |
992 | +} | |
993 | +arch_initcall(mrst_platform_init); | |
994 | + | |
995 | +/* | |
996 | + * we will search these buttons in SFI GPIO table (by name) | |
997 | + * and register them dynamically. Please add all possible | |
998 | + * buttons here, we will shrink them if no GPIO found. | |
999 | + */ | |
1000 | +static struct gpio_keys_button gpio_button[] = { | |
1001 | + {KEY_POWER, -1, 1, "power_btn", EV_KEY, 0, 3000}, | |
1002 | + {KEY_PROG1, -1, 1, "prog_btn1", EV_KEY, 0, 20}, | |
1003 | + {KEY_PROG2, -1, 1, "prog_btn2", EV_KEY, 0, 20}, | |
1004 | + {SW_LID, -1, 1, "lid_switch", EV_SW, 0, 20}, | |
1005 | + {KEY_VOLUMEUP, -1, 1, "vol_up", EV_KEY, 0, 20}, | |
1006 | + {KEY_VOLUMEDOWN, -1, 1, "vol_down", EV_KEY, 0, 20}, | |
1007 | + {KEY_CAMERA, -1, 1, "camera_full", EV_KEY, 0, 20}, | |
1008 | + {KEY_CAMERA_FOCUS, -1, 1, "camera_half", EV_KEY, 0, 20}, | |
1009 | + {SW_KEYPAD_SLIDE, -1, 1, "MagSw1", EV_SW, 0, 20}, | |
1010 | + {SW_KEYPAD_SLIDE, -1, 1, "MagSw2", EV_SW, 0, 20}, | |
1011 | +}; | |
1012 | + | |
1013 | +static struct gpio_keys_platform_data mrst_gpio_keys = { | |
1014 | + .buttons = gpio_button, | |
1015 | + .rep = 1, | |
1016 | + .nbuttons = -1, /* will fill it after search */ | |
1017 | +}; | |
1018 | + | |
1019 | +static struct platform_device pb_device = { | |
1020 | + .name = "gpio-keys", | |
1021 | + .id = -1, | |
1022 | + .dev = { | |
1023 | + .platform_data = &mrst_gpio_keys, | |
1024 | + }, | |
1025 | +}; | |
1026 | + | |
1027 | +/* | |
1028 | + * Shrink the non-existent buttons, register the gpio button | |
1029 | + * device if there is some | |
1030 | + */ | |
1031 | +static int __init pb_keys_init(void) | |
1032 | +{ | |
1033 | + struct gpio_keys_button *gb = gpio_button; | |
1034 | + int i, num, good = 0; | |
1035 | + | |
1036 | + num = sizeof(gpio_button) / sizeof(struct gpio_keys_button); | |
1037 | + for (i = 0; i < num; i++) { | |
1038 | + gb[i].gpio = get_gpio_by_name(gb[i].desc); | |
1039 | + pr_debug("info[%2d]: name = %s, gpio = %d\n", i, gb[i].desc, | |
1040 | + gb[i].gpio); | |
1041 | + if (gb[i].gpio == -1) | |
1042 | + continue; | |
1043 | + | |
1044 | + if (i != good) | |
1045 | + gb[good] = gb[i]; | |
1046 | + good++; | |
1047 | + } | |
1048 | + | |
1049 | + if (good) { | |
1050 | + mrst_gpio_keys.nbuttons = good; | |
1051 | + return platform_device_register(&pb_device); | |
1052 | + } | |
1053 | + return 0; | |
1054 | +} | |
1055 | +late_initcall(pb_keys_init); |
arch/x86/platform/intel-mid/intel_mid_vrtc.c
1 | +/* | |
2 | + * intel_mid_vrtc.c: Driver for virtual RTC device on Intel MID platform | |
3 | + * | |
4 | + * (C) Copyright 2009 Intel Corporation | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or | |
7 | + * modify it under the terms of the GNU General Public License | |
8 | + * as published by the Free Software Foundation; version 2 | |
9 | + * of the License. | |
10 | + * | |
11 | + * Note: | |
12 | + * VRTC is emulated by system controller firmware, the real HW | |
13 | + * RTC is located in the PMIC device. SCU FW shadows PMIC RTC | |
14 | + * in a memory mapped IO space that is visible to the host IA | |
15 | + * processor. | |
16 | + * | |
17 | + * This driver is based on RTC CMOS driver. | |
18 | + */ | |
19 | + | |
20 | +#include <linux/kernel.h> | |
21 | +#include <linux/export.h> | |
22 | +#include <linux/init.h> | |
23 | +#include <linux/sfi.h> | |
24 | +#include <linux/platform_device.h> | |
25 | + | |
26 | +#include <asm/intel-mid.h> | |
27 | +#include <asm/intel_mid_vrtc.h> | |
28 | +#include <asm/time.h> | |
29 | +#include <asm/fixmap.h> | |
30 | + | |
31 | +static unsigned char __iomem *vrtc_virt_base; | |
32 | + | |
33 | +unsigned char vrtc_cmos_read(unsigned char reg) | |
34 | +{ | |
35 | + unsigned char retval; | |
36 | + | |
37 | + /* vRTC's registers range from 0x0 to 0xD */ | |
38 | + if (reg > 0xd || !vrtc_virt_base) | |
39 | + return 0xff; | |
40 | + | |
41 | + lock_cmos_prefix(reg); | |
42 | + retval = __raw_readb(vrtc_virt_base + (reg << 2)); | |
43 | + lock_cmos_suffix(reg); | |
44 | + return retval; | |
45 | +} | |
46 | +EXPORT_SYMBOL_GPL(vrtc_cmos_read); | |
47 | + | |
48 | +void vrtc_cmos_write(unsigned char val, unsigned char reg) | |
49 | +{ | |
50 | + if (reg > 0xd || !vrtc_virt_base) | |
51 | + return; | |
52 | + | |
53 | + lock_cmos_prefix(reg); | |
54 | + __raw_writeb(val, vrtc_virt_base + (reg << 2)); | |
55 | + lock_cmos_suffix(reg); | |
56 | +} | |
57 | +EXPORT_SYMBOL_GPL(vrtc_cmos_write); | |
58 | + | |
59 | +void vrtc_get_time(struct timespec *now) | |
60 | +{ | |
61 | + u8 sec, min, hour, mday, mon; | |
62 | + unsigned long flags; | |
63 | + u32 year; | |
64 | + | |
65 | + spin_lock_irqsave(&rtc_lock, flags); | |
66 | + | |
67 | + while ((vrtc_cmos_read(RTC_FREQ_SELECT) & RTC_UIP)) | |
68 | + cpu_relax(); | |
69 | + | |
70 | + sec = vrtc_cmos_read(RTC_SECONDS); | |
71 | + min = vrtc_cmos_read(RTC_MINUTES); | |
72 | + hour = vrtc_cmos_read(RTC_HOURS); | |
73 | + mday = vrtc_cmos_read(RTC_DAY_OF_MONTH); | |
74 | + mon = vrtc_cmos_read(RTC_MONTH); | |
75 | + year = vrtc_cmos_read(RTC_YEAR); | |
76 | + | |
77 | + spin_unlock_irqrestore(&rtc_lock, flags); | |
78 | + | |
79 | + /* vRTC YEAR reg contains the offset to 1972 */ | |
80 | + year += 1972; | |
81 | + | |
82 | + pr_info("vRTC: sec: %d min: %d hour: %d day: %d " | |
83 | + "mon: %d year: %d\n", sec, min, hour, mday, mon, year); | |
84 | + | |
85 | + now->tv_sec = mktime(year, mon, mday, hour, min, sec); | |
86 | + now->tv_nsec = 0; | |
87 | +} | |
88 | + | |
89 | +int vrtc_set_mmss(const struct timespec *now) | |
90 | +{ | |
91 | + unsigned long flags; | |
92 | + struct rtc_time tm; | |
93 | + int year; | |
94 | + int retval = 0; | |
95 | + | |
96 | + rtc_time_to_tm(now->tv_sec, &tm); | |
97 | + if (!rtc_valid_tm(&tm) && tm.tm_year >= 72) { | |
98 | + /* | |
99 | + * tm.year is the number of years since 1900, and the | |
100 | + * vrtc need the years since 1972. | |
101 | + */ | |
102 | + year = tm.tm_year - 72; | |
103 | + spin_lock_irqsave(&rtc_lock, flags); | |
104 | + vrtc_cmos_write(year, RTC_YEAR); | |
105 | + vrtc_cmos_write(tm.tm_mon, RTC_MONTH); | |
106 | + vrtc_cmos_write(tm.tm_mday, RTC_DAY_OF_MONTH); | |
107 | + vrtc_cmos_write(tm.tm_hour, RTC_HOURS); | |
108 | + vrtc_cmos_write(tm.tm_min, RTC_MINUTES); | |
109 | + vrtc_cmos_write(tm.tm_sec, RTC_SECONDS); | |
110 | + spin_unlock_irqrestore(&rtc_lock, flags); | |
111 | + } else { | |
112 | + pr_err("%s: Invalid vRTC value: write of %lx to vRTC failed\n", | |
113 | + __FUNCTION__, now->tv_sec); | |
114 | + retval = -EINVAL; | |
115 | + } | |
116 | + return retval; | |
117 | +} | |
118 | + | |
119 | +void __init mrst_rtc_init(void) | |
120 | +{ | |
121 | + unsigned long vrtc_paddr; | |
122 | + | |
123 | + sfi_table_parse(SFI_SIG_MRTC, NULL, NULL, sfi_parse_mrtc); | |
124 | + | |
125 | + vrtc_paddr = sfi_mrtc_array[0].phys_addr; | |
126 | + if (!sfi_mrtc_num || !vrtc_paddr) | |
127 | + return; | |
128 | + | |
129 | + vrtc_virt_base = (void __iomem *)set_fixmap_offset_nocache(FIX_LNW_VRTC, | |
130 | + vrtc_paddr); | |
131 | + x86_platform.get_wallclock = vrtc_get_time; | |
132 | + x86_platform.set_wallclock = vrtc_set_mmss; | |
133 | +} | |
134 | + | |
135 | +/* | |
136 | + * The Moorestown platform has a memory mapped virtual RTC device that emulates | |
137 | + * the programming interface of the RTC. | |
138 | + */ | |
139 | + | |
140 | +static struct resource vrtc_resources[] = { | |
141 | + [0] = { | |
142 | + .flags = IORESOURCE_MEM, | |
143 | + }, | |
144 | + [1] = { | |
145 | + .flags = IORESOURCE_IRQ, | |
146 | + } | |
147 | +}; | |
148 | + | |
149 | +static struct platform_device vrtc_device = { | |
150 | + .name = "rtc_mrst", | |
151 | + .id = -1, | |
152 | + .resource = vrtc_resources, | |
153 | + .num_resources = ARRAY_SIZE(vrtc_resources), | |
154 | +}; | |
155 | + | |
156 | +/* Register the RTC device if appropriate */ | |
157 | +static int __init mrst_device_create(void) | |
158 | +{ | |
159 | + /* No Moorestown, no device */ | |
160 | + if (!mrst_identify_cpu()) | |
161 | + return -ENODEV; | |
162 | + /* No timer, no device */ | |
163 | + if (!sfi_mrtc_num) | |
164 | + return -ENODEV; | |
165 | + | |
166 | + /* iomem resource */ | |
167 | + vrtc_resources[0].start = sfi_mrtc_array[0].phys_addr; | |
168 | + vrtc_resources[0].end = sfi_mrtc_array[0].phys_addr + | |
169 | + MRST_VRTC_MAP_SZ; | |
170 | + /* irq resource */ | |
171 | + vrtc_resources[1].start = sfi_mrtc_array[0].irq; | |
172 | + vrtc_resources[1].end = sfi_mrtc_array[0].irq; | |
173 | + | |
174 | + return platform_device_register(&vrtc_device); | |
175 | +} | |
176 | + | |
177 | +module_init(mrst_device_create); |
arch/x86/platform/mrst/Makefile
arch/x86/platform/mrst/early_printk_mrst.c
1 | -/* | |
2 | - * early_printk_mrst.c - early consoles for Intel MID platforms | |
3 | - * | |
4 | - * Copyright (c) 2008-2010, Intel Corporation | |
5 | - * | |
6 | - * This program is free software; you can redistribute it and/or | |
7 | - * modify it under the terms of the GNU General Public License | |
8 | - * as published by the Free Software Foundation; version 2 | |
9 | - * of the License. | |
10 | - */ | |
11 | - | |
12 | -/* | |
13 | - * This file implements two early consoles named mrst and hsu. | |
14 | - * mrst is based on Maxim3110 spi-uart device, it exists in both | |
15 | - * Moorestown and Medfield platforms, while hsu is based on a High | |
16 | - * Speed UART device which only exists in the Medfield platform | |
17 | - */ | |
18 | - | |
19 | -#include <linux/serial_reg.h> | |
20 | -#include <linux/serial_mfd.h> | |
21 | -#include <linux/kmsg_dump.h> | |
22 | -#include <linux/console.h> | |
23 | -#include <linux/kernel.h> | |
24 | -#include <linux/delay.h> | |
25 | -#include <linux/init.h> | |
26 | -#include <linux/io.h> | |
27 | - | |
28 | -#include <asm/fixmap.h> | |
29 | -#include <asm/pgtable.h> | |
30 | -#include <asm/mrst.h> | |
31 | - | |
32 | -#define MRST_SPI_TIMEOUT 0x200000 | |
33 | -#define MRST_REGBASE_SPI0 0xff128000 | |
34 | -#define MRST_REGBASE_SPI1 0xff128400 | |
35 | -#define MRST_CLK_SPI0_REG 0xff11d86c | |
36 | - | |
37 | -/* Bit fields in CTRLR0 */ | |
38 | -#define SPI_DFS_OFFSET 0 | |
39 | - | |
40 | -#define SPI_FRF_OFFSET 4 | |
41 | -#define SPI_FRF_SPI 0x0 | |
42 | -#define SPI_FRF_SSP 0x1 | |
43 | -#define SPI_FRF_MICROWIRE 0x2 | |
44 | -#define SPI_FRF_RESV 0x3 | |
45 | - | |
46 | -#define SPI_MODE_OFFSET 6 | |
47 | -#define SPI_SCPH_OFFSET 6 | |
48 | -#define SPI_SCOL_OFFSET 7 | |
49 | -#define SPI_TMOD_OFFSET 8 | |
50 | -#define SPI_TMOD_TR 0x0 /* xmit & recv */ | |
51 | -#define SPI_TMOD_TO 0x1 /* xmit only */ | |
52 | -#define SPI_TMOD_RO 0x2 /* recv only */ | |
53 | -#define SPI_TMOD_EPROMREAD 0x3 /* eeprom read mode */ | |
54 | - | |
55 | -#define SPI_SLVOE_OFFSET 10 | |
56 | -#define SPI_SRL_OFFSET 11 | |
57 | -#define SPI_CFS_OFFSET 12 | |
58 | - | |
59 | -/* Bit fields in SR, 7 bits */ | |
60 | -#define SR_MASK 0x7f /* cover 7 bits */ | |
61 | -#define SR_BUSY (1 << 0) | |
62 | -#define SR_TF_NOT_FULL (1 << 1) | |
63 | -#define SR_TF_EMPT (1 << 2) | |
64 | -#define SR_RF_NOT_EMPT (1 << 3) | |
65 | -#define SR_RF_FULL (1 << 4) | |
66 | -#define SR_TX_ERR (1 << 5) | |
67 | -#define SR_DCOL (1 << 6) | |
68 | - | |
69 | -struct dw_spi_reg { | |
70 | - u32 ctrl0; | |
71 | - u32 ctrl1; | |
72 | - u32 ssienr; | |
73 | - u32 mwcr; | |
74 | - u32 ser; | |
75 | - u32 baudr; | |
76 | - u32 txfltr; | |
77 | - u32 rxfltr; | |
78 | - u32 txflr; | |
79 | - u32 rxflr; | |
80 | - u32 sr; | |
81 | - u32 imr; | |
82 | - u32 isr; | |
83 | - u32 risr; | |
84 | - u32 txoicr; | |
85 | - u32 rxoicr; | |
86 | - u32 rxuicr; | |
87 | - u32 msticr; | |
88 | - u32 icr; | |
89 | - u32 dmacr; | |
90 | - u32 dmatdlr; | |
91 | - u32 dmardlr; | |
92 | - u32 idr; | |
93 | - u32 version; | |
94 | - | |
95 | - /* Currently operates as 32 bits, though only the low 16 bits matter */ | |
96 | - u32 dr; | |
97 | -} __packed; | |
98 | - | |
99 | -#define dw_readl(dw, name) __raw_readl(&(dw)->name) | |
100 | -#define dw_writel(dw, name, val) __raw_writel((val), &(dw)->name) | |
101 | - | |
102 | -/* Default use SPI0 register for mrst, we will detect Penwell and use SPI1 */ | |
103 | -static unsigned long mrst_spi_paddr = MRST_REGBASE_SPI0; | |
104 | - | |
105 | -static u32 *pclk_spi0; | |
106 | -/* Always contains an accessible address, start with 0 */ | |
107 | -static struct dw_spi_reg *pspi; | |
108 | - | |
109 | -static struct kmsg_dumper dw_dumper; | |
110 | -static int dumper_registered; | |
111 | - | |
112 | -static void dw_kmsg_dump(struct kmsg_dumper *dumper, | |
113 | - enum kmsg_dump_reason reason) | |
114 | -{ | |
115 | - static char line[1024]; | |
116 | - size_t len; | |
117 | - | |
118 | - /* When run to this, we'd better re-init the HW */ | |
119 | - mrst_early_console_init(); | |
120 | - | |
121 | - while (kmsg_dump_get_line(dumper, true, line, sizeof(line), &len)) | |
122 | - early_mrst_console.write(&early_mrst_console, line, len); | |
123 | -} | |
124 | - | |
125 | -/* Set the ratio rate to 115200, 8n1, IRQ disabled */ | |
126 | -static void max3110_write_config(void) | |
127 | -{ | |
128 | - u16 config; | |
129 | - | |
130 | - config = 0xc001; | |
131 | - dw_writel(pspi, dr, config); | |
132 | -} | |
133 | - | |
134 | -/* Translate char to a eligible word and send to max3110 */ | |
135 | -static void max3110_write_data(char c) | |
136 | -{ | |
137 | - u16 data; | |
138 | - | |
139 | - data = 0x8000 | c; | |
140 | - dw_writel(pspi, dr, data); | |
141 | -} | |
142 | - | |
143 | -void mrst_early_console_init(void) | |
144 | -{ | |
145 | - u32 ctrlr0 = 0; | |
146 | - u32 spi0_cdiv; | |
147 | - u32 freq; /* Freqency info only need be searched once */ | |
148 | - | |
149 | - /* Base clk is 100 MHz, the actual clk = 100M / (clk_divider + 1) */ | |
150 | - pclk_spi0 = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE, | |
151 | - MRST_CLK_SPI0_REG); | |
152 | - spi0_cdiv = ((*pclk_spi0) & 0xe00) >> 9; | |
153 | - freq = 100000000 / (spi0_cdiv + 1); | |
154 | - | |
155 | - if (mrst_identify_cpu() == MRST_CPU_CHIP_PENWELL) | |
156 | - mrst_spi_paddr = MRST_REGBASE_SPI1; | |
157 | - | |
158 | - pspi = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE, | |
159 | - mrst_spi_paddr); | |
160 | - | |
161 | - /* Disable SPI controller */ | |
162 | - dw_writel(pspi, ssienr, 0); | |
163 | - | |
164 | - /* Set control param, 8 bits, transmit only mode */ | |
165 | - ctrlr0 = dw_readl(pspi, ctrl0); | |
166 | - | |
167 | - ctrlr0 &= 0xfcc0; | |
168 | - ctrlr0 |= 0xf | (SPI_FRF_SPI << SPI_FRF_OFFSET) | |
169 | - | (SPI_TMOD_TO << SPI_TMOD_OFFSET); | |
170 | - dw_writel(pspi, ctrl0, ctrlr0); | |
171 | - | |
172 | - /* | |
173 | - * Change the spi0 clk to comply with 115200 bps, use 100000 to | |
174 | - * calculate the clk dividor to make the clock a little slower | |
175 | - * than real baud rate. | |
176 | - */ | |
177 | - dw_writel(pspi, baudr, freq/100000); | |
178 | - | |
179 | - /* Disable all INT for early phase */ | |
180 | - dw_writel(pspi, imr, 0x0); | |
181 | - | |
182 | - /* Set the cs to spi-uart */ | |
183 | - dw_writel(pspi, ser, 0x2); | |
184 | - | |
185 | - /* Enable the HW, the last step for HW init */ | |
186 | - dw_writel(pspi, ssienr, 0x1); | |
187 | - | |
188 | - /* Set the default configuration */ | |
189 | - max3110_write_config(); | |
190 | - | |
191 | - /* Register the kmsg dumper */ | |
192 | - if (!dumper_registered) { | |
193 | - dw_dumper.dump = dw_kmsg_dump; | |
194 | - kmsg_dump_register(&dw_dumper); | |
195 | - dumper_registered = 1; | |
196 | - } | |
197 | -} | |
198 | - | |
199 | -/* Slave select should be called in the read/write function */ | |
200 | -static void early_mrst_spi_putc(char c) | |
201 | -{ | |
202 | - unsigned int timeout; | |
203 | - u32 sr; | |
204 | - | |
205 | - timeout = MRST_SPI_TIMEOUT; | |
206 | - /* Early putc needs to make sure the TX FIFO is not full */ | |
207 | - while (--timeout) { | |
208 | - sr = dw_readl(pspi, sr); | |
209 | - if (!(sr & SR_TF_NOT_FULL)) | |
210 | - cpu_relax(); | |
211 | - else | |
212 | - break; | |
213 | - } | |
214 | - | |
215 | - if (!timeout) | |
216 | - pr_warn("MRST earlycon: timed out\n"); | |
217 | - else | |
218 | - max3110_write_data(c); | |
219 | -} | |
220 | - | |
221 | -/* Early SPI only uses polling mode */ | |
222 | -static void early_mrst_spi_write(struct console *con, const char *str, | |
223 | - unsigned n) | |
224 | -{ | |
225 | - int i; | |
226 | - | |
227 | - for (i = 0; i < n && *str; i++) { | |
228 | - if (*str == '\n') | |
229 | - early_mrst_spi_putc('\r'); | |
230 | - early_mrst_spi_putc(*str); | |
231 | - str++; | |
232 | - } | |
233 | -} | |
234 | - | |
235 | -struct console early_mrst_console = { | |
236 | - .name = "earlymrst", | |
237 | - .write = early_mrst_spi_write, | |
238 | - .flags = CON_PRINTBUFFER, | |
239 | - .index = -1, | |
240 | -}; | |
241 | - | |
242 | -/* | |
243 | - * Following is the early console based on Medfield HSU (High | |
244 | - * Speed UART) device. | |
245 | - */ | |
246 | -#define HSU_PORT_BASE 0xffa28080 | |
247 | - | |
248 | -static void __iomem *phsu; | |
249 | - | |
250 | -void hsu_early_console_init(const char *s) | |
251 | -{ | |
252 | - unsigned long paddr, port = 0; | |
253 | - u8 lcr; | |
254 | - | |
255 | - /* | |
256 | - * Select the early HSU console port if specified by user in the | |
257 | - * kernel command line. | |
258 | - */ | |
259 | - if (*s && !kstrtoul(s, 10, &port)) | |
260 | - port = clamp_val(port, 0, 2); | |
261 | - | |
262 | - paddr = HSU_PORT_BASE + port * 0x80; | |
263 | - phsu = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE, paddr); | |
264 | - | |
265 | - /* Disable FIFO */ | |
266 | - writeb(0x0, phsu + UART_FCR); | |
267 | - | |
268 | - /* Set to default 115200 bps, 8n1 */ | |
269 | - lcr = readb(phsu + UART_LCR); | |
270 | - writeb((0x80 | lcr), phsu + UART_LCR); | |
271 | - writeb(0x18, phsu + UART_DLL); | |
272 | - writeb(lcr, phsu + UART_LCR); | |
273 | - writel(0x3600, phsu + UART_MUL*4); | |
274 | - | |
275 | - writeb(0x8, phsu + UART_MCR); | |
276 | - writeb(0x7, phsu + UART_FCR); | |
277 | - writeb(0x3, phsu + UART_LCR); | |
278 | - | |
279 | - /* Clear IRQ status */ | |
280 | - readb(phsu + UART_LSR); | |
281 | - readb(phsu + UART_RX); | |
282 | - readb(phsu + UART_IIR); | |
283 | - readb(phsu + UART_MSR); | |
284 | - | |
285 | - /* Enable FIFO */ | |
286 | - writeb(0x7, phsu + UART_FCR); | |
287 | -} | |
288 | - | |
289 | -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) | |
290 | - | |
291 | -static void early_hsu_putc(char ch) | |
292 | -{ | |
293 | - unsigned int timeout = 10000; /* 10ms */ | |
294 | - u8 status; | |
295 | - | |
296 | - while (--timeout) { | |
297 | - status = readb(phsu + UART_LSR); | |
298 | - if (status & BOTH_EMPTY) | |
299 | - break; | |
300 | - udelay(1); | |
301 | - } | |
302 | - | |
303 | - /* Only write the char when there was no timeout */ | |
304 | - if (timeout) | |
305 | - writeb(ch, phsu + UART_TX); | |
306 | -} | |
307 | - | |
308 | -static void early_hsu_write(struct console *con, const char *str, unsigned n) | |
309 | -{ | |
310 | - int i; | |
311 | - | |
312 | - for (i = 0; i < n && *str; i++) { | |
313 | - if (*str == '\n') | |
314 | - early_hsu_putc('\r'); | |
315 | - early_hsu_putc(*str); | |
316 | - str++; | |
317 | - } | |
318 | -} | |
319 | - | |
320 | -struct console early_hsu_console = { | |
321 | - .name = "earlyhsu", | |
322 | - .write = early_hsu_write, | |
323 | - .flags = CON_PRINTBUFFER, | |
324 | - .index = -1, | |
325 | -}; |
arch/x86/platform/mrst/mrst.c
Changes suppressed. Click to show
1 | -/* | |
2 | - * mrst.c: Intel Moorestown platform specific setup code | |
3 | - * | |
4 | - * (C) Copyright 2008 Intel Corporation | |
5 | - * Author: Jacob Pan (jacob.jun.pan@intel.com) | |
6 | - * | |
7 | - * This program is free software; you can redistribute it and/or | |
8 | - * modify it under the terms of the GNU General Public License | |
9 | - * as published by the Free Software Foundation; version 2 | |
10 | - * of the License. | |
11 | - */ | |
12 | - | |
13 | -#define pr_fmt(fmt) "mrst: " fmt | |
14 | - | |
15 | -#include <linux/init.h> | |
16 | -#include <linux/kernel.h> | |
17 | -#include <linux/interrupt.h> | |
18 | -#include <linux/scatterlist.h> | |
19 | -#include <linux/sfi.h> | |
20 | -#include <linux/intel_pmic_gpio.h> | |
21 | -#include <linux/spi/spi.h> | |
22 | -#include <linux/i2c.h> | |
23 | -#include <linux/platform_data/pca953x.h> | |
24 | -#include <linux/gpio_keys.h> | |
25 | -#include <linux/input.h> | |
26 | -#include <linux/platform_device.h> | |
27 | -#include <linux/irq.h> | |
28 | -#include <linux/module.h> | |
29 | -#include <linux/notifier.h> | |
30 | -#include <linux/mfd/intel_msic.h> | |
31 | -#include <linux/gpio.h> | |
32 | -#include <linux/i2c/tc35876x.h> | |
33 | - | |
34 | -#include <asm/setup.h> | |
35 | -#include <asm/mpspec_def.h> | |
36 | -#include <asm/hw_irq.h> | |
37 | -#include <asm/apic.h> | |
38 | -#include <asm/io_apic.h> | |
39 | -#include <asm/mrst.h> | |
40 | -#include <asm/mrst-vrtc.h> | |
41 | -#include <asm/io.h> | |
42 | -#include <asm/i8259.h> | |
43 | -#include <asm/intel_scu_ipc.h> | |
44 | -#include <asm/apb_timer.h> | |
45 | -#include <asm/reboot.h> | |
46 | - | |
47 | -/* | |
48 | - * the clockevent devices on Moorestown/Medfield can be APBT or LAPIC clock, | |
49 | - * cmdline option x86_mrst_timer can be used to override the configuration | |
50 | - * to prefer one or the other. | |
51 | - * at runtime, there are basically three timer configurations: | |
52 | - * 1. per cpu apbt clock only | |
53 | - * 2. per cpu always-on lapic clocks only, this is Penwell/Medfield only | |
54 | - * 3. per cpu lapic clock (C3STOP) and one apbt clock, with broadcast. | |
55 | - * | |
56 | - * by default (without cmdline option), platform code first detects cpu type | |
57 | - * to see if we are on lincroft or penwell, then set up both lapic or apbt | |
58 | - * clocks accordingly. | |
59 | - * i.e. by default, medfield uses configuration #2, moorestown uses #1. | |
60 | - * config #3 is supported but not recommended on medfield. | |
61 | - * | |
62 | - * rating and feature summary: | |
63 | - * lapic (with C3STOP) --------- 100 | |
64 | - * apbt (always-on) ------------ 110 | |
65 | - * lapic (always-on,ARAT) ------ 150 | |
66 | - */ | |
67 | - | |
68 | -enum mrst_timer_options mrst_timer_options; | |
69 | - | |
70 | -static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM]; | |
71 | -static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM]; | |
72 | -enum mrst_cpu_type __mrst_cpu_chip; | |
73 | -EXPORT_SYMBOL_GPL(__mrst_cpu_chip); | |
74 | - | |
75 | -int sfi_mtimer_num; | |
76 | - | |
77 | -struct sfi_rtc_table_entry sfi_mrtc_array[SFI_MRTC_MAX]; | |
78 | -EXPORT_SYMBOL_GPL(sfi_mrtc_array); | |
79 | -int sfi_mrtc_num; | |
80 | - | |
81 | -static void mrst_power_off(void) | |
82 | -{ | |
83 | -} | |
84 | - | |
85 | -static void mrst_reboot(void) | |
86 | -{ | |
87 | - intel_scu_ipc_simple_command(IPCMSG_COLD_BOOT, 0); | |
88 | -} | |
89 | - | |
90 | -/* parse all the mtimer info to a static mtimer array */ | |
91 | -static int __init sfi_parse_mtmr(struct sfi_table_header *table) | |
92 | -{ | |
93 | - struct sfi_table_simple *sb; | |
94 | - struct sfi_timer_table_entry *pentry; | |
95 | - struct mpc_intsrc mp_irq; | |
96 | - int totallen; | |
97 | - | |
98 | - sb = (struct sfi_table_simple *)table; | |
99 | - if (!sfi_mtimer_num) { | |
100 | - sfi_mtimer_num = SFI_GET_NUM_ENTRIES(sb, | |
101 | - struct sfi_timer_table_entry); | |
102 | - pentry = (struct sfi_timer_table_entry *) sb->pentry; | |
103 | - totallen = sfi_mtimer_num * sizeof(*pentry); | |
104 | - memcpy(sfi_mtimer_array, pentry, totallen); | |
105 | - } | |
106 | - | |
107 | - pr_debug("SFI MTIMER info (num = %d):\n", sfi_mtimer_num); | |
108 | - pentry = sfi_mtimer_array; | |
109 | - for (totallen = 0; totallen < sfi_mtimer_num; totallen++, pentry++) { | |
110 | - pr_debug("timer[%d]: paddr = 0x%08x, freq = %dHz," | |
111 | - " irq = %d\n", totallen, (u32)pentry->phys_addr, | |
112 | - pentry->freq_hz, pentry->irq); | |
113 | - if (!pentry->irq) | |
114 | - continue; | |
115 | - mp_irq.type = MP_INTSRC; | |
116 | - mp_irq.irqtype = mp_INT; | |
117 | -/* triggering mode edge bit 2-3, active high polarity bit 0-1 */ | |
118 | - mp_irq.irqflag = 5; | |
119 | - mp_irq.srcbus = MP_BUS_ISA; | |
120 | - mp_irq.srcbusirq = pentry->irq; /* IRQ */ | |
121 | - mp_irq.dstapic = MP_APIC_ALL; | |
122 | - mp_irq.dstirq = pentry->irq; | |
123 | - mp_save_irq(&mp_irq); | |
124 | - } | |
125 | - | |
126 | - return 0; | |
127 | -} | |
128 | - | |
129 | -struct sfi_timer_table_entry *sfi_get_mtmr(int hint) | |
130 | -{ | |
131 | - int i; | |
132 | - if (hint < sfi_mtimer_num) { | |
133 | - if (!sfi_mtimer_usage[hint]) { | |
134 | - pr_debug("hint taken for timer %d irq %d\n", | |
135 | - hint, sfi_mtimer_array[hint].irq); | |
136 | - sfi_mtimer_usage[hint] = 1; | |
137 | - return &sfi_mtimer_array[hint]; | |
138 | - } | |
139 | - } | |
140 | - /* take the first timer available */ | |
141 | - for (i = 0; i < sfi_mtimer_num;) { | |
142 | - if (!sfi_mtimer_usage[i]) { | |
143 | - sfi_mtimer_usage[i] = 1; | |
144 | - return &sfi_mtimer_array[i]; | |
145 | - } | |
146 | - i++; | |
147 | - } | |
148 | - return NULL; | |
149 | -} | |
150 | - | |
151 | -void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr) | |
152 | -{ | |
153 | - int i; | |
154 | - for (i = 0; i < sfi_mtimer_num;) { | |
155 | - if (mtmr->irq == sfi_mtimer_array[i].irq) { | |
156 | - sfi_mtimer_usage[i] = 0; | |
157 | - return; | |
158 | - } | |
159 | - i++; | |
160 | - } | |
161 | -} | |
162 | - | |
163 | -/* parse all the mrtc info to a global mrtc array */ | |
164 | -int __init sfi_parse_mrtc(struct sfi_table_header *table) | |
165 | -{ | |
166 | - struct sfi_table_simple *sb; | |
167 | - struct sfi_rtc_table_entry *pentry; | |
168 | - struct mpc_intsrc mp_irq; | |
169 | - | |
170 | - int totallen; | |
171 | - | |
172 | - sb = (struct sfi_table_simple *)table; | |
173 | - if (!sfi_mrtc_num) { | |
174 | - sfi_mrtc_num = SFI_GET_NUM_ENTRIES(sb, | |
175 | - struct sfi_rtc_table_entry); | |
176 | - pentry = (struct sfi_rtc_table_entry *)sb->pentry; | |
177 | - totallen = sfi_mrtc_num * sizeof(*pentry); | |
178 | - memcpy(sfi_mrtc_array, pentry, totallen); | |
179 | - } | |
180 | - | |
181 | - pr_debug("SFI RTC info (num = %d):\n", sfi_mrtc_num); | |
182 | - pentry = sfi_mrtc_array; | |
183 | - for (totallen = 0; totallen < sfi_mrtc_num; totallen++, pentry++) { | |
184 | - pr_debug("RTC[%d]: paddr = 0x%08x, irq = %d\n", | |
185 | - totallen, (u32)pentry->phys_addr, pentry->irq); | |
186 | - mp_irq.type = MP_INTSRC; | |
187 | - mp_irq.irqtype = mp_INT; | |
188 | - mp_irq.irqflag = 0xf; /* level trigger and active low */ | |
189 | - mp_irq.srcbus = MP_BUS_ISA; | |
190 | - mp_irq.srcbusirq = pentry->irq; /* IRQ */ | |
191 | - mp_irq.dstapic = MP_APIC_ALL; | |
192 | - mp_irq.dstirq = pentry->irq; | |
193 | - mp_save_irq(&mp_irq); | |
194 | - } | |
195 | - return 0; | |
196 | -} | |
197 | - | |
198 | -static unsigned long __init mrst_calibrate_tsc(void) | |
199 | -{ | |
200 | - unsigned long fast_calibrate; | |
201 | - u32 lo, hi, ratio, fsb; | |
202 | - | |
203 | - rdmsr(MSR_IA32_PERF_STATUS, lo, hi); | |
204 | - pr_debug("IA32 perf status is 0x%x, 0x%0x\n", lo, hi); | |
205 | - ratio = (hi >> 8) & 0x1f; | |
206 | - pr_debug("ratio is %d\n", ratio); | |
207 | - if (!ratio) { | |
208 | - pr_err("read a zero ratio, should be incorrect!\n"); | |
209 | - pr_err("force tsc ratio to 16 ...\n"); | |
210 | - ratio = 16; | |
211 | - } | |
212 | - rdmsr(MSR_FSB_FREQ, lo, hi); | |
213 | - if ((lo & 0x7) == 0x7) | |
214 | - fsb = PENWELL_FSB_FREQ_83SKU; | |
215 | - else | |
216 | - fsb = PENWELL_FSB_FREQ_100SKU; | |
217 | - fast_calibrate = ratio * fsb; | |
218 | - pr_debug("read penwell tsc %lu khz\n", fast_calibrate); | |
219 | - lapic_timer_frequency = fsb * 1000 / HZ; | |
220 | - /* mark tsc clocksource as reliable */ | |
221 | - set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE); | |
222 | - | |
223 | - if (fast_calibrate) | |
224 | - return fast_calibrate; | |
225 | - | |
226 | - return 0; | |
227 | -} | |
228 | - | |
229 | -static void __init mrst_time_init(void) | |
230 | -{ | |
231 | - sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr); | |
232 | - switch (mrst_timer_options) { | |
233 | - case MRST_TIMER_APBT_ONLY: | |
234 | - break; | |
235 | - case MRST_TIMER_LAPIC_APBT: | |
236 | - x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock; | |
237 | - x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock; | |
238 | - break; | |
239 | - default: | |
240 | - if (!boot_cpu_has(X86_FEATURE_ARAT)) | |
241 | - break; | |
242 | - x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock; | |
243 | - x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock; | |
244 | - return; | |
245 | - } | |
246 | - /* we need at least one APB timer */ | |
247 | - pre_init_apic_IRQ0(); | |
248 | - apbt_time_init(); | |
249 | -} | |
250 | - | |
251 | -static void mrst_arch_setup(void) | |
252 | -{ | |
253 | - if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27) | |
254 | - __mrst_cpu_chip = MRST_CPU_CHIP_PENWELL; | |
255 | - else { | |
256 | - pr_err("Unknown Intel MID CPU (%d:%d), default to Penwell\n", | |
257 | - boot_cpu_data.x86, boot_cpu_data.x86_model); | |
258 | - __mrst_cpu_chip = MRST_CPU_CHIP_PENWELL; | |
259 | - } | |
260 | -} | |
261 | - | |
262 | -/* MID systems don't have i8042 controller */ | |
263 | -static int mrst_i8042_detect(void) | |
264 | -{ | |
265 | - return 0; | |
266 | -} | |
267 | - | |
268 | -/* | |
269 | - * Moorestown does not have external NMI source nor port 0x61 to report | |
270 | - * NMI status. The possible NMI sources are from pmu as a result of NMI | |
271 | - * watchdog or lock debug. Reading io port 0x61 results in 0xff which | |
272 | - * misled NMI handler. | |
273 | - */ | |
274 | -static unsigned char mrst_get_nmi_reason(void) | |
275 | -{ | |
276 | - return 0; | |
277 | -} | |
278 | - | |
279 | -/* | |
280 | - * Moorestown specific x86_init function overrides and early setup | |
281 | - * calls. | |
282 | - */ | |
283 | -void __init x86_mrst_early_setup(void) | |
284 | -{ | |
285 | - x86_init.resources.probe_roms = x86_init_noop; | |
286 | - x86_init.resources.reserve_resources = x86_init_noop; | |
287 | - | |
288 | - x86_init.timers.timer_init = mrst_time_init; | |
289 | - x86_init.timers.setup_percpu_clockev = x86_init_noop; | |
290 | - | |
291 | - x86_init.irqs.pre_vector_init = x86_init_noop; | |
292 | - | |
293 | - x86_init.oem.arch_setup = mrst_arch_setup; | |
294 | - | |
295 | - x86_cpuinit.setup_percpu_clockev = apbt_setup_secondary_clock; | |
296 | - | |
297 | - x86_platform.calibrate_tsc = mrst_calibrate_tsc; | |
298 | - x86_platform.i8042_detect = mrst_i8042_detect; | |
299 | - x86_init.timers.wallclock_init = mrst_rtc_init; | |
300 | - x86_platform.get_nmi_reason = mrst_get_nmi_reason; | |
301 | - | |
302 | - x86_init.pci.init = pci_mrst_init; | |
303 | - x86_init.pci.fixup_irqs = x86_init_noop; | |
304 | - | |
305 | - legacy_pic = &null_legacy_pic; | |
306 | - | |
307 | - /* Moorestown specific power_off/restart method */ | |
308 | - pm_power_off = mrst_power_off; | |
309 | - machine_ops.emergency_restart = mrst_reboot; | |
310 | - | |
311 | - /* Avoid searching for BIOS MP tables */ | |
312 | - x86_init.mpparse.find_smp_config = x86_init_noop; | |
313 | - x86_init.mpparse.get_smp_config = x86_init_uint_noop; | |
314 | - set_bit(MP_BUS_ISA, mp_bus_not_pci); | |
315 | -} | |
316 | - | |
317 | -/* | |
318 | - * if user does not want to use per CPU apb timer, just give it a lower rating | |
319 | - * than local apic timer and skip the late per cpu timer init. | |
320 | - */ | |
321 | -static inline int __init setup_x86_mrst_timer(char *arg) | |
322 | -{ | |
323 | - if (!arg) | |
324 | - return -EINVAL; | |
325 | - | |
326 | - if (strcmp("apbt_only", arg) == 0) | |
327 | - mrst_timer_options = MRST_TIMER_APBT_ONLY; | |
328 | - else if (strcmp("lapic_and_apbt", arg) == 0) | |
329 | - mrst_timer_options = MRST_TIMER_LAPIC_APBT; | |
330 | - else { | |
331 | - pr_warn("X86 MRST timer option %s not recognised" | |
332 | - " use x86_mrst_timer=apbt_only or lapic_and_apbt\n", | |
333 | - arg); | |
334 | - return -EINVAL; | |
335 | - } | |
336 | - return 0; | |
337 | -} | |
338 | -__setup("x86_mrst_timer=", setup_x86_mrst_timer); | |
339 | - | |
340 | -/* | |
341 | - * Parsing GPIO table first, since the DEVS table will need this table | |
342 | - * to map the pin name to the actual pin. | |
343 | - */ | |
344 | -static struct sfi_gpio_table_entry *gpio_table; | |
345 | -static int gpio_num_entry; | |
346 | - | |
347 | -static int __init sfi_parse_gpio(struct sfi_table_header *table) | |
348 | -{ | |
349 | - struct sfi_table_simple *sb; | |
350 | - struct sfi_gpio_table_entry *pentry; | |
351 | - int num, i; | |
352 | - | |
353 | - if (gpio_table) | |
354 | - return 0; | |
355 | - sb = (struct sfi_table_simple *)table; | |
356 | - num = SFI_GET_NUM_ENTRIES(sb, struct sfi_gpio_table_entry); | |
357 | - pentry = (struct sfi_gpio_table_entry *)sb->pentry; | |
358 | - | |
359 | - gpio_table = kmalloc(num * sizeof(*pentry), GFP_KERNEL); | |
360 | - if (!gpio_table) | |
361 | - return -1; | |
362 | - memcpy(gpio_table, pentry, num * sizeof(*pentry)); | |
363 | - gpio_num_entry = num; | |
364 | - | |
365 | - pr_debug("GPIO pin info:\n"); | |
366 | - for (i = 0; i < num; i++, pentry++) | |
367 | - pr_debug("info[%2d]: controller = %16.16s, pin_name = %16.16s," | |
368 | - " pin = %d\n", i, | |
369 | - pentry->controller_name, | |
370 | - pentry->pin_name, | |
371 | - pentry->pin_no); | |
372 | - return 0; | |
373 | -} | |
374 | - | |
375 | -static int get_gpio_by_name(const char *name) | |
376 | -{ | |
377 | - struct sfi_gpio_table_entry *pentry = gpio_table; | |
378 | - int i; | |
379 | - | |
380 | - if (!pentry) | |
381 | - return -1; | |
382 | - for (i = 0; i < gpio_num_entry; i++, pentry++) { | |
383 | - if (!strncmp(name, pentry->pin_name, SFI_NAME_LEN)) | |
384 | - return pentry->pin_no; | |
385 | - } | |
386 | - return -1; | |
387 | -} | |
388 | - | |
389 | -/* | |
390 | - * Here defines the array of devices platform data that IAFW would export | |
391 | - * through SFI "DEVS" table, we use name and type to match the device and | |
392 | - * its platform data. | |
393 | - */ | |
394 | -struct devs_id { | |
395 | - char name[SFI_NAME_LEN + 1]; | |
396 | - u8 type; | |
397 | - u8 delay; | |
398 | - void *(*get_platform_data)(void *info); | |
399 | -}; | |
400 | - | |
401 | -/* the offset for the mapping of global gpio pin to irq */ | |
402 | -#define MRST_IRQ_OFFSET 0x100 | |
403 | - | |
404 | -static void __init *pmic_gpio_platform_data(void *info) | |
405 | -{ | |
406 | - static struct intel_pmic_gpio_platform_data pmic_gpio_pdata; | |
407 | - int gpio_base = get_gpio_by_name("pmic_gpio_base"); | |
408 | - | |
409 | - if (gpio_base == -1) | |
410 | - gpio_base = 64; | |
411 | - pmic_gpio_pdata.gpio_base = gpio_base; | |
412 | - pmic_gpio_pdata.irq_base = gpio_base + MRST_IRQ_OFFSET; | |
413 | - pmic_gpio_pdata.gpiointr = 0xffffeff8; | |
414 | - | |
415 | - return &pmic_gpio_pdata; | |
416 | -} | |
417 | - | |
418 | -static void __init *max3111_platform_data(void *info) | |
419 | -{ | |
420 | - struct spi_board_info *spi_info = info; | |
421 | - int intr = get_gpio_by_name("max3111_int"); | |
422 | - | |
423 | - spi_info->mode = SPI_MODE_0; | |
424 | - if (intr == -1) | |
425 | - return NULL; | |
426 | - spi_info->irq = intr + MRST_IRQ_OFFSET; | |
427 | - return NULL; | |
428 | -} | |
429 | - | |
430 | -/* we have multiple max7315 on the board ... */ | |
431 | -#define MAX7315_NUM 2 | |
432 | -static void __init *max7315_platform_data(void *info) | |
433 | -{ | |
434 | - static struct pca953x_platform_data max7315_pdata[MAX7315_NUM]; | |
435 | - static int nr; | |
436 | - struct pca953x_platform_data *max7315 = &max7315_pdata[nr]; | |
437 | - struct i2c_board_info *i2c_info = info; | |
438 | - int gpio_base, intr; | |
439 | - char base_pin_name[SFI_NAME_LEN + 1]; | |
440 | - char intr_pin_name[SFI_NAME_LEN + 1]; | |
441 | - | |
442 | - if (nr == MAX7315_NUM) { | |
443 | - pr_err("too many max7315s, we only support %d\n", | |
444 | - MAX7315_NUM); | |
445 | - return NULL; | |
446 | - } | |
447 | - /* we have several max7315 on the board, we only need load several | |
448 | - * instances of the same pca953x driver to cover them | |
449 | - */ | |
450 | - strcpy(i2c_info->type, "max7315"); | |
451 | - if (nr++) { | |
452 | - sprintf(base_pin_name, "max7315_%d_base", nr); | |
453 | - sprintf(intr_pin_name, "max7315_%d_int", nr); | |
454 | - } else { | |
455 | - strcpy(base_pin_name, "max7315_base"); | |
456 | - strcpy(intr_pin_name, "max7315_int"); | |
457 | - } | |
458 | - | |
459 | - gpio_base = get_gpio_by_name(base_pin_name); | |
460 | - intr = get_gpio_by_name(intr_pin_name); | |
461 | - | |
462 | - if (gpio_base == -1) | |
463 | - return NULL; | |
464 | - max7315->gpio_base = gpio_base; | |
465 | - if (intr != -1) { | |
466 | - i2c_info->irq = intr + MRST_IRQ_OFFSET; | |
467 | - max7315->irq_base = gpio_base + MRST_IRQ_OFFSET; | |
468 | - } else { | |
469 | - i2c_info->irq = -1; | |
470 | - max7315->irq_base = -1; | |
471 | - } | |
472 | - return max7315; | |
473 | -} | |
474 | - | |
475 | -static void *tca6416_platform_data(void *info) | |
476 | -{ | |
477 | - static struct pca953x_platform_data tca6416; | |
478 | - struct i2c_board_info *i2c_info = info; | |
479 | - int gpio_base, intr; | |
480 | - char base_pin_name[SFI_NAME_LEN + 1]; | |
481 | - char intr_pin_name[SFI_NAME_LEN + 1]; | |
482 | - | |
483 | - strcpy(i2c_info->type, "tca6416"); | |
484 | - strcpy(base_pin_name, "tca6416_base"); | |
485 | - strcpy(intr_pin_name, "tca6416_int"); | |
486 | - | |
487 | - gpio_base = get_gpio_by_name(base_pin_name); | |
488 | - intr = get_gpio_by_name(intr_pin_name); | |
489 | - | |
490 | - if (gpio_base == -1) | |
491 | - return NULL; | |
492 | - tca6416.gpio_base = gpio_base; | |
493 | - if (intr != -1) { | |
494 | - i2c_info->irq = intr + MRST_IRQ_OFFSET; | |
495 | - tca6416.irq_base = gpio_base + MRST_IRQ_OFFSET; | |
496 | - } else { | |
497 | - i2c_info->irq = -1; | |
498 | - tca6416.irq_base = -1; | |
499 | - } | |
500 | - return &tca6416; | |
501 | -} | |
502 | - | |
503 | -static void *mpu3050_platform_data(void *info) | |
504 | -{ | |
505 | - struct i2c_board_info *i2c_info = info; | |
506 | - int intr = get_gpio_by_name("mpu3050_int"); | |
507 | - | |
508 | - if (intr == -1) | |
509 | - return NULL; | |
510 | - | |
511 | - i2c_info->irq = intr + MRST_IRQ_OFFSET; | |
512 | - return NULL; | |
513 | -} | |
514 | - | |
515 | -static void __init *emc1403_platform_data(void *info) | |
516 | -{ | |
517 | - static short intr2nd_pdata; | |
518 | - struct i2c_board_info *i2c_info = info; | |
519 | - int intr = get_gpio_by_name("thermal_int"); | |
520 | - int intr2nd = get_gpio_by_name("thermal_alert"); | |
521 | - | |
522 | - if (intr == -1 || intr2nd == -1) | |
523 | - return NULL; | |
524 | - | |
525 | - i2c_info->irq = intr + MRST_IRQ_OFFSET; | |
526 | - intr2nd_pdata = intr2nd + MRST_IRQ_OFFSET; | |
527 | - | |
528 | - return &intr2nd_pdata; | |
529 | -} | |
530 | - | |
531 | -static void __init *lis331dl_platform_data(void *info) | |
532 | -{ | |
533 | - static short intr2nd_pdata; | |
534 | - struct i2c_board_info *i2c_info = info; | |
535 | - int intr = get_gpio_by_name("accel_int"); | |
536 | - int intr2nd = get_gpio_by_name("accel_2"); | |
537 | - | |
538 | - if (intr == -1 || intr2nd == -1) | |
539 | - return NULL; | |
540 | - | |
541 | - i2c_info->irq = intr + MRST_IRQ_OFFSET; | |
542 | - intr2nd_pdata = intr2nd + MRST_IRQ_OFFSET; | |
543 | - | |
544 | - return &intr2nd_pdata; | |
545 | -} | |
546 | - | |
547 | -static void __init *no_platform_data(void *info) | |
548 | -{ | |
549 | - return NULL; | |
550 | -} | |
551 | - | |
552 | -static struct resource msic_resources[] = { | |
553 | - { | |
554 | - .start = INTEL_MSIC_IRQ_PHYS_BASE, | |
555 | - .end = INTEL_MSIC_IRQ_PHYS_BASE + 64 - 1, | |
556 | - .flags = IORESOURCE_MEM, | |
557 | - }, | |
558 | -}; | |
559 | - | |
560 | -static struct intel_msic_platform_data msic_pdata; | |
561 | - | |
562 | -static struct platform_device msic_device = { | |
563 | - .name = "intel_msic", | |
564 | - .id = -1, | |
565 | - .dev = { | |
566 | - .platform_data = &msic_pdata, | |
567 | - }, | |
568 | - .num_resources = ARRAY_SIZE(msic_resources), | |
569 | - .resource = msic_resources, | |
570 | -}; | |
571 | - | |
572 | -static inline bool mrst_has_msic(void) | |
573 | -{ | |
574 | - return mrst_identify_cpu() == MRST_CPU_CHIP_PENWELL; | |
575 | -} | |
576 | - | |
577 | -static int msic_scu_status_change(struct notifier_block *nb, | |
578 | - unsigned long code, void *data) | |
579 | -{ | |
580 | - if (code == SCU_DOWN) { | |
581 | - platform_device_unregister(&msic_device); | |
582 | - return 0; | |
583 | - } | |
584 | - | |
585 | - return platform_device_register(&msic_device); | |
586 | -} | |
587 | - | |
588 | -static int __init msic_init(void) | |
589 | -{ | |
590 | - static struct notifier_block msic_scu_notifier = { | |
591 | - .notifier_call = msic_scu_status_change, | |
592 | - }; | |
593 | - | |
594 | - /* | |
595 | - * We need to be sure that the SCU IPC is ready before MSIC device | |
596 | - * can be registered. | |
597 | - */ | |
598 | - if (mrst_has_msic()) | |
599 | - intel_scu_notifier_add(&msic_scu_notifier); | |
600 | - | |
601 | - return 0; | |
602 | -} | |
603 | -arch_initcall(msic_init); | |
604 | - | |
605 | -/* | |
606 | - * msic_generic_platform_data - sets generic platform data for the block | |
607 | - * @info: pointer to the SFI device table entry for this block | |
608 | - * @block: MSIC block | |
609 | - * | |
610 | - * Function sets IRQ number from the SFI table entry for given device to | |
611 | - * the MSIC platform data. | |
612 | - */ | |
613 | -static void *msic_generic_platform_data(void *info, enum intel_msic_block block) | |
614 | -{ | |
615 | - struct sfi_device_table_entry *entry = info; | |
616 | - | |
617 | - BUG_ON(block < 0 || block >= INTEL_MSIC_BLOCK_LAST); | |
618 | - msic_pdata.irq[block] = entry->irq; | |
619 | - | |
620 | - return no_platform_data(info); | |
621 | -} | |
622 | - | |
623 | -static void *msic_battery_platform_data(void *info) | |
624 | -{ | |
625 | - return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_BATTERY); | |
626 | -} | |
627 | - | |
628 | -static void *msic_gpio_platform_data(void *info) | |
629 | -{ | |
630 | - static struct intel_msic_gpio_pdata pdata; | |
631 | - int gpio = get_gpio_by_name("msic_gpio_base"); | |
632 | - | |
633 | - if (gpio < 0) | |
634 | - return NULL; | |
635 | - | |
636 | - pdata.gpio_base = gpio; | |
637 | - msic_pdata.gpio = &pdata; | |
638 | - | |
639 | - return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_GPIO); | |
640 | -} | |
641 | - | |
642 | -static void *msic_audio_platform_data(void *info) | |
643 | -{ | |
644 | - struct platform_device *pdev; | |
645 | - | |
646 | - pdev = platform_device_register_simple("sst-platform", -1, NULL, 0); | |
647 | - if (IS_ERR(pdev)) { | |
648 | - pr_err("failed to create audio platform device\n"); | |
649 | - return NULL; | |
650 | - } | |
651 | - | |
652 | - return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_AUDIO); | |
653 | -} | |
654 | - | |
655 | -static void *msic_power_btn_platform_data(void *info) | |
656 | -{ | |
657 | - return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_POWER_BTN); | |
658 | -} | |
659 | - | |
660 | -static void *msic_ocd_platform_data(void *info) | |
661 | -{ | |
662 | - static struct intel_msic_ocd_pdata pdata; | |
663 | - int gpio = get_gpio_by_name("ocd_gpio"); | |
664 | - | |
665 | - if (gpio < 0) | |
666 | - return NULL; | |
667 | - | |
668 | - pdata.gpio = gpio; | |
669 | - msic_pdata.ocd = &pdata; | |
670 | - | |
671 | - return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_OCD); | |
672 | -} | |
673 | - | |
674 | -static void *msic_thermal_platform_data(void *info) | |
675 | -{ | |
676 | - return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_THERMAL); | |
677 | -} | |
678 | - | |
679 | -/* tc35876x DSI-LVDS bridge chip and panel platform data */ | |
680 | -static void *tc35876x_platform_data(void *data) | |
681 | -{ | |
682 | - static struct tc35876x_platform_data pdata; | |
683 | - | |
684 | - /* gpio pins set to -1 will not be used by the driver */ | |
685 | - pdata.gpio_bridge_reset = get_gpio_by_name("LCMB_RXEN"); | |
686 | - pdata.gpio_panel_bl_en = get_gpio_by_name("6S6P_BL_EN"); | |
687 | - pdata.gpio_panel_vadd = get_gpio_by_name("EN_VREG_LCD_V3P3"); | |
688 | - | |
689 | - return &pdata; | |
690 | -} | |
691 | - | |
692 | -static const struct devs_id __initconst device_ids[] = { | |
693 | - {"bma023", SFI_DEV_TYPE_I2C, 1, &no_platform_data}, | |
694 | - {"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data}, | |
695 | - {"pmic_gpio", SFI_DEV_TYPE_IPC, 1, &pmic_gpio_platform_data}, | |
696 | - {"spi_max3111", SFI_DEV_TYPE_SPI, 0, &max3111_platform_data}, | |
697 | - {"i2c_max7315", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data}, | |
698 | - {"i2c_max7315_2", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data}, | |
699 | - {"tca6416", SFI_DEV_TYPE_I2C, 1, &tca6416_platform_data}, | |
700 | - {"emc1403", SFI_DEV_TYPE_I2C, 1, &emc1403_platform_data}, | |
701 | - {"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data}, | |
702 | - {"pmic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data}, | |
703 | - {"mpu3050", SFI_DEV_TYPE_I2C, 1, &mpu3050_platform_data}, | |
704 | - {"i2c_disp_brig", SFI_DEV_TYPE_I2C, 0, &tc35876x_platform_data}, | |
705 | - | |
706 | - /* MSIC subdevices */ | |
707 | - {"msic_battery", SFI_DEV_TYPE_IPC, 1, &msic_battery_platform_data}, | |
708 | - {"msic_gpio", SFI_DEV_TYPE_IPC, 1, &msic_gpio_platform_data}, | |
709 | - {"msic_audio", SFI_DEV_TYPE_IPC, 1, &msic_audio_platform_data}, | |
710 | - {"msic_power_btn", SFI_DEV_TYPE_IPC, 1, &msic_power_btn_platform_data}, | |
711 | - {"msic_ocd", SFI_DEV_TYPE_IPC, 1, &msic_ocd_platform_data}, | |
712 | - {"msic_thermal", SFI_DEV_TYPE_IPC, 1, &msic_thermal_platform_data}, | |
713 | - | |
714 | - {}, | |
715 | -}; | |
716 | - | |
717 | -#define MAX_IPCDEVS 24 | |
718 | -static struct platform_device *ipc_devs[MAX_IPCDEVS]; | |
719 | -static int ipc_next_dev; | |
720 | - | |
721 | -#define MAX_SCU_SPI 24 | |
722 | -static struct spi_board_info *spi_devs[MAX_SCU_SPI]; | |
723 | -static int spi_next_dev; | |
724 | - | |
725 | -#define MAX_SCU_I2C 24 | |
726 | -static struct i2c_board_info *i2c_devs[MAX_SCU_I2C]; | |
727 | -static int i2c_bus[MAX_SCU_I2C]; | |
728 | -static int i2c_next_dev; | |
729 | - | |
730 | -static void __init intel_scu_device_register(struct platform_device *pdev) | |
731 | -{ | |
732 | - if (ipc_next_dev == MAX_IPCDEVS) | |
733 | - pr_err("too many SCU IPC devices"); | |
734 | - else | |
735 | - ipc_devs[ipc_next_dev++] = pdev; | |
736 | -} | |
737 | - | |
738 | -static void __init intel_scu_spi_device_register(struct spi_board_info *sdev) | |
739 | -{ | |
740 | - struct spi_board_info *new_dev; | |
741 | - | |
742 | - if (spi_next_dev == MAX_SCU_SPI) { | |
743 | - pr_err("too many SCU SPI devices"); | |
744 | - return; | |
745 | - } | |
746 | - | |
747 | - new_dev = kzalloc(sizeof(*sdev), GFP_KERNEL); | |
748 | - if (!new_dev) { | |
749 | - pr_err("failed to alloc mem for delayed spi dev %s\n", | |
750 | - sdev->modalias); | |
751 | - return; | |
752 | - } | |
753 | - memcpy(new_dev, sdev, sizeof(*sdev)); | |
754 | - | |
755 | - spi_devs[spi_next_dev++] = new_dev; | |
756 | -} | |
757 | - | |
758 | -static void __init intel_scu_i2c_device_register(int bus, | |
759 | - struct i2c_board_info *idev) | |
760 | -{ | |
761 | - struct i2c_board_info *new_dev; | |
762 | - | |
763 | - if (i2c_next_dev == MAX_SCU_I2C) { | |
764 | - pr_err("too many SCU I2C devices"); | |
765 | - return; | |
766 | - } | |
767 | - | |
768 | - new_dev = kzalloc(sizeof(*idev), GFP_KERNEL); | |
769 | - if (!new_dev) { | |
770 | - pr_err("failed to alloc mem for delayed i2c dev %s\n", | |
771 | - idev->type); | |
772 | - return; | |
773 | - } | |
774 | - memcpy(new_dev, idev, sizeof(*idev)); | |
775 | - | |
776 | - i2c_bus[i2c_next_dev] = bus; | |
777 | - i2c_devs[i2c_next_dev++] = new_dev; | |
778 | -} | |
779 | - | |
780 | -BLOCKING_NOTIFIER_HEAD(intel_scu_notifier); | |
781 | -EXPORT_SYMBOL_GPL(intel_scu_notifier); | |
782 | - | |
783 | -/* Called by IPC driver */ | |
784 | -void intel_scu_devices_create(void) | |
785 | -{ | |
786 | - int i; | |
787 | - | |
788 | - for (i = 0; i < ipc_next_dev; i++) | |
789 | - platform_device_add(ipc_devs[i]); | |
790 | - | |
791 | - for (i = 0; i < spi_next_dev; i++) | |
792 | - spi_register_board_info(spi_devs[i], 1); | |
793 | - | |
794 | - for (i = 0; i < i2c_next_dev; i++) { | |
795 | - struct i2c_adapter *adapter; | |
796 | - struct i2c_client *client; | |
797 | - | |
798 | - adapter = i2c_get_adapter(i2c_bus[i]); | |
799 | - if (adapter) { | |
800 | - client = i2c_new_device(adapter, i2c_devs[i]); | |
801 | - if (!client) | |
802 | - pr_err("can't create i2c device %s\n", | |
803 | - i2c_devs[i]->type); | |
804 | - } else | |
805 | - i2c_register_board_info(i2c_bus[i], i2c_devs[i], 1); | |
806 | - } | |
807 | - intel_scu_notifier_post(SCU_AVAILABLE, NULL); | |
808 | -} | |
809 | -EXPORT_SYMBOL_GPL(intel_scu_devices_create); | |
810 | - | |
811 | -/* Called by IPC driver */ | |
812 | -void intel_scu_devices_destroy(void) | |
813 | -{ | |
814 | - int i; | |
815 | - | |
816 | - intel_scu_notifier_post(SCU_DOWN, NULL); | |
817 | - | |
818 | - for (i = 0; i < ipc_next_dev; i++) | |
819 | - platform_device_del(ipc_devs[i]); | |
820 | -} | |
821 | -EXPORT_SYMBOL_GPL(intel_scu_devices_destroy); | |
822 | - | |
823 | -static void __init install_irq_resource(struct platform_device *pdev, int irq) | |
824 | -{ | |
825 | - /* Single threaded */ | |
826 | - static struct resource __initdata res = { | |
827 | - .name = "IRQ", | |
828 | - .flags = IORESOURCE_IRQ, | |
829 | - }; | |
830 | - res.start = irq; | |
831 | - platform_device_add_resources(pdev, &res, 1); | |
832 | -} | |
833 | - | |
834 | -static void __init sfi_handle_ipc_dev(struct sfi_device_table_entry *entry) | |
835 | -{ | |
836 | - const struct devs_id *dev = device_ids; | |
837 | - struct platform_device *pdev; | |
838 | - void *pdata = NULL; | |
839 | - | |
840 | - while (dev->name[0]) { | |
841 | - if (dev->type == SFI_DEV_TYPE_IPC && | |
842 | - !strncmp(dev->name, entry->name, SFI_NAME_LEN)) { | |
843 | - pdata = dev->get_platform_data(entry); | |
844 | - break; | |
845 | - } | |
846 | - dev++; | |
847 | - } | |
848 | - | |
849 | - /* | |
850 | - * On Medfield the platform device creation is handled by the MSIC | |
851 | - * MFD driver so we don't need to do it here. | |
852 | - */ | |
853 | - if (mrst_has_msic()) | |
854 | - return; | |
855 | - | |
856 | - pdev = platform_device_alloc(entry->name, 0); | |
857 | - if (pdev == NULL) { | |
858 | - pr_err("out of memory for SFI platform device '%s'.\n", | |
859 | - entry->name); | |
860 | - return; | |
861 | - } | |
862 | - install_irq_resource(pdev, entry->irq); | |
863 | - | |
864 | - pdev->dev.platform_data = pdata; | |
865 | - intel_scu_device_register(pdev); | |
866 | -} | |
867 | - | |
868 | -static void __init sfi_handle_spi_dev(struct spi_board_info *spi_info) | |
869 | -{ | |
870 | - const struct devs_id *dev = device_ids; | |
871 | - void *pdata = NULL; | |
872 | - | |
873 | - while (dev->name[0]) { | |
874 | - if (dev->type == SFI_DEV_TYPE_SPI && | |
875 | - !strncmp(dev->name, spi_info->modalias, | |
876 | - SFI_NAME_LEN)) { | |
877 | - pdata = dev->get_platform_data(spi_info); | |
878 | - break; | |
879 | - } | |
880 | - dev++; | |
881 | - } | |
882 | - spi_info->platform_data = pdata; | |
883 | - if (dev->delay) | |
884 | - intel_scu_spi_device_register(spi_info); | |
885 | - else | |
886 | - spi_register_board_info(spi_info, 1); | |
887 | -} | |
888 | - | |
889 | -static void __init sfi_handle_i2c_dev(int bus, struct i2c_board_info *i2c_info) | |
890 | -{ | |
891 | - const struct devs_id *dev = device_ids; | |
892 | - void *pdata = NULL; | |
893 | - | |
894 | - while (dev->name[0]) { | |
895 | - if (dev->type == SFI_DEV_TYPE_I2C && | |
896 | - !strncmp(dev->name, i2c_info->type, SFI_NAME_LEN)) { | |
897 | - pdata = dev->get_platform_data(i2c_info); | |
898 | - break; | |
899 | - } | |
900 | - dev++; | |
901 | - } | |
902 | - i2c_info->platform_data = pdata; | |
903 | - | |
904 | - if (dev->delay) | |
905 | - intel_scu_i2c_device_register(bus, i2c_info); | |
906 | - else | |
907 | - i2c_register_board_info(bus, i2c_info, 1); | |
908 | -} | |
909 | - | |
910 | - | |
911 | -static int __init sfi_parse_devs(struct sfi_table_header *table) | |
912 | -{ | |
913 | - struct sfi_table_simple *sb; | |
914 | - struct sfi_device_table_entry *pentry; | |
915 | - struct spi_board_info spi_info; | |
916 | - struct i2c_board_info i2c_info; | |
917 | - int num, i, bus; | |
918 | - int ioapic; | |
919 | - struct io_apic_irq_attr irq_attr; | |
920 | - | |
921 | - sb = (struct sfi_table_simple *)table; | |
922 | - num = SFI_GET_NUM_ENTRIES(sb, struct sfi_device_table_entry); | |
923 | - pentry = (struct sfi_device_table_entry *)sb->pentry; | |
924 | - | |
925 | - for (i = 0; i < num; i++, pentry++) { | |
926 | - int irq = pentry->irq; | |
927 | - | |
928 | - if (irq != (u8)0xff) { /* native RTE case */ | |
929 | - /* these SPI2 devices are not exposed to system as PCI | |
930 | - * devices, but they have separate RTE entry in IOAPIC | |
931 | - * so we have to enable them one by one here | |
932 | - */ | |
933 | - ioapic = mp_find_ioapic(irq); | |
934 | - irq_attr.ioapic = ioapic; | |
935 | - irq_attr.ioapic_pin = irq; | |
936 | - irq_attr.trigger = 1; | |
937 | - irq_attr.polarity = 1; | |
938 | - io_apic_set_pci_routing(NULL, irq, &irq_attr); | |
939 | - } else | |
940 | - irq = 0; /* No irq */ | |
941 | - | |
942 | - switch (pentry->type) { | |
943 | - case SFI_DEV_TYPE_IPC: | |
944 | - pr_debug("info[%2d]: IPC bus, name = %16.16s, " | |
945 | - "irq = 0x%2x\n", i, pentry->name, pentry->irq); | |
946 | - sfi_handle_ipc_dev(pentry); | |
947 | - break; | |
948 | - case SFI_DEV_TYPE_SPI: | |
949 | - memset(&spi_info, 0, sizeof(spi_info)); | |
950 | - strncpy(spi_info.modalias, pentry->name, SFI_NAME_LEN); | |
951 | - spi_info.irq = irq; | |
952 | - spi_info.bus_num = pentry->host_num; | |
953 | - spi_info.chip_select = pentry->addr; | |
954 | - spi_info.max_speed_hz = pentry->max_freq; | |
955 | - pr_debug("info[%2d]: SPI bus = %d, name = %16.16s, " | |
956 | - "irq = 0x%2x, max_freq = %d, cs = %d\n", i, | |
957 | - spi_info.bus_num, | |
958 | - spi_info.modalias, | |
959 | - spi_info.irq, | |
960 | - spi_info.max_speed_hz, | |
961 | - spi_info.chip_select); | |
962 | - sfi_handle_spi_dev(&spi_info); | |
963 | - break; | |
964 | - case SFI_DEV_TYPE_I2C: | |
965 | - memset(&i2c_info, 0, sizeof(i2c_info)); | |
966 | - bus = pentry->host_num; | |
967 | - strncpy(i2c_info.type, pentry->name, SFI_NAME_LEN); | |
968 | - i2c_info.irq = irq; | |
969 | - i2c_info.addr = pentry->addr; | |
970 | - pr_debug("info[%2d]: I2C bus = %d, name = %16.16s, " | |
971 | - "irq = 0x%2x, addr = 0x%x\n", i, bus, | |
972 | - i2c_info.type, | |
973 | - i2c_info.irq, | |
974 | - i2c_info.addr); | |
975 | - sfi_handle_i2c_dev(bus, &i2c_info); | |
976 | - break; | |
977 | - case SFI_DEV_TYPE_UART: | |
978 | - case SFI_DEV_TYPE_HSI: | |
979 | - default: | |
980 | - ; | |
981 | - } | |
982 | - } | |
983 | - return 0; | |
984 | -} | |
985 | - | |
986 | -static int __init mrst_platform_init(void) | |
987 | -{ | |
988 | - sfi_table_parse(SFI_SIG_GPIO, NULL, NULL, sfi_parse_gpio); | |
989 | - sfi_table_parse(SFI_SIG_DEVS, NULL, NULL, sfi_parse_devs); | |
990 | - return 0; | |
991 | -} | |
992 | -arch_initcall(mrst_platform_init); | |
993 | - | |
994 | -/* | |
995 | - * we will search these buttons in SFI GPIO table (by name) | |
996 | - * and register them dynamically. Please add all possible | |
997 | - * buttons here, we will shrink them if no GPIO found. | |
998 | - */ | |
999 | -static struct gpio_keys_button gpio_button[] = { | |
1000 | - {KEY_POWER, -1, 1, "power_btn", EV_KEY, 0, 3000}, | |
1001 | - {KEY_PROG1, -1, 1, "prog_btn1", EV_KEY, 0, 20}, | |
1002 | - {KEY_PROG2, -1, 1, "prog_btn2", EV_KEY, 0, 20}, | |
1003 | - {SW_LID, -1, 1, "lid_switch", EV_SW, 0, 20}, | |
1004 | - {KEY_VOLUMEUP, -1, 1, "vol_up", EV_KEY, 0, 20}, | |
1005 | - {KEY_VOLUMEDOWN, -1, 1, "vol_down", EV_KEY, 0, 20}, | |
1006 | - {KEY_CAMERA, -1, 1, "camera_full", EV_KEY, 0, 20}, | |
1007 | - {KEY_CAMERA_FOCUS, -1, 1, "camera_half", EV_KEY, 0, 20}, | |
1008 | - {SW_KEYPAD_SLIDE, -1, 1, "MagSw1", EV_SW, 0, 20}, | |
1009 | - {SW_KEYPAD_SLIDE, -1, 1, "MagSw2", EV_SW, 0, 20}, | |
1010 | -}; | |
1011 | - | |
1012 | -static struct gpio_keys_platform_data mrst_gpio_keys = { | |
1013 | - .buttons = gpio_button, | |
1014 | - .rep = 1, | |
1015 | - .nbuttons = -1, /* will fill it after search */ | |
1016 | -}; | |
1017 | - | |
1018 | -static struct platform_device pb_device = { | |
1019 | - .name = "gpio-keys", | |
1020 | - .id = -1, | |
1021 | - .dev = { | |
1022 | - .platform_data = &mrst_gpio_keys, | |
1023 | - }, | |
1024 | -}; | |
1025 | - | |
1026 | -/* | |
1027 | - * Shrink the non-existent buttons, register the gpio button | |
1028 | - * device if there is some | |
1029 | - */ | |
1030 | -static int __init pb_keys_init(void) | |
1031 | -{ | |
1032 | - struct gpio_keys_button *gb = gpio_button; | |
1033 | - int i, num, good = 0; | |
1034 | - | |
1035 | - num = sizeof(gpio_button) / sizeof(struct gpio_keys_button); | |
1036 | - for (i = 0; i < num; i++) { | |
1037 | - gb[i].gpio = get_gpio_by_name(gb[i].desc); | |
1038 | - pr_debug("info[%2d]: name = %s, gpio = %d\n", i, gb[i].desc, | |
1039 | - gb[i].gpio); | |
1040 | - if (gb[i].gpio == -1) | |
1041 | - continue; | |
1042 | - | |
1043 | - if (i != good) | |
1044 | - gb[good] = gb[i]; | |
1045 | - good++; | |
1046 | - } | |
1047 | - | |
1048 | - if (good) { | |
1049 | - mrst_gpio_keys.nbuttons = good; | |
1050 | - return platform_device_register(&pb_device); | |
1051 | - } | |
1052 | - return 0; | |
1053 | -} | |
1054 | -late_initcall(pb_keys_init); |
arch/x86/platform/mrst/vrtc.c
1 | -/* | |
2 | - * vrtc.c: Driver for virtual RTC device on Intel MID platform | |
3 | - * | |
4 | - * (C) Copyright 2009 Intel Corporation | |
5 | - * | |
6 | - * This program is free software; you can redistribute it and/or | |
7 | - * modify it under the terms of the GNU General Public License | |
8 | - * as published by the Free Software Foundation; version 2 | |
9 | - * of the License. | |
10 | - * | |
11 | - * Note: | |
12 | - * VRTC is emulated by system controller firmware, the real HW | |
13 | - * RTC is located in the PMIC device. SCU FW shadows PMIC RTC | |
14 | - * in a memory mapped IO space that is visible to the host IA | |
15 | - * processor. | |
16 | - * | |
17 | - * This driver is based on RTC CMOS driver. | |
18 | - */ | |
19 | - | |
20 | -#include <linux/kernel.h> | |
21 | -#include <linux/export.h> | |
22 | -#include <linux/init.h> | |
23 | -#include <linux/sfi.h> | |
24 | -#include <linux/platform_device.h> | |
25 | - | |
26 | -#include <asm/mrst.h> | |
27 | -#include <asm/mrst-vrtc.h> | |
28 | -#include <asm/time.h> | |
29 | -#include <asm/fixmap.h> | |
30 | - | |
31 | -static unsigned char __iomem *vrtc_virt_base; | |
32 | - | |
33 | -unsigned char vrtc_cmos_read(unsigned char reg) | |
34 | -{ | |
35 | - unsigned char retval; | |
36 | - | |
37 | - /* vRTC's registers range from 0x0 to 0xD */ | |
38 | - if (reg > 0xd || !vrtc_virt_base) | |
39 | - return 0xff; | |
40 | - | |
41 | - lock_cmos_prefix(reg); | |
42 | - retval = __raw_readb(vrtc_virt_base + (reg << 2)); | |
43 | - lock_cmos_suffix(reg); | |
44 | - return retval; | |
45 | -} | |
46 | -EXPORT_SYMBOL_GPL(vrtc_cmos_read); | |
47 | - | |
48 | -void vrtc_cmos_write(unsigned char val, unsigned char reg) | |
49 | -{ | |
50 | - if (reg > 0xd || !vrtc_virt_base) | |
51 | - return; | |
52 | - | |
53 | - lock_cmos_prefix(reg); | |
54 | - __raw_writeb(val, vrtc_virt_base + (reg << 2)); | |
55 | - lock_cmos_suffix(reg); | |
56 | -} | |
57 | -EXPORT_SYMBOL_GPL(vrtc_cmos_write); | |
58 | - | |
59 | -void vrtc_get_time(struct timespec *now) | |
60 | -{ | |
61 | - u8 sec, min, hour, mday, mon; | |
62 | - unsigned long flags; | |
63 | - u32 year; | |
64 | - | |
65 | - spin_lock_irqsave(&rtc_lock, flags); | |
66 | - | |
67 | - while ((vrtc_cmos_read(RTC_FREQ_SELECT) & RTC_UIP)) | |
68 | - cpu_relax(); | |
69 | - | |
70 | - sec = vrtc_cmos_read(RTC_SECONDS); | |
71 | - min = vrtc_cmos_read(RTC_MINUTES); | |
72 | - hour = vrtc_cmos_read(RTC_HOURS); | |
73 | - mday = vrtc_cmos_read(RTC_DAY_OF_MONTH); | |
74 | - mon = vrtc_cmos_read(RTC_MONTH); | |
75 | - year = vrtc_cmos_read(RTC_YEAR); | |
76 | - | |
77 | - spin_unlock_irqrestore(&rtc_lock, flags); | |
78 | - | |
79 | - /* vRTC YEAR reg contains the offset to 1972 */ | |
80 | - year += 1972; | |
81 | - | |
82 | - pr_info("vRTC: sec: %d min: %d hour: %d day: %d " | |
83 | - "mon: %d year: %d\n", sec, min, hour, mday, mon, year); | |
84 | - | |
85 | - now->tv_sec = mktime(year, mon, mday, hour, min, sec); | |
86 | - now->tv_nsec = 0; | |
87 | -} | |
88 | - | |
89 | -int vrtc_set_mmss(const struct timespec *now) | |
90 | -{ | |
91 | - unsigned long flags; | |
92 | - struct rtc_time tm; | |
93 | - int year; | |
94 | - int retval = 0; | |
95 | - | |
96 | - rtc_time_to_tm(now->tv_sec, &tm); | |
97 | - if (!rtc_valid_tm(&tm) && tm.tm_year >= 72) { | |
98 | - /* | |
99 | - * tm.year is the number of years since 1900, and the | |
100 | - * vrtc need the years since 1972. | |
101 | - */ | |
102 | - year = tm.tm_year - 72; | |
103 | - spin_lock_irqsave(&rtc_lock, flags); | |
104 | - vrtc_cmos_write(year, RTC_YEAR); | |
105 | - vrtc_cmos_write(tm.tm_mon, RTC_MONTH); | |
106 | - vrtc_cmos_write(tm.tm_mday, RTC_DAY_OF_MONTH); | |
107 | - vrtc_cmos_write(tm.tm_hour, RTC_HOURS); | |
108 | - vrtc_cmos_write(tm.tm_min, RTC_MINUTES); | |
109 | - vrtc_cmos_write(tm.tm_sec, RTC_SECONDS); | |
110 | - spin_unlock_irqrestore(&rtc_lock, flags); | |
111 | - } else { | |
112 | - pr_err("%s: Invalid vRTC value: write of %lx to vRTC failed\n", | |
113 | - __FUNCTION__, now->tv_sec); | |
114 | - retval = -EINVAL; | |
115 | - } | |
116 | - return retval; | |
117 | -} | |
118 | - | |
119 | -void __init mrst_rtc_init(void) | |
120 | -{ | |
121 | - unsigned long vrtc_paddr; | |
122 | - | |
123 | - sfi_table_parse(SFI_SIG_MRTC, NULL, NULL, sfi_parse_mrtc); | |
124 | - | |
125 | - vrtc_paddr = sfi_mrtc_array[0].phys_addr; | |
126 | - if (!sfi_mrtc_num || !vrtc_paddr) | |
127 | - return; | |
128 | - | |
129 | - vrtc_virt_base = (void __iomem *)set_fixmap_offset_nocache(FIX_LNW_VRTC, | |
130 | - vrtc_paddr); | |
131 | - x86_platform.get_wallclock = vrtc_get_time; | |
132 | - x86_platform.set_wallclock = vrtc_set_mmss; | |
133 | -} | |
134 | - | |
135 | -/* | |
136 | - * The Moorestown platform has a memory mapped virtual RTC device that emulates | |
137 | - * the programming interface of the RTC. | |
138 | - */ | |
139 | - | |
140 | -static struct resource vrtc_resources[] = { | |
141 | - [0] = { | |
142 | - .flags = IORESOURCE_MEM, | |
143 | - }, | |
144 | - [1] = { | |
145 | - .flags = IORESOURCE_IRQ, | |
146 | - } | |
147 | -}; | |
148 | - | |
149 | -static struct platform_device vrtc_device = { | |
150 | - .name = "rtc_mrst", | |
151 | - .id = -1, | |
152 | - .resource = vrtc_resources, | |
153 | - .num_resources = ARRAY_SIZE(vrtc_resources), | |
154 | -}; | |
155 | - | |
156 | -/* Register the RTC device if appropriate */ | |
157 | -static int __init mrst_device_create(void) | |
158 | -{ | |
159 | - /* No Moorestown, no device */ | |
160 | - if (!mrst_identify_cpu()) | |
161 | - return -ENODEV; | |
162 | - /* No timer, no device */ | |
163 | - if (!sfi_mrtc_num) | |
164 | - return -ENODEV; | |
165 | - | |
166 | - /* iomem resource */ | |
167 | - vrtc_resources[0].start = sfi_mrtc_array[0].phys_addr; | |
168 | - vrtc_resources[0].end = sfi_mrtc_array[0].phys_addr + | |
169 | - MRST_VRTC_MAP_SZ; | |
170 | - /* irq resource */ | |
171 | - vrtc_resources[1].start = sfi_mrtc_array[0].irq; | |
172 | - vrtc_resources[1].end = sfi_mrtc_array[0].irq; | |
173 | - | |
174 | - return platform_device_register(&vrtc_device); | |
175 | -} | |
176 | - | |
177 | -module_init(mrst_device_create); |
drivers/gpu/drm/gma500/mdfld_dsi_output.h
... | ... | @@ -39,7 +39,7 @@ |
39 | 39 | #include "psb_intel_reg.h" |
40 | 40 | #include "mdfld_output.h" |
41 | 41 | |
42 | -#include <asm/mrst.h> | |
42 | +#include <asm/intel-mid.h> | |
43 | 43 | |
44 | 44 | #define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end)) |
45 | 45 | #define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) |
drivers/gpu/drm/gma500/oaktrail_device.c
drivers/gpu/drm/gma500/oaktrail_lvds.c
drivers/platform/x86/intel_scu_ipc.c
drivers/rtc/rtc-mrst.c
drivers/watchdog/intel_scu_watchdog.c