2 * This file is part of the coreboot project.
4 * Copyright 2016 Google Inc.
5 * Copyright (C) 2017 Siemens AG
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
17 #include <console/console.h>
18 #include <device/device.h>
19 #include <device/pci.h>
20 #include <device/pci_ids.h>
23 #include <intelblocks/lpc_lib.h>
24 #include <soc/pci_devs.h>
26 #include <bootstate.h>
28 #include <timestamp.h>
32 #define MAX_PATH_DEPTH 12
33 #define MAX_NUM_MAPPINGS 10
35 /** \brief This function can decide if a given MAC address is valid or not.
36 * Currently, addresses filled with 0xff or 0x00 are not valid.
37 * @param mac Buffer to the MAC address to check
38 * @return 0 if address is not valid, otherwise 1
40 static uint8_t is_mac_adr_valid(uint8_t mac
[6])
44 memset(buf
, 0, sizeof(buf
));
45 if (!memcmp(buf
, mac
, sizeof(buf
)))
47 memset(buf
, 0xff, sizeof(buf
));
48 if (!memcmp(buf
, mac
, sizeof(buf
)))
53 /** \brief This function will search for a MAC address which can be assigned
55 * @param dev pointer to PCI device
56 * @param mac buffer where to store the MAC address
57 * @return cb_err CB_ERR or CB_SUCCESS
59 enum cb_err
mainboard_get_mac_address(struct device
*dev
, uint8_t mac
[6])
61 struct bus
*parent
= dev
->bus
;
62 uint8_t buf
[16], mapping
[16], i
= 0, chain_len
= 0;
64 memset(buf
, 0, sizeof(buf
));
65 memset(mapping
, 0, sizeof(mapping
));
67 /* The first entry in the tree is the device itself. */
68 buf
[0] = dev
->path
.pci
.devfn
;
70 for (i
= 1; i
< MAX_PATH_DEPTH
&& parent
->dev
->bus
->subordinate
; i
++) {
71 buf
[i
] = parent
->dev
->path
.pci
.devfn
;
73 parent
= parent
->dev
->bus
;
75 if (i
== MAX_PATH_DEPTH
) {
76 /* The path is deeper than MAX_PATH_DEPTH devices, error. */
77 printk(BIOS_ERR
, "Too many bridges for %s\n", dev_path(dev
));
81 * Now construct the mapping based on the device chain starting from
82 * root bridge device to the device itself.
85 mapping
[1] = chain_len
;
86 for (i
= 0; i
< chain_len
; i
++)
87 mapping
[i
+ 4] = buf
[chain_len
- i
- 1];
89 /* Open main hwinfo block */
90 if (hwilib_find_blocks("hwinfo.hex") != CB_SUCCESS
)
92 /* Now try to find a valid MAC address in hwinfo for this mapping.*/
93 for (i
= 0; i
< MAX_NUM_MAPPINGS
; i
++) {
94 if ((hwilib_get_field(XMac1Mapping
+ i
, buf
, 16) == 16) &&
95 !(memcmp(buf
, mapping
, chain_len
+ 4))) {
96 /* There is a matching mapping available, get MAC address. */
97 if ((hwilib_get_field(XMac1
+ i
, mac
, 6) == 6) &&
98 (is_mac_adr_valid(mac
))) {
106 /* No MAC address found for */
110 static void mainboard_init(void *chip_info
)
112 const struct pad_config
*pads
;
115 pads
= brd_gpio_table(&num
);
116 gpio_configure_pads(pads
, num
);
119 static void mainboard_final(void *chip_info
)
126 * Set up the DP2LVDS converter.
127 * ptn3460_init() may only be executed after i2c bus init.
129 status
= ptn3460_init("hwinfo.hex");
131 printk(BIOS_ERR
, "LCD: Set up PTN with status 0x%x\n", status
);
133 printk(BIOS_INFO
, "LCD: Set up PTN was successful.\n");
135 /* Enable additional I/O decoding range on LPC for COM 3 */
136 lpc_open_pmio_window(0x3e8, 8);
138 /* Set Master Enable for on-board PCI device. */
139 dev
= dev_find_device(PCI_VENDOR_ID_SIEMENS
, 0x403f, 0);
141 cmd
= pci_read_config16(dev
, PCI_COMMAND
);
142 cmd
|= PCI_COMMAND_MASTER
;
143 pci_write_config16(dev
, PCI_COMMAND
, cmd
);
147 static void wait_for_legacy_dev(void *unused
)
149 uint32_t legacy_delay
, us_since_boot
;
152 /* Open main hwinfo block. */
153 if (hwilib_find_blocks("hwinfo.hex") != CB_SUCCESS
)
156 /* Get legacy delay parameter from hwinfo. */
157 if (hwilib_get_field(LegacyDelay
, (uint8_t *) &legacy_delay
,
158 sizeof(legacy_delay
)) != sizeof(legacy_delay
))
161 us_since_boot
= get_us_since_boot();
162 /* No need to wait if the time since boot is already long enough.*/
163 if (us_since_boot
> legacy_delay
)
165 stopwatch_init_msecs_expire(&sw
, (legacy_delay
- us_since_boot
) / 1000);
166 printk(BIOS_NOTICE
, "Wait remaining %d of %d us for legacy devices...",
167 legacy_delay
- us_since_boot
, legacy_delay
);
168 while (!stopwatch_expired(&sw
))
170 printk(BIOS_NOTICE
, "done!\n");
173 BOOT_STATE_INIT_ENTRY(BS_DEV_ENUMERATE
, BS_ON_ENTRY
, wait_for_legacy_dev
, NULL
);
175 struct chip_operations mainboard_ops
= {
176 .init
= mainboard_init
,
177 .final
= mainboard_final
,