2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2010 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 #include <grub/types.h>
20 #include <grub/cs5536.h>
22 #include <grub/time.h>
24 #ifdef GRUB_MACHINE_MIPS_LOONGSON
25 #include <grub/machine/kernel.h>
30 GRUB_MOD_LICENSE ("GPLv3+");
33 grub_cs5536_find (grub_pci_device_t
*devp
)
36 auto int NESTED_FUNC_ATTR
hook (grub_pci_device_t dev
,
39 int NESTED_FUNC_ATTR
hook (grub_pci_device_t dev
,
42 if (pciid
== GRUB_CS5536_PCIID
)
51 grub_pci_iterate (hook
);
57 grub_cs5536_read_msr (grub_pci_device_t dev
, grub_uint32_t addr
)
59 grub_uint64_t ret
= 0;
60 grub_pci_write (grub_pci_make_address (dev
, GRUB_CS5536_MSR_MAILBOX_ADDR
),
63 grub_pci_read (grub_pci_make_address (dev
, GRUB_CS5536_MSR_MAILBOX_DATA0
));
64 ret
|= (((grub_uint64_t
)
65 grub_pci_read (grub_pci_make_address (dev
,
66 GRUB_CS5536_MSR_MAILBOX_DATA1
)))
72 grub_cs5536_write_msr (grub_pci_device_t dev
, grub_uint32_t addr
,
75 grub_pci_write (grub_pci_make_address (dev
, GRUB_CS5536_MSR_MAILBOX_ADDR
),
77 grub_pci_write (grub_pci_make_address (dev
, GRUB_CS5536_MSR_MAILBOX_DATA0
),
79 grub_pci_write (grub_pci_make_address (dev
, GRUB_CS5536_MSR_MAILBOX_DATA1
),
84 grub_cs5536_smbus_wait (grub_port_t smbbase
)
86 grub_uint64_t start
= grub_get_time_ms ();
90 status
= grub_inb (smbbase
+ GRUB_CS5536_SMB_REG_STATUS
);
91 if (status
& GRUB_CS5536_SMB_REG_STATUS_SDAST
)
93 if (status
& GRUB_CS5536_SMB_REG_STATUS_BER
)
94 return grub_error (GRUB_ERR_IO
, "SM bus error");
95 if (status
& GRUB_CS5536_SMB_REG_STATUS_NACK
)
96 return grub_error (GRUB_ERR_IO
, "NACK received");
97 if (grub_get_time_ms () > start
+ 40)
98 return grub_error (GRUB_ERR_IO
, "SM stalled");
103 grub_cs5536_read_spd_byte (grub_port_t smbbase
, grub_uint8_t dev
,
104 grub_uint8_t addr
, grub_uint8_t
*res
)
109 grub_outb (grub_inb (smbbase
+ GRUB_CS5536_SMB_REG_CTRL1
)
110 | GRUB_CS5536_SMB_REG_CTRL1_START
,
111 smbbase
+ GRUB_CS5536_SMB_REG_CTRL1
);
113 /* Send device address. */
114 err
= grub_cs5536_smbus_wait (smbbase
);
117 grub_outb (dev
<< 1, smbbase
+ GRUB_CS5536_SMB_REG_DATA
);
120 err
= grub_cs5536_smbus_wait (smbbase
);
123 grub_outb (grub_inb (smbbase
+ GRUB_CS5536_SMB_REG_CTRL1
)
124 | GRUB_CS5536_SMB_REG_CTRL1_ACK
,
125 smbbase
+ GRUB_CS5536_SMB_REG_CTRL1
);
127 /* Send byte address. */
128 grub_outb (addr
, smbbase
+ GRUB_CS5536_SMB_REG_DATA
);
131 err
= grub_cs5536_smbus_wait (smbbase
);
134 grub_outb (grub_inb (smbbase
+ GRUB_CS5536_SMB_REG_CTRL1
)
135 | GRUB_CS5536_SMB_REG_CTRL1_START
,
136 smbbase
+ GRUB_CS5536_SMB_REG_CTRL1
);
138 /* Send device address. */
139 err
= grub_cs5536_smbus_wait (smbbase
);
142 grub_outb ((dev
<< 1) | 1, smbbase
+ GRUB_CS5536_SMB_REG_DATA
);
145 err
= grub_cs5536_smbus_wait (smbbase
);
148 grub_outb (grub_inb (smbbase
+ GRUB_CS5536_SMB_REG_CTRL1
)
149 | GRUB_CS5536_SMB_REG_CTRL1_STOP
,
150 smbbase
+ GRUB_CS5536_SMB_REG_CTRL1
);
152 err
= grub_cs5536_smbus_wait (smbbase
);
155 *res
= grub_inb (smbbase
+ GRUB_CS5536_SMB_REG_DATA
);
157 return GRUB_ERR_NONE
;
161 grub_cs5536_init_smbus (grub_pci_device_t dev
, grub_uint16_t divisor
,
162 grub_port_t
*smbbase
)
164 grub_uint64_t smbbar
;
166 smbbar
= grub_cs5536_read_msr (dev
, GRUB_CS5536_MSR_SMB_BAR
);
169 if (!(smbbar
& GRUB_CS5536_LBAR_ENABLE
))
170 return grub_error(GRUB_ERR_IO
, "SMB controller not enabled\n");
171 *smbbase
= (smbbar
& GRUB_CS5536_LBAR_ADDR_MASK
) + GRUB_MACHINE_PCI_IO_BASE
;
174 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "invalid divisor");
177 grub_outb (0, *smbbase
+ GRUB_CS5536_SMB_REG_CTRL2
);
179 /* Disable interrupts. */
180 grub_outb (0, *smbbase
+ GRUB_CS5536_SMB_REG_CTRL1
);
183 grub_outb (GRUB_CS5536_SMB_REG_ADDR_MASTER
,
184 *smbbase
+ GRUB_CS5536_SMB_REG_ADDR
);
187 grub_outb (((divisor
>> 7) & 0xff), *smbbase
+ GRUB_CS5536_SMB_REG_CTRL3
);
188 grub_outb (((divisor
<< 1) & 0xfe) | GRUB_CS5536_SMB_REG_CTRL2_ENABLE
,
189 *smbbase
+ GRUB_CS5536_SMB_REG_CTRL2
);
191 return GRUB_ERR_NONE
;
195 grub_cs5536_read_spd (grub_port_t smbbase
, grub_uint8_t dev
,
196 struct grub_smbus_spd
*res
)
203 err
= grub_cs5536_read_spd_byte (smbbase
, dev
, 0, &b
);
207 return grub_error (GRUB_ERR_IO
, "no SPD found");
210 ((grub_uint8_t
*) res
)[0] = b
;
211 for (ptr
= 1; ptr
< size
; ptr
++)
213 err
= grub_cs5536_read_spd_byte (smbbase
, dev
, ptr
,
214 &((grub_uint8_t
*) res
)[ptr
]);
218 return GRUB_ERR_NONE
;
222 set_io_space (grub_pci_device_t dev
, int num
, grub_uint16_t start
,
225 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_GL_REGIONS_START
+ num
,
226 ((((grub_uint64_t
) start
+ len
- 4)
227 << GRUB_CS5536_MSR_GL_REGION_IO_TOP_SHIFT
)
228 & GRUB_CS5536_MSR_GL_REGION_TOP_MASK
)
229 | (((grub_uint64_t
) start
230 << GRUB_CS5536_MSR_GL_REGION_IO_BASE_SHIFT
)
231 & GRUB_CS5536_MSR_GL_REGION_BASE_MASK
)
232 | GRUB_CS5536_MSR_GL_REGION_IO
233 | GRUB_CS5536_MSR_GL_REGION_ENABLE
);
237 set_iod (grub_pci_device_t dev
, int num
, int dest
, int start
, int mask
)
239 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_GL_IOD_START
+ num
,
240 ((grub_uint64_t
) dest
<< GRUB_CS5536_IOD_DEST_SHIFT
)
241 | (((grub_uint64_t
) start
& GRUB_CS5536_IOD_ADDR_MASK
)
242 << GRUB_CS5536_IOD_BASE_SHIFT
)
243 | ((mask
& GRUB_CS5536_IOD_ADDR_MASK
)
244 << GRUB_CS5536_IOD_MASK_SHIFT
));
248 set_p2d (grub_pci_device_t dev
, int num
, int dest
, grub_uint32_t start
)
250 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_GL_P2D_START
+ num
,
251 (((grub_uint64_t
) dest
) << GRUB_CS5536_P2D_DEST_SHIFT
)
252 | ((grub_uint64_t
) (start
>> GRUB_CS5536_P2D_LOG_ALIGN
)
253 << GRUB_CS5536_P2D_BASE_SHIFT
)
254 | (((1 << (32 - GRUB_CS5536_P2D_LOG_ALIGN
)) - 1)
255 << GRUB_CS5536_P2D_MASK_SHIFT
));
259 grub_cs5536_init_geode (grub_pci_device_t dev
)
261 /* Enable more BARs. */
262 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_IRQ_MAP_BAR
,
263 GRUB_CS5536_LBAR_TURN_ON
| GRUB_CS5536_LBAR_IRQ_MAP
);
264 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_MFGPT_BAR
,
265 GRUB_CS5536_LBAR_TURN_ON
| GRUB_CS5536_LBAR_MFGPT
);
266 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_ACPI_BAR
,
267 GRUB_CS5536_LBAR_TURN_ON
| GRUB_CS5536_LBAR_ACPI
);
268 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_PM_BAR
,
269 GRUB_CS5536_LBAR_TURN_ON
| GRUB_CS5536_LBAR_PM
);
272 #ifdef GRUB_MACHINE_MIPS_LOONGSON
273 switch (grub_arch_machine
)
275 case GRUB_ARCH_MACHINE_YEELOONG
:
276 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_DIVIL_LEG_IO
,
277 GRUB_CS5536_MSR_DIVIL_LEG_IO_MODE_X86
278 | GRUB_CS5536_MSR_DIVIL_LEG_IO_F_REMAP
279 | GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE0
280 | GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE1
);
282 case GRUB_ARCH_MACHINE_FULOONG2F
:
283 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_DIVIL_LEG_IO
,
284 GRUB_CS5536_MSR_DIVIL_LEG_IO_UART2_COM3
285 | GRUB_CS5536_MSR_DIVIL_LEG_IO_UART1_COM1
286 | GRUB_CS5536_MSR_DIVIL_LEG_IO_MODE_X86
287 | GRUB_CS5536_MSR_DIVIL_LEG_IO_F_REMAP
288 | GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE0
289 | GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE1
);
293 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_DIVIL_IRQ_MAPPER_PRIMARY_MASK
,
294 (~GRUB_CS5536_DIVIL_LPC_INTERRUPTS
) & 0xffff);
295 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_DIVIL_IRQ_MAPPER_LPC_MASK
,
296 GRUB_CS5536_DIVIL_LPC_INTERRUPTS
);
297 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_DIVIL_LPC_SERIAL_IRQ_CONTROL
,
298 GRUB_CS5536_MSR_DIVIL_LPC_SERIAL_IRQ_CONTROL_ENABLE
);
300 /* Initialise USB controller. */
301 /* FIXME: assign adresses dynamically. */
302 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_USB_OHCI_BASE
,
303 GRUB_CS5536_MSR_USB_BASE_BUS_MASTER
304 | GRUB_CS5536_MSR_USB_BASE_MEMORY_ENABLE
306 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_USB_EHCI_BASE
,
307 GRUB_CS5536_MSR_USB_BASE_BUS_MASTER
308 | GRUB_CS5536_MSR_USB_BASE_MEMORY_ENABLE
309 | (0x20ULL
<< GRUB_CS5536_MSR_USB_EHCI_BASE_FLDJ_SHIFT
)
311 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_USB_CONTROLLER_BASE
,
312 GRUB_CS5536_MSR_USB_BASE_BUS_MASTER
313 | GRUB_CS5536_MSR_USB_BASE_MEMORY_ENABLE
| 0x05020000);
314 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_USB_OPTION_CONTROLLER_BASE
,
315 GRUB_CS5536_MSR_USB_BASE_MEMORY_ENABLE
| 0x05022000);
316 set_p2d (dev
, 0, GRUB_CS5536_DESTINATION_USB
, 0x05020000);
317 set_p2d (dev
, 1, GRUB_CS5536_DESTINATION_USB
, 0x05022000);
318 set_p2d (dev
, 5, GRUB_CS5536_DESTINATION_USB
, 0x05024000);
319 set_p2d (dev
, 6, GRUB_CS5536_DESTINATION_USB
, 0x05023000);
322 volatile grub_uint32_t
*oc
;
323 oc
= grub_pci_device_map_range (dev
, 0x05022000,
324 GRUB_CS5536_USB_OPTION_REGS_SIZE
);
326 oc
[GRUB_CS5536_USB_OPTION_REG_UOCMUX
] =
327 (oc
[GRUB_CS5536_USB_OPTION_REG_UOCMUX
]
328 & ~GRUB_CS5536_USB_OPTION_REG_UOCMUX_PMUX_MASK
)
329 | GRUB_CS5536_USB_OPTION_REG_UOCMUX_PMUX_HC
;
330 grub_pci_device_unmap_range (dev
, oc
, GRUB_CS5536_USB_OPTION_REGS_SIZE
);
333 /* Setup IDE controller. */
334 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_IDE_IO_BAR
,
336 | GRUB_CS5536_MSR_IDE_IO_BAR_UNITS
);
337 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_IDE_CFG
,
338 GRUB_CS5536_MSR_IDE_CFG_CHANNEL_ENABLE
);
339 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_IDE_TIMING
,
340 (GRUB_CS5536_MSR_IDE_TIMING_PIO0
341 << GRUB_CS5536_MSR_IDE_TIMING_DRIVE0_SHIFT
)
342 | (GRUB_CS5536_MSR_IDE_TIMING_PIO0
343 << GRUB_CS5536_MSR_IDE_TIMING_DRIVE1_SHIFT
));
344 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_IDE_CAS_TIMING
,
345 (GRUB_CS5536_MSR_IDE_CAS_TIMING_CMD_PIO0
346 << GRUB_CS5536_MSR_IDE_CAS_TIMING_CMD_SHIFT
)
347 | (GRUB_CS5536_MSR_IDE_CAS_TIMING_PIO0
348 << GRUB_CS5536_MSR_IDE_CAS_TIMING_DRIVE0_SHIFT
)
349 | (GRUB_CS5536_MSR_IDE_CAS_TIMING_PIO0
350 << GRUB_CS5536_MSR_IDE_CAS_TIMING_DRIVE1_SHIFT
));
352 /* Setup Geodelink PCI. */
353 grub_cs5536_write_msr (dev
, GRUB_CS5536_MSR_GL_PCI_CTRL
,
354 (4ULL << GRUB_CS5536_MSR_GL_PCI_CTRL_OUT_THR_SHIFT
)
355 | (4ULL << GRUB_CS5536_MSR_GL_PCI_CTRL_IN_THR_SHIFT
)
356 | (8ULL << GRUB_CS5536_MSR_GL_PCI_CTRL_LATENCY_SHIFT
)
357 | GRUB_CS5536_MSR_GL_PCI_CTRL_IO_ENABLE
358 | GRUB_CS5536_MSR_GL_PCI_CTRL_MEMORY_ENABLE
);
361 set_io_space (dev
, 0, GRUB_CS5536_LBAR_SMBUS
, GRUB_CS5536_SMBUS_REGS_SIZE
);
362 set_io_space (dev
, 1, GRUB_CS5536_LBAR_GPIO
, GRUB_CS5536_GPIO_REGS_SIZE
);
363 set_io_space (dev
, 2, GRUB_CS5536_LBAR_MFGPT
, GRUB_CS5536_MFGPT_REGS_SIZE
);
364 set_io_space (dev
, 3, GRUB_CS5536_LBAR_IRQ_MAP
, GRUB_CS5536_IRQ_MAP_REGS_SIZE
);
365 set_io_space (dev
, 4, GRUB_CS5536_LBAR_PM
, GRUB_CS5536_PM_REGS_SIZE
);
366 set_io_space (dev
, 5, GRUB_CS5536_LBAR_ACPI
, GRUB_CS5536_ACPI_REGS_SIZE
);
367 set_iod (dev
, 0, GRUB_CS5536_DESTINATION_IDE
, GRUB_ATA_CH0_PORT1
, 0xffff8);
368 set_iod (dev
, 1, GRUB_CS5536_DESTINATION_ACC
, GRUB_CS5536_LBAR_ACC
, 0xfff80);
369 set_iod (dev
, 2, GRUB_CS5536_DESTINATION_IDE
, GRUB_CS5536_LBAR_IDE
, 0xffff0);