siemens/mc_apl1: Add delay to wait for legacy devices
[coreboot.git] / src / mainboard / siemens / mc_apl1 / mainboard.c
blobfb849f98723bab5883c5bc8a0cea0af106c52149
1 /*
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>
21 #include <hwilib.h>
22 #include <i210.h>
23 #include <intelblocks/lpc_lib.h>
24 #include <soc/pci_devs.h>
25 #include <string.h>
26 #include <bootstate.h>
27 #include <timer.h>
28 #include <timestamp.h>
29 #include "brd_gpio.h"
30 #include "ptn3460.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])
42 uint8_t buf[6];
44 memset(buf, 0, sizeof(buf));
45 if (!memcmp(buf, mac, sizeof(buf)))
46 return 0;
47 memset(buf, 0xff, sizeof(buf));
48 if (!memcmp(buf, mac, sizeof(buf)))
49 return 0;
50 return 1;
53 /** \brief This function will search for a MAC address which can be assigned
54 * to a MACPHY.
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;
69 chain_len = 1;
70 for (i = 1; i < MAX_PATH_DEPTH && parent->dev->bus->subordinate; i++) {
71 buf[i] = parent->dev->path.pci.devfn;
72 chain_len++;
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));
78 return CB_ERR;
81 * Now construct the mapping based on the device chain starting from
82 * root bridge device to the device itself.
84 mapping[0] = 1;
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)
91 return CB_ERR;
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))) {
99 return CB_SUCCESS;
100 } else {
101 return CB_ERR;
103 } else
104 continue;
106 /* No MAC address found for */
107 return CB_ERR;
110 static void mainboard_init(void *chip_info)
112 const struct pad_config *pads;
113 size_t num;
115 pads = brd_gpio_table(&num);
116 gpio_configure_pads(pads, num);
119 static void mainboard_final(void *chip_info)
121 int status;
122 uint16_t cmd = 0;
123 device_t dev = NULL;
126 * Set up the DP2LVDS converter.
127 * ptn3460_init() may only be executed after i2c bus init.
129 status = ptn3460_init("hwinfo.hex");
130 if (status)
131 printk(BIOS_ERR, "LCD: Set up PTN with status 0x%x\n", status);
132 else
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);
140 if (dev) {
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;
150 struct stopwatch sw;
152 /* Open main hwinfo block. */
153 if (hwilib_find_blocks("hwinfo.hex") != CB_SUCCESS)
154 return;
156 /* Get legacy delay parameter from hwinfo. */
157 if (hwilib_get_field(LegacyDelay, (uint8_t *) &legacy_delay,
158 sizeof(legacy_delay)) != sizeof(legacy_delay))
159 return;
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)
164 return;
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,