blob: 086bbfd458858ca484cb629b9e27f70b6db27311 [file] [log] [blame]
Angel Pons6bc13742020-04-05 15:46:38 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Andrey Petrov79fc33a2017-01-24 21:56:36 -08002
Kyösti Mälkki13f66502019-03-03 08:01:05 +02003#include <device/mmio.h>
Andrey Petrov79fc33a2017-01-24 21:56:36 -08004#include <console/console.h>
5#include <device/device.h>
6#include <device/pci.h>
Subrata Banik4aaa7e32017-04-24 11:54:34 +05307#include <intelblocks/xdci.h>
Andrey Petrov79fc33a2017-01-24 21:56:36 -08008#include <soc/pci_devs.h>
Andrey Petrov79fc33a2017-01-24 21:56:36 -08009#include <timer.h>
10
11#define DUAL_ROLE_CFG0 0x80d8
12# define DRD_CONFIG_MASK (0x3 << 0)
13# define DRD_CONFIG_DYNAMIC (0x0 << 0)
14# define DRD_CONFIG_HOST (0x1 << 0)
15# define DRD_CONFIG_DEVICE (0x2 << 0)
16# define SW_VBUS_VALID_MASK (1 << 24)
17# define SW_VBUS_DEASSERT_VALID (0 << 24)
18# define SW_VBUS_ASSERT_VALID (1 << 24)
19# define SW_IDPIN_EN_MASK (1 << 21)
20# define SW_IDPIN_DIS (0 << 21)
21# define SW_IDPIN_EN (1 << 21)
22# define SW_IDPIN_MASK (1 << 20)
23# define SW_IDPIN_HOST (0 << 20)
24# define SW_IDPIN_DEVICE (1 << 20)
25#define DUAL_ROLE_CFG1 0x80dc
26# define DRD_MODE_MASK (1 << 29)
27# define DRD_MODE_DEVICE (0 << 29)
28# define DRD_MODE_HOST (1 << 29)
29
30static void configure_host_mode_port0(struct device *dev)
31{
32 uint32_t *cfg0;
33 uint32_t *cfg1;
34 const struct resource *res;
35 uint32_t reg;
36 struct stopwatch sw;
Andrey Petrov79fc33a2017-01-24 21:56:36 -080037
38 /*
39 * Only default to host mode if the xdci device is present and
40 * enabled. If it's disabled assume the switch was already done
41 * in FSP.
42 */
Angel Ponsadeac8d2021-06-23 12:32:59 +020043 if (!dev->enabled)
Andrey Petrov79fc33a2017-01-24 21:56:36 -080044 return;
45
46 printk(BIOS_INFO, "Putting port 0 into host mode.\n");
47
Angel Pons50b92f92021-06-23 12:31:35 +020048 res = find_resource(dev, PCI_BASE_ADDRESS_0);
Andrey Petrov79fc33a2017-01-24 21:56:36 -080049
50 cfg0 = (void *)(uintptr_t)(res->base + DUAL_ROLE_CFG0);
51 cfg1 = (void *)(uintptr_t)(res->base + DUAL_ROLE_CFG1);
52
53 reg = read32(cfg0);
54 reg &= ~(DRD_CONFIG_MASK | SW_IDPIN_EN_MASK | SW_IDPIN_MASK);
55 reg &= ~(SW_VBUS_VALID_MASK);
56 reg |= DRD_CONFIG_DYNAMIC | SW_IDPIN_EN | SW_IDPIN_HOST;
57 reg |= SW_VBUS_DEASSERT_VALID;
58 write32(cfg0, reg);
59
60 stopwatch_init_msecs_expire(&sw, 10);
61
62 /* Wait for the host mode status bit. */
63 while ((read32(cfg1) & DRD_MODE_MASK) != DRD_MODE_HOST) {
64 if (stopwatch_expired(&sw)) {
65 printk(BIOS_INFO, "Timed out waiting for host mode.\n");
66 break;
67 }
68 }
69
Rob Barnesd522f382022-09-12 06:31:47 -060070 printk(BIOS_INFO, "XDCI port 0 host switch over took %lld ms\n",
Andrey Petrov79fc33a2017-01-24 21:56:36 -080071 stopwatch_duration_msecs(&sw));
72}
73
Subrata Banik4aaa7e32017-04-24 11:54:34 +053074void soc_xdci_init(struct device *dev)
Andrey Petrov79fc33a2017-01-24 21:56:36 -080075{
76 configure_host_mode_port0(dev);
77}