Commit | Line | Data |
---|---|---|
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 | 19 | char __initdata cmd_line[COMMAND_LINE_SIZE]; |
19c4f5f7 SAS |
20 | static LIST_HEAD(irq_domains); |
21 | static DEFINE_RAW_SPINLOCK(big_irq_lock); | |
22 | ||
3879a6f3 SAS |
23 | int __initdata of_ioapic; |
24 | ||
19c4f5f7 SAS |
25 | void 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 | ||
34 | static 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 | |
50 | unsigned 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 | } |
70 | EXPORT_SYMBOL_GPL(irq_create_of_mapping); | |
71 | ||
72 | unsigned 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 | } | |
80 | EXPORT_SYMBOL_GPL(pci_address_to_pio); | |
81 | ||
82 | void __init early_init_dt_scan_chosen_arch(unsigned long node) | |
83 | { | |
84 | BUG(); | |
85 | } | |
86 | ||
87 | void __init early_init_dt_add_memory_arch(u64 base, u64 size) | |
88 | { | |
89 | BUG(); | |
90 | } | |
91 | ||
92 | void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) | |
93 | { | |
94 | return __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS)); | |
95 | } | |
96 | ||
97 | void __init add_dtb(u64 data) | |
98 | { | |
3879a6f3 SAS |
99 | initial_dtb = data + offsetof(struct setup_data, data); |
100 | } | |
101 | ||
ffb9fc68 SAS |
102 | static 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 |
119 | static 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 | |
138 | static unsigned int ioapic_id; | |
139 | ||
140 | static 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 | ||
154 | static 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 | |
172 | static void __init dtb_ioapic_setup(void) {} | |
173 | #endif | |
174 | ||
175 | static void __init dtb_apic_setup(void) | |
176 | { | |
177 | dtb_lapic_setup(); | |
178 | dtb_ioapic_setup(); | |
179 | } | |
180 | ||
181 | void __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 | ||
189 | void __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 | } |