x86: dtb: Add device tree support for HPET
[deliverable/linux.git] / arch / x86 / kernel / devicetree.c
CommitLineData
da6b737b
SAS
1/*
2 * Architecture specific OF callbacks.
3 */
4#include <linux/bootmem.h>
5#include <linux/io.h>
19c4f5f7 6#include <linux/interrupt.h>
da6b737b
SAS
7#include <linux/list.h>
8#include <linux/of.h>
9#include <linux/of_fdt.h>
3879a6f3 10#include <linux/of_address.h>
da6b737b
SAS
11#include <linux/of_platform.h>
12#include <linux/slab.h>
13
ffb9fc68 14#include <asm/hpet.h>
19c4f5f7 15#include <asm/irq_controller.h>
3879a6f3 16#include <asm/apic.h>
19c4f5f7 17
3879a6f3 18__initdata u64 initial_dtb;
da6b737b 19char __initdata cmd_line[COMMAND_LINE_SIZE];
19c4f5f7
SAS
20static LIST_HEAD(irq_domains);
21static DEFINE_RAW_SPINLOCK(big_irq_lock);
22
3879a6f3
SAS
23int __initdata of_ioapic;
24
19c4f5f7
SAS
25void add_interrupt_host(struct irq_domain *ih)
26{
27 unsigned long flags;
28
29 raw_spin_lock_irqsave(&big_irq_lock, flags);
30 list_add(&ih->l, &irq_domains);
31 raw_spin_unlock_irqrestore(&big_irq_lock, flags);
32}
33
34static struct irq_domain *get_ih_from_node(struct device_node *controller)
35{
36 struct irq_domain *ih, *found = NULL;
37 unsigned long flags;
38
39 raw_spin_lock_irqsave(&big_irq_lock, flags);
40 list_for_each_entry(ih, &irq_domains, l) {
41 if (ih->controller == controller) {
42 found = ih;
43 break;
44 }
45 }
46 raw_spin_unlock_irqrestore(&big_irq_lock, flags);
47 return found;
48}
da6b737b
SAS
49
50unsigned int irq_create_of_mapping(struct device_node *controller,
51 const u32 *intspec, unsigned int intsize)
52{
19c4f5f7
SAS
53 struct irq_domain *ih;
54 u32 virq, type;
55 int ret;
da6b737b 56
19c4f5f7
SAS
57 ih = get_ih_from_node(controller);
58 if (!ih)
59 return 0;
60 ret = ih->xlate(ih, intspec, intsize, &virq, &type);
61 if (ret)
62 return ret;
63 if (type == IRQ_TYPE_NONE)
64 return virq;
65 /* set the mask if it is different from current */
66 if (type == (irq_to_desc(virq)->status & IRQF_TRIGGER_MASK))
67 set_irq_type(virq, type);
68 return virq;
da6b737b
SAS
69}
70EXPORT_SYMBOL_GPL(irq_create_of_mapping);
71
72unsigned long pci_address_to_pio(phys_addr_t address)
73{
74 /*
75 * The ioport address can be directly used by inX / outX
76 */
77 BUG_ON(address >= (1 << 16));
78 return (unsigned long)address;
79}
80EXPORT_SYMBOL_GPL(pci_address_to_pio);
81
82void __init early_init_dt_scan_chosen_arch(unsigned long node)
83{
84 BUG();
85}
86
87void __init early_init_dt_add_memory_arch(u64 base, u64 size)
88{
89 BUG();
90}
91
92void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
93{
94 return __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS));
95}
96
97void __init add_dtb(u64 data)
98{
3879a6f3
SAS
99 initial_dtb = data + offsetof(struct setup_data, data);
100}
101
ffb9fc68
SAS
102static void __init dtb_setup_hpet(void)
103{
104 struct device_node *dn;
105 struct resource r;
106 int ret;
107
108 dn = of_find_compatible_node(NULL, NULL, "intel,ce4100-hpet");
109 if (!dn)
110 return;
111 ret = of_address_to_resource(dn, 0, &r);
112 if (ret) {
113 WARN_ON(1);
114 return;
115 }
116 hpet_address = r.start;
117}
118
3879a6f3
SAS
119static void __init dtb_lapic_setup(void)
120{
121#ifdef CONFIG_X86_LOCAL_APIC
122 if (apic_force_enable())
123 return;
124
125 smp_found_config = 1;
126 pic_mode = 1;
127 /* Required for ioapic registration */
128 set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr);
129 if (boot_cpu_physical_apicid == -1U)
130 boot_cpu_physical_apicid = read_apic_id();
131
132 generic_processor_info(boot_cpu_physical_apicid,
133 GET_APIC_VERSION(apic_read(APIC_LVR)));
134#endif
135}
136
137#ifdef CONFIG_X86_IO_APIC
138static unsigned int ioapic_id;
139
140static void __init dtb_add_ioapic(struct device_node *dn)
141{
142 struct resource r;
143 int ret;
144
145 ret = of_address_to_resource(dn, 0, &r);
146 if (ret) {
147 printk(KERN_ERR "Can't obtain address from node %s.\n",
148 dn->full_name);
149 return;
150 }
151 mp_register_ioapic(++ioapic_id, r.start, gsi_top);
152}
153
154static void __init dtb_ioapic_setup(void)
155{
156 struct device_node *dn;
157
158 if (!smp_found_config)
159 return;
160
161 for_each_compatible_node(dn, NULL, "intel,ce4100-ioapic")
162 dtb_add_ioapic(dn);
163
164 if (nr_ioapics) {
165 of_ioapic = 1;
166 return;
167 }
168 printk(KERN_ERR "Error: No information about IO-APIC in OF.\n");
169 smp_found_config = 0;
170}
171#else
172static void __init dtb_ioapic_setup(void) {}
173#endif
174
175static void __init dtb_apic_setup(void)
176{
177 dtb_lapic_setup();
178 dtb_ioapic_setup();
179}
180
181void __init x86_dtb_find_config(void)
182{
183 if (initial_dtb)
184 smp_found_config = 1;
185 else
186 printk(KERN_ERR "Missing device tree!.\n");
187}
188
189void __init x86_dtb_get_config(unsigned int unused)
190{
191 u32 size, map_len;
192 void *new_dtb;
193
194 if (!initial_dtb)
195 return;
196
197 map_len = max(PAGE_SIZE - (initial_dtb & ~PAGE_MASK),
198 (u64)sizeof(struct boot_param_header));
199
200 initial_boot_params = early_memremap(initial_dtb, map_len);
201 size = be32_to_cpu(initial_boot_params->totalsize);
202 if (map_len < size) {
203 early_iounmap(initial_boot_params, map_len);
204 initial_boot_params = early_memremap(initial_dtb, size);
205 map_len = size;
206 }
207
208 new_dtb = alloc_bootmem(size);
209 memcpy(new_dtb, initial_boot_params, size);
210 early_iounmap(initial_boot_params, map_len);
211
212 initial_boot_params = new_dtb;
213
214 /* root level address cells */
215 of_scan_flat_dt(early_init_dt_scan_root, NULL);
216
217 unflatten_device_tree();
ffb9fc68 218 dtb_setup_hpet();
3879a6f3 219 dtb_apic_setup();
da6b737b 220}
This page took 0.166474 seconds and 5 git commands to generate.