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>
26
grub_cs5536_find (grub_pci_device_t *devp)
29
auto int NESTED_FUNC_ATTR hook (grub_pci_device_t dev,
32
int NESTED_FUNC_ATTR hook (grub_pci_device_t dev,
35
if (pciid == GRUB_CS5536_PCIID)
44
grub_pci_iterate (hook);
50
grub_cs5536_read_msr (grub_pci_device_t dev, grub_uint32_t addr)
52
grub_uint64_t ret = 0;
53
grub_pci_write (grub_pci_make_address (dev, GRUB_CS5536_MSR_MAILBOX_ADDR),
56
grub_pci_read (grub_pci_make_address (dev, GRUB_CS5536_MSR_MAILBOX_DATA0));
57
ret |= (((grub_uint64_t)
58
grub_pci_read (grub_pci_make_address (dev,
59
GRUB_CS5536_MSR_MAILBOX_DATA1)))
65
grub_cs5536_write_msr (grub_pci_device_t dev, grub_uint32_t addr,
68
grub_pci_write (grub_pci_make_address (dev, GRUB_CS5536_MSR_MAILBOX_ADDR),
70
grub_pci_write (grub_pci_make_address (dev, GRUB_CS5536_MSR_MAILBOX_DATA0),
72
grub_pci_write (grub_pci_make_address (dev, GRUB_CS5536_MSR_MAILBOX_DATA1),
77
grub_cs5536_smbus_wait (grub_port_t smbbase)
79
grub_uint64_t start = grub_get_time_ms ();
83
status = grub_inb (smbbase + GRUB_CS5536_SMB_REG_STATUS);
84
if (status & GRUB_CS5536_SMB_REG_STATUS_SDAST)
86
if (status & GRUB_CS5536_SMB_REG_STATUS_BER)
87
return grub_error (GRUB_ERR_IO, "SM bus error");
88
if (status & GRUB_CS5536_SMB_REG_STATUS_NACK)
89
return grub_error (GRUB_ERR_IO, "NACK received");
90
if (grub_get_time_ms () > start + 40)
91
return grub_error (GRUB_ERR_IO, "SM stalled");
98
grub_cs5536_read_spd_byte (grub_port_t smbbase, grub_uint8_t dev,
99
grub_uint8_t addr, grub_uint8_t *res)
104
grub_outb (grub_inb (smbbase + GRUB_CS5536_SMB_REG_CTRL1)
105
| GRUB_CS5536_SMB_REG_CTRL1_START,
106
smbbase + GRUB_CS5536_SMB_REG_CTRL1);
108
/* Send device address. */
109
err = grub_cs5536_smbus_wait (smbbase);
112
grub_outb (dev << 1, smbbase + GRUB_CS5536_SMB_REG_DATA);
115
err = grub_cs5536_smbus_wait (smbbase);
118
grub_outb (grub_inb (smbbase + GRUB_CS5536_SMB_REG_CTRL1)
119
| GRUB_CS5536_SMB_REG_CTRL1_ACK,
120
smbbase + GRUB_CS5536_SMB_REG_CTRL1);
122
/* Send byte address. */
123
grub_outb (addr, smbbase + GRUB_CS5536_SMB_REG_DATA);
126
err = grub_cs5536_smbus_wait (smbbase);
129
grub_outb (grub_inb (smbbase + GRUB_CS5536_SMB_REG_CTRL1)
130
| GRUB_CS5536_SMB_REG_CTRL1_START,
131
smbbase + GRUB_CS5536_SMB_REG_CTRL1);
133
/* Send device address. */
134
err = grub_cs5536_smbus_wait (smbbase);
137
grub_outb ((dev << 1) | 1, smbbase + GRUB_CS5536_SMB_REG_DATA);
140
err = grub_cs5536_smbus_wait (smbbase);
143
grub_outb (grub_inb (smbbase + GRUB_CS5536_SMB_REG_CTRL1)
144
| GRUB_CS5536_SMB_REG_CTRL1_STOP,
145
smbbase + GRUB_CS5536_SMB_REG_CTRL1);
147
err = grub_cs5536_smbus_wait (smbbase);
150
*res = grub_inb (smbbase + GRUB_CS5536_SMB_REG_DATA);
152
return GRUB_ERR_NONE;
156
grub_cs5536_init_smbus (grub_pci_device_t dev, grub_uint16_t divisor,
157
grub_port_t *smbbase)
159
grub_uint64_t smbbar;
161
smbbar = grub_cs5536_read_msr (dev, GRUB_CS5536_MSR_SMB_BAR);
164
if (!(smbbar & GRUB_CS5536_LBAR_ENABLE))
165
return grub_error(GRUB_ERR_IO, "SMB controller not enabled\n");
166
*smbbase = (smbbar & GRUB_CS5536_LBAR_ADDR_MASK) + GRUB_MACHINE_PCI_IO_BASE;
169
return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid divisor");
172
grub_outb (0, *smbbase + GRUB_CS5536_SMB_REG_CTRL2);
174
/* Disable interrupts. */
175
grub_outb (0, *smbbase + GRUB_CS5536_SMB_REG_CTRL1);
178
grub_outb (GRUB_CS5536_SMB_REG_ADDR_MASTER,
179
*smbbase + GRUB_CS5536_SMB_REG_ADDR);
182
grub_outb (((divisor >> 7) & 0xff), *smbbase + GRUB_CS5536_SMB_REG_CTRL3);
183
grub_outb (((divisor << 1) & 0xfe) | GRUB_CS5536_SMB_REG_CTRL2_ENABLE,
184
*smbbase + GRUB_CS5536_SMB_REG_CTRL2);
186
return GRUB_ERR_NONE;
190
grub_cs5536_read_spd (grub_port_t smbbase, grub_uint8_t dev,
191
struct grub_smbus_spd *res)
198
err = grub_cs5536_read_spd_byte (smbbase, dev, 0, &b);
202
return grub_error (GRUB_ERR_IO, "no SPD found");
205
((grub_uint8_t *) res)[0] = b;
206
for (ptr = 1; ptr < size; ptr++)
208
err = grub_cs5536_read_spd_byte (smbbase, dev, ptr,
209
&((grub_uint8_t *) res)[ptr]);
213
return GRUB_ERR_NONE;
216
/* Dump of GPIO connections. FIXME: Remove useless and macroify. */
217
static grub_uint32_t gpiodump[] = {
218
0xffff0000, 0x2ffdd002, 0xffff0000, 0xffff0000,
219
0x2fffd000, 0xffff0000, 0x1000efff, 0xefff1000,
220
0x3ffbc004, 0xffff0000, 0xffff0000, 0xffff0000,
221
0x3ffbc004, 0x3ffbc004, 0xffff0000, 0x00000000,
222
0xffff0000, 0xffff0000, 0x3ffbc004, 0x3f9bc064,
223
0x00000000, 0x00000000, 0x00000000, 0x00000000,
224
0x00000000, 0x00000000, 0x00000000, 0x00000000,
225
0x00000000, 0x00000000, 0x00000000, 0x00000000,
226
0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000,
227
0xffff0000, 0xffff0000, 0x0000ffff, 0xffff0000,
228
0xefff1000, 0xffff0000, 0xffff0000, 0xffff0000,
229
0xefff1000, 0xefff1000, 0xffff0000, 0x00000000,
230
0xffff0000, 0xffff0000, 0xefff1000, 0xffff0000,
231
0x00000000, 0x00000000, 0x00000000, 0x00000000,
232
0x00000000, 0x00000000, 0x00000000, 0x00000000,
233
0x00000000, 0x50000000, 0x00000000, 0x00000000,
237
set_io_space (grub_pci_device_t dev, int num, grub_uint16_t start,
240
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_GL_REGIONS_START + num,
241
((((grub_uint64_t) start + len - 4)
242
<< GRUB_CS5536_MSR_GL_REGION_IO_TOP_SHIFT)
243
& GRUB_CS5536_MSR_GL_REGION_TOP_MASK)
244
| (((grub_uint64_t) start
245
<< GRUB_CS5536_MSR_GL_REGION_IO_BASE_SHIFT)
246
& GRUB_CS5536_MSR_GL_REGION_BASE_MASK)
247
| GRUB_CS5536_MSR_GL_REGION_IO
248
| GRUB_CS5536_MSR_GL_REGION_ENABLE);
252
set_iod (grub_pci_device_t dev, int num, int dest, int start, int mask)
254
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_GL_IOD_START + num,
255
((grub_uint64_t) dest << GRUB_CS5536_IOD_DEST_SHIFT)
256
| (((grub_uint64_t) start & GRUB_CS5536_IOD_ADDR_MASK)
257
<< GRUB_CS5536_IOD_BASE_SHIFT)
258
| ((mask & GRUB_CS5536_IOD_ADDR_MASK)
259
<< GRUB_CS5536_IOD_MASK_SHIFT));
263
set_p2d (grub_pci_device_t dev, int num, int dest, grub_uint32_t start)
265
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_GL_P2D_START + num,
266
(((grub_uint64_t) dest) << GRUB_CS5536_P2D_DEST_SHIFT)
267
| ((grub_uint64_t) (start >> GRUB_CS5536_P2D_LOG_ALIGN)
268
<< GRUB_CS5536_P2D_BASE_SHIFT)
269
| (((1 << (32 - GRUB_CS5536_P2D_LOG_ALIGN)) - 1)
270
<< GRUB_CS5536_P2D_MASK_SHIFT));
274
grub_cs5536_init_geode (grub_pci_device_t dev)
278
/* Make sure GPIO is where we expect it to be. */
279
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_GPIO_BAR,
280
GRUB_CS5536_LBAR_TURN_ON | GRUB_CS5536_LBAR_GPIO);
283
for (i = 0; i < (int) ARRAY_SIZE (gpiodump); i++)
284
((volatile grub_uint32_t *) (GRUB_MACHINE_PCI_IO_BASE
285
+ GRUB_CS5536_LBAR_GPIO)) [i] = gpiodump[i];
287
/* Enable more BARs. */
288
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_IRQ_MAP_BAR,
289
GRUB_CS5536_LBAR_TURN_ON | GRUB_CS5536_LBAR_IRQ_MAP);
290
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_MFGPT_BAR,
291
GRUB_CS5536_LBAR_TURN_ON | GRUB_CS5536_LBAR_MFGPT);
292
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_ACPI_BAR,
293
GRUB_CS5536_LBAR_TURN_ON | GRUB_CS5536_LBAR_ACPI);
294
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_PM_BAR,
295
GRUB_CS5536_LBAR_TURN_ON | GRUB_CS5536_LBAR_PM);
298
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_DIVIL_LEG_IO,
299
GRUB_CS5536_MSR_DIVIL_LEG_IO_MODE_X86
300
| GRUB_CS5536_MSR_DIVIL_LEG_IO_F_REMAP
301
| GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE0
302
| GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE1);
303
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_DIVIL_IRQ_MAPPER_PRIMARY_MASK,
304
(~GRUB_CS5536_DIVIL_LPC_INTERRUPTS) & 0xffff);
305
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_DIVIL_IRQ_MAPPER_LPC_MASK,
306
GRUB_CS5536_DIVIL_LPC_INTERRUPTS);
307
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_DIVIL_LPC_SERIAL_IRQ_CONTROL,
308
GRUB_CS5536_MSR_DIVIL_LPC_SERIAL_IRQ_CONTROL_ENABLE);
310
/* Initialise USB controller. */
311
/* FIXME: assign adresses dynamically. */
312
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_USB_OHCI_BASE,
313
GRUB_CS5536_MSR_USB_BASE_BUS_MASTER
314
| GRUB_CS5536_MSR_USB_BASE_MEMORY_ENABLE
316
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_USB_EHCI_BASE,
317
GRUB_CS5536_MSR_USB_BASE_BUS_MASTER
318
| GRUB_CS5536_MSR_USB_BASE_MEMORY_ENABLE
319
| (0x20ULL << GRUB_CS5536_MSR_USB_EHCI_BASE_FLDJ_SHIFT)
321
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_USB_CONTROLLER_BASE,
322
GRUB_CS5536_MSR_USB_BASE_BUS_MASTER
323
| GRUB_CS5536_MSR_USB_BASE_MEMORY_ENABLE | 0x05020000);
324
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_USB_OPTION_CONTROLLER_BASE,
325
GRUB_CS5536_MSR_USB_BASE_MEMORY_ENABLE | 0x05022000);
326
set_p2d (dev, 0, GRUB_CS5536_DESTINATION_USB, 0x05020000);
327
set_p2d (dev, 1, GRUB_CS5536_DESTINATION_USB, 0x05022000);
328
set_p2d (dev, 5, GRUB_CS5536_DESTINATION_USB, 0x05024000);
329
set_p2d (dev, 6, GRUB_CS5536_DESTINATION_USB, 0x05023000);
332
volatile grub_uint32_t *oc;
333
oc = grub_pci_device_map_range (dev, 0x05022000,
334
GRUB_CS5536_USB_OPTION_REGS_SIZE);
336
oc[GRUB_CS5536_USB_OPTION_REG_UOCMUX] =
337
(oc[GRUB_CS5536_USB_OPTION_REG_UOCMUX]
338
& ~GRUB_CS5536_USB_OPTION_REG_UOCMUX_PMUX_MASK)
339
| GRUB_CS5536_USB_OPTION_REG_UOCMUX_PMUX_HC;
340
grub_pci_device_unmap_range (dev, oc, GRUB_CS5536_USB_OPTION_REGS_SIZE);
343
/* Setup IDE controller. */
344
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_IDE_IO_BAR,
346
| GRUB_CS5536_MSR_IDE_IO_BAR_UNITS);
347
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_IDE_CFG,
348
GRUB_CS5536_MSR_IDE_CFG_CHANNEL_ENABLE);
349
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_IDE_TIMING,
350
(GRUB_CS5536_MSR_IDE_TIMING_PIO0
351
<< GRUB_CS5536_MSR_IDE_TIMING_DRIVE0_SHIFT)
352
| (GRUB_CS5536_MSR_IDE_TIMING_PIO0
353
<< GRUB_CS5536_MSR_IDE_TIMING_DRIVE1_SHIFT));
354
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_IDE_CAS_TIMING,
355
(GRUB_CS5536_MSR_IDE_CAS_TIMING_CMD_PIO0
356
<< GRUB_CS5536_MSR_IDE_CAS_TIMING_CMD_SHIFT)
357
| (GRUB_CS5536_MSR_IDE_CAS_TIMING_PIO0
358
<< GRUB_CS5536_MSR_IDE_CAS_TIMING_DRIVE0_SHIFT)
359
| (GRUB_CS5536_MSR_IDE_CAS_TIMING_PIO0
360
<< GRUB_CS5536_MSR_IDE_CAS_TIMING_DRIVE1_SHIFT));
362
/* Setup Geodelink PCI. */
363
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_GL_PCI_CTRL,
364
(4ULL << GRUB_CS5536_MSR_GL_PCI_CTRL_OUT_THR_SHIFT)
365
| (4ULL << GRUB_CS5536_MSR_GL_PCI_CTRL_IN_THR_SHIFT)
366
| (8ULL << GRUB_CS5536_MSR_GL_PCI_CTRL_LATENCY_SHIFT)
367
| GRUB_CS5536_MSR_GL_PCI_CTRL_IO_ENABLE
368
| GRUB_CS5536_MSR_GL_PCI_CTRL_MEMORY_ENABLE);
371
set_io_space (dev, 0, GRUB_CS5536_LBAR_SMBUS, GRUB_CS5536_SMBUS_REGS_SIZE);
372
set_io_space (dev, 1, GRUB_CS5536_LBAR_GPIO, GRUB_CS5536_GPIO_REGS_SIZE);
373
set_io_space (dev, 2, GRUB_CS5536_LBAR_MFGPT, GRUB_CS5536_MFGPT_REGS_SIZE);
374
set_io_space (dev, 3, GRUB_CS5536_LBAR_IRQ_MAP, GRUB_CS5536_IRQ_MAP_REGS_SIZE);
375
set_io_space (dev, 4, GRUB_CS5536_LBAR_PM, GRUB_CS5536_PM_REGS_SIZE);
376
set_io_space (dev, 5, GRUB_CS5536_LBAR_ACPI, GRUB_CS5536_ACPI_REGS_SIZE);
377
set_iod (dev, 0, GRUB_CS5536_DESTINATION_IDE, GRUB_ATA_CH0_PORT1, 0xffff8);
378
set_iod (dev, 1, GRUB_CS5536_DESTINATION_ACC, GRUB_CS5536_LBAR_ACC, 0xfff80);
379
set_iod (dev, 2, GRUB_CS5536_DESTINATION_IDE, GRUB_CS5536_LBAR_IDE, 0xffff0);