]>
Commit | Line | Data |
---|---|---|
a65b25d1 BM |
1 | /* |
2 | * Copyright (C) 2015, Bin Meng <[email protected]> | |
3 | * | |
4 | * SPDX-License-Identifier: GPL-2.0+ | |
5 | */ | |
6 | ||
7 | #include <common.h> | |
6039200c | 8 | #include <pci.h> |
18686590 | 9 | #include <qfw.h> |
5c564226 | 10 | #include <asm/irq.h> |
a65b25d1 BM |
11 | #include <asm/post.h> |
12 | #include <asm/processor.h> | |
48748595 BM |
13 | #include <asm/arch/device.h> |
14 | #include <asm/arch/qemu.h> | |
15 | ||
16 | static bool i440fx; | |
17 | ||
2e82e745 MY |
18 | #ifdef CONFIG_QFW |
19 | ||
331ba7db | 20 | /* on x86, the qfw registers are all IO ports */ |
2e82e745 MY |
21 | #define FW_CONTROL_PORT 0x510 |
22 | #define FW_DATA_PORT 0x511 | |
23 | #define FW_DMA_PORT_LOW 0x514 | |
24 | #define FW_DMA_PORT_HIGH 0x518 | |
25 | ||
26 | static void qemu_x86_fwcfg_read_entry_pio(uint16_t entry, | |
27 | uint32_t size, void *address) | |
28 | { | |
29 | uint32_t i = 0; | |
30 | uint8_t *data = address; | |
31 | ||
32 | /* | |
33 | * writting FW_CFG_INVALID will cause read operation to resume at | |
34 | * last offset, otherwise read will start at offset 0 | |
331ba7db MY |
35 | * |
36 | * Note: on platform where the control register is IO port, the | |
37 | * endianness is little endian. | |
2e82e745 MY |
38 | */ |
39 | if (entry != FW_CFG_INVALID) | |
331ba7db MY |
40 | outw(cpu_to_le16(entry), FW_CONTROL_PORT); |
41 | ||
42 | /* the endianness of data register is string-preserving */ | |
2e82e745 MY |
43 | while (size--) |
44 | data[i++] = inb(FW_DATA_PORT); | |
45 | } | |
46 | ||
47 | static void qemu_x86_fwcfg_read_entry_dma(struct fw_cfg_dma_access *dma) | |
48 | { | |
331ba7db | 49 | /* the DMA address register is big endian */ |
2e82e745 MY |
50 | outl(cpu_to_be32((uint32_t)dma), FW_DMA_PORT_HIGH); |
51 | ||
52 | while (be32_to_cpu(dma->control) & ~FW_CFG_DMA_ERROR) | |
53 | __asm__ __volatile__ ("pause"); | |
54 | } | |
55 | ||
56 | static struct fw_cfg_arch_ops fwcfg_x86_ops = { | |
57 | .arch_read_pio = qemu_x86_fwcfg_read_entry_pio, | |
58 | .arch_read_dma = qemu_x86_fwcfg_read_entry_dma | |
59 | }; | |
60 | #endif | |
61 | ||
a3b15a05 MY |
62 | static void enable_pm_piix(void) |
63 | { | |
64 | u8 en; | |
65 | u16 cmd; | |
66 | ||
67 | /* Set the PM I/O base */ | |
6039200c | 68 | pci_write_config32(PIIX_PM, PMBA, CONFIG_ACPI_PM1_BASE | 1); |
a3b15a05 MY |
69 | |
70 | /* Enable access to the PM I/O space */ | |
6039200c | 71 | pci_read_config16(PIIX_PM, PCI_COMMAND, &cmd); |
a3b15a05 | 72 | cmd |= PCI_COMMAND_IO; |
6039200c | 73 | pci_write_config16(PIIX_PM, PCI_COMMAND, cmd); |
a3b15a05 MY |
74 | |
75 | /* PM I/O Space Enable (PMIOSE) */ | |
6039200c | 76 | pci_read_config8(PIIX_PM, PMREGMISC, &en); |
a3b15a05 | 77 | en |= PMIOSE; |
6039200c | 78 | pci_write_config8(PIIX_PM, PMREGMISC, en); |
a3b15a05 MY |
79 | } |
80 | ||
81 | static void enable_pm_ich9(void) | |
82 | { | |
83 | /* Set the PM I/O base */ | |
6039200c | 84 | pci_write_config32(ICH9_PM, PMBA, CONFIG_ACPI_PM1_BASE | 1); |
a3b15a05 MY |
85 | } |
86 | ||
48748595 BM |
87 | static void qemu_chipset_init(void) |
88 | { | |
89 | u16 device, xbcs; | |
90 | int pam, i; | |
91 | ||
92 | /* | |
93 | * i440FX and Q35 chipset have different PAM register offset, but with | |
94 | * the same bitfield layout. Here we determine the offset based on its | |
95 | * PCI device ID. | |
96 | */ | |
6039200c | 97 | pci_read_config16(PCI_BDF(0, 0, 0), PCI_DEVICE_ID, &device); |
48748595 BM |
98 | i440fx = (device == PCI_DEVICE_ID_INTEL_82441); |
99 | pam = i440fx ? I440FX_PAM : Q35_PAM; | |
100 | ||
101 | /* | |
102 | * Initialize Programmable Attribute Map (PAM) Registers | |
103 | * | |
104 | * Configure legacy segments C/D/E/F to system RAM | |
105 | */ | |
106 | for (i = 0; i < PAM_NUM; i++) | |
6039200c | 107 | pci_write_config8(PCI_BDF(0, 0, 0), pam + i, PAM_RW); |
48748595 BM |
108 | |
109 | if (i440fx) { | |
110 | /* | |
111 | * Enable legacy IDE I/O ports decode | |
112 | * | |
113 | * Note: QEMU always decode legacy IDE I/O port on PIIX chipset. | |
114 | * However Linux ata_piix driver does sanity check on these two | |
115 | * registers to see whether legacy ports decode is turned on. | |
116 | * This is to make Linux ata_piix driver happy. | |
117 | */ | |
6039200c BM |
118 | pci_write_config16(PIIX_IDE, IDE0_TIM, IDE_DECODE_EN); |
119 | pci_write_config16(PIIX_IDE, IDE1_TIM, IDE_DECODE_EN); | |
48748595 BM |
120 | |
121 | /* Enable I/O APIC */ | |
6039200c | 122 | pci_read_config16(PIIX_ISA, XBCS, &xbcs); |
48748595 | 123 | xbcs |= APIC_EN; |
6039200c | 124 | pci_write_config16(PIIX_ISA, XBCS, xbcs); |
a3b15a05 MY |
125 | |
126 | enable_pm_piix(); | |
48748595 BM |
127 | } else { |
128 | /* Configure PCIe ECAM base address */ | |
6039200c BM |
129 | pci_write_config32(PCI_BDF(0, 0, 0), PCIEX_BAR, |
130 | CONFIG_PCIE_ECAM_BASE | BAR_EN); | |
a3b15a05 MY |
131 | |
132 | enable_pm_ich9(); | |
48748595 | 133 | } |
f60df20a | 134 | |
fcf5c041 | 135 | #ifdef CONFIG_QFW |
2e82e745 | 136 | qemu_fwcfg_init(&fwcfg_x86_ops); |
fcf5c041 | 137 | #endif |
48748595 | 138 | } |
a65b25d1 BM |
139 | |
140 | int arch_cpu_init(void) | |
141 | { | |
142 | int ret; | |
143 | ||
144 | post_code(POST_CPU_INIT); | |
a65b25d1 BM |
145 | |
146 | ret = x86_cpu_init_f(); | |
147 | if (ret) | |
148 | return ret; | |
149 | ||
150 | return 0; | |
151 | } | |
152 | ||
eeae5100 | 153 | #ifndef CONFIG_EFI_STUB |
a65b25d1 BM |
154 | int print_cpuinfo(void) |
155 | { | |
156 | post_code(POST_CPU_INFO); | |
157 | return default_print_cpuinfo(); | |
158 | } | |
eeae5100 | 159 | #endif |
a65b25d1 BM |
160 | |
161 | void reset_cpu(ulong addr) | |
162 | { | |
163 | /* cold reset */ | |
164 | x86_full_reset(); | |
165 | } | |
5c564226 | 166 | |
48748595 BM |
167 | int arch_early_init_r(void) |
168 | { | |
169 | qemu_chipset_init(); | |
170 | ||
171 | return 0; | |
172 | } | |
173 | ||
48748595 BM |
174 | #ifdef CONFIG_GENERATE_MP_TABLE |
175 | int mp_determine_pci_dstirq(int bus, int dev, int func, int pirq) | |
176 | { | |
177 | u8 irq; | |
178 | ||
179 | if (i440fx) { | |
180 | /* | |
181 | * Not like most x86 platforms, the PIRQ[A-D] on PIIX3 are not | |
182 | * connected to I/O APIC INTPIN#16-19. Instead they are routed | |
183 | * to an irq number controled by the PIRQ routing register. | |
184 | */ | |
6039200c BM |
185 | pci_read_config8(PCI_BDF(bus, dev, func), |
186 | PCI_INTERRUPT_LINE, &irq); | |
48748595 BM |
187 | } else { |
188 | /* | |
189 | * ICH9's PIRQ[A-H] are not consecutive numbers from 0 to 7. | |
190 | * PIRQ[A-D] still maps to [0-3] but PIRQ[E-H] maps to [8-11]. | |
191 | */ | |
192 | irq = pirq < 8 ? pirq + 16 : pirq + 12; | |
193 | } | |
194 | ||
195 | return irq; | |
196 | } | |
197 | #endif |