blob: d384fcb56191fd7395fb95efd227ee7980e74c2c [file] [log] [blame]
Nico Huberb0f83262014-01-01 20:47:55 +01001/*
2 * Copyright (C) 2014 Nico Huber <nico.h@gmx.de>
3 *
4 * Code borrowed from pci_early.c:
5 * Copyright (C) 2011 Google Inc
6 *
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.
10 *
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.
Nico Huberb0f83262014-01-01 20:47:55 +010015 */
16
17#include <device/pci_ehci.h>
18
19static unsigned pci_find_next_capability(pci_devfn_t dev, unsigned cap, unsigned last)
20{
21 unsigned pos = 0;
22 u16 status;
23 unsigned reps = 48;
24
25 status = pci_read_config16(dev, PCI_STATUS);
26 if (!(status & PCI_STATUS_CAP_LIST))
27 return 0;
28
29 u8 hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE);
30 switch (hdr_type & 0x7f) {
31 case PCI_HEADER_TYPE_NORMAL:
32 case PCI_HEADER_TYPE_BRIDGE:
33 pos = PCI_CAPABILITY_LIST;
34 break;
35 case PCI_HEADER_TYPE_CARDBUS:
36 pos = PCI_CB_CAPABILITY_LIST;
37 break;
38 default:
39 return 0;
40 }
41
42 pos = pci_read_config8(dev, pos);
43 while (reps-- && (pos >= 0x40)) { /* Loop through the linked list. */
44 unsigned this_cap;
45
46 pos &= ~3;
47 this_cap = pci_read_config8(dev, pos + PCI_CAP_LIST_ID);
48 if (this_cap == 0xff)
49 break;
50
51 if (!last && (this_cap == cap))
52 return pos;
53
54 if (last == pos)
55 last = 0;
56
57 pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT);
58 }
59 return 0;
60}
61
62static unsigned pci_find_capability(pci_devfn_t dev, unsigned cap)
63{
64 return pci_find_next_capability(dev, cap, 0);
65}
66
67extern void *ehci_bar;
68int ehci_debug_hw_enable(unsigned int *base, unsigned int *dbg_offset)
69{
70 pci_devfn_t dbg_dev = pci_ehci_dbg_dev(CONFIG_USBDEBUG_HCD_INDEX);
71 pci_ehci_dbg_enable(dbg_dev, CONFIG_EHCI_BAR);
72 pci_devfn_t dev = dbg_dev;
73
74 u8 pos = pci_find_capability(dev, PCI_CAP_ID_EHCI_DEBUG);
75 if (!pos)
76 return -1;
77
78 u32 cap = pci_read_config32(dev, pos);
79
80 /* FIXME: We should remove static EHCI_BAR_INDEX. */
81 u8 dbg_bar = 0x10 + 4 * ((cap >> 29) - 1);
82 if (dbg_bar != EHCI_BAR_INDEX)
83 return -1;
84
85 *base = (u32)ehci_bar;
86 *dbg_offset = (cap>>16) & 0x1ffc;
87 return 0;
88}
89
90void ehci_debug_select_port(unsigned int port)
91{
92 pci_devfn_t dbg_dev = pci_ehci_dbg_dev(CONFIG_USBDEBUG_HCD_INDEX);
93 pci_ehci_dbg_set_port(dbg_dev, port);
94}