Zheng Bao | d098575 | 2011-01-20 04:45:48 +0000 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
| 4 | * Copyright (C) 2010 Advanced Micro Devices, Inc. |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; version 2 of the License. |
| 9 | * |
| 10 | * This program 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. |
Zheng Bao | d098575 | 2011-01-20 04:45:48 +0000 | [diff] [blame] | 14 | */ |
| 15 | |
| 16 | #include <console/console.h> |
| 17 | #include <device/device.h> |
| 18 | #include <device/pci.h> |
| 19 | #include <device/pci_ids.h> |
| 20 | #include <device/pci_ops.h> |
Kyösti Mälkki | e2227a2 | 2014-02-05 13:02:55 +0200 | [diff] [blame] | 21 | #include <device/pci_ehci.h> |
Zheng Bao | d098575 | 2011-01-20 04:45:48 +0000 | [diff] [blame] | 22 | #include <arch/io.h> |
| 23 | #include "sb800.h" |
| 24 | |
| 25 | static struct pci_operations lops_pci = { |
| 26 | .set_subsystem = pci_dev_set_subsystem, |
| 27 | }; |
| 28 | |
| 29 | static void usb_init(struct device *dev) |
| 30 | { |
| 31 | u8 byte; |
| 32 | u16 word; |
| 33 | |
| 34 | /* 7.1 Enable OHCI0-4 and EHCI Controllers */ |
| 35 | /* pmio 0xEF; */ |
| 36 | |
| 37 | /* RPR 7.2 USB S4/S5 Wake-up or PHY Power-down Support */ |
| 38 | byte = pm_ioread(0xF0); |
| 39 | byte |= 1 << 0; /* A12, USB Wake from S5 not supported on the platform */ |
| 40 | pm_iowrite(0xF0, byte); |
| 41 | |
| 42 | /* RPR 7.4 Enable the USB controller to get reset by any software that generate a PCIRst# condition */ |
| 43 | byte = pm_ioread(0xF0); |
| 44 | byte |= (1 << 2); |
| 45 | byte |= 3 << 8; /* rpr 7.5 */ |
| 46 | pm_iowrite(0xF0, byte); |
| 47 | |
| 48 | /* RPR 7.9 Disable OHCI MSI Capability. */ |
| 49 | word = pci_read_config16(dev, 0x40); |
| 50 | word |= (0x1 << 8); |
| 51 | pci_write_config16(dev, 0x40, word); |
| 52 | } |
| 53 | |
| 54 | static void usb_init2(struct device *dev) |
| 55 | { |
| 56 | u32 dword; |
Kevin Paul Herbert | bde6d30 | 2014-12-24 18:43:20 -0800 | [diff] [blame] | 57 | void *usb2_bar0; |
Zheng Bao | d098575 | 2011-01-20 04:45:48 +0000 | [diff] [blame] | 58 | device_t sm_dev; |
| 59 | |
| 60 | sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0)); |
| 61 | //rev = get_sb800_revision(sm_dev); |
| 62 | |
| 63 | /* dword = pci_read_config32(dev, 0xf8); */ |
| 64 | /* dword |= 40; */ |
| 65 | /* pci_write_config32(dev, 0xf8, dword); */ |
| 66 | |
Kevin Paul Herbert | bde6d30 | 2014-12-24 18:43:20 -0800 | [diff] [blame] | 67 | usb2_bar0 = (void *)(pci_read_config32(dev, 0x10) & ~0xFF); |
| 68 | printk(BIOS_INFO, "usb2_bar0=0x%p\n", usb2_bar0); |
Zheng Bao | d098575 | 2011-01-20 04:45:48 +0000 | [diff] [blame] | 69 | |
Martin Roth | dcf253c | 2014-12-16 20:51:31 -0700 | [diff] [blame] | 70 | /* RPR7.3 Enables the USB PHY auto calibration resister to match 45ohm resistance */ |
Zheng Bao | d098575 | 2011-01-20 04:45:48 +0000 | [diff] [blame] | 71 | dword = 0x00020F00; |
| 72 | write32(usb2_bar0 + 0xC0, dword); |
| 73 | |
| 74 | /* RPR7.8 Sets In/OUT FIFO threshold for best performance */ |
| 75 | dword = 0x00400040; |
| 76 | write32(usb2_bar0 + 0xA4, dword); |
| 77 | |
| 78 | /* RPR7.10 Disable EHCI MSI support */ |
| 79 | dword = pci_read_config32(dev, 0x50); |
| 80 | dword |= (1 << 6); |
| 81 | pci_write_config32(dev, 0x50, dword); |
| 82 | |
| 83 | /* RPR7.12 EHCI Async Park Mode */ |
| 84 | dword = pci_read_config32(dev, 0x50); |
| 85 | dword &= ~(0xF << 8); |
| 86 | dword &= ~(0xF << 12); |
| 87 | dword |= 1 << 8; |
| 88 | dword |= 2 << 12; |
| 89 | pci_write_config32(dev, 0x50, dword); |
| 90 | |
| 91 | /* RPR 6.12 EHCI Advance PHY Power Savings */ |
| 92 | /* RPR says it is just for A12. CIMM sets it when it is above A11. */ |
| 93 | /* But it makes the linux crash, so we skip it */ |
| 94 | #if 0 |
| 95 | dword = pci_read_config32(dev, 0x50); |
| 96 | dword |= 1 << 31; |
| 97 | pci_write_config32(dev, 0x50, dword); |
| 98 | #endif |
| 99 | |
| 100 | /* Each step below causes the linux crashes. Leave them here |
| 101 | * for future debugging. */ |
| 102 | #if 0 |
| 103 | u8 byte; |
| 104 | u16 word; |
| 105 | |
| 106 | |
| 107 | /* RPR6.17 Disable the EHCI Dynamic Power Saving feature */ |
| 108 | word = read32(usb2_bar0 + 0xBC); |
| 109 | word &= ~(1 << 12); |
| 110 | write16(usb2_bar0 + 0xBC, word); |
| 111 | |
| 112 | /* RPR6.19 USB Controller DMA Read Delay Tolerant. */ |
| 113 | if (rev >= REV_SB800_A14) { |
| 114 | byte = pci_read_config8(dev, 0x50); |
| 115 | byte |= (1 << 7); |
| 116 | pci_write_config8(dev, 0x50, byte); |
| 117 | } |
| 118 | |
| 119 | /* RPR6.20 Async Park Mode. */ |
| 120 | /* RPR recommends not to set these bits. */ |
| 121 | #if 0 |
| 122 | dword = pci_read_config32(dev, 0x50); |
| 123 | dword |= 1 << 23; |
| 124 | if (rev >= REV_SB800_A14) { |
| 125 | dword &= ~(1 << 2); |
| 126 | } |
| 127 | pci_write_config32(dev, 0x50, dword); |
| 128 | #endif |
| 129 | |
| 130 | /* RPR6.22 Advance Async Enhancement */ |
| 131 | /* RPR6.23 USB Periodic Cache Setting */ |
| 132 | dword = pci_read_config32(dev, 0x50); |
| 133 | if (rev == REV_SB800_A12) { |
| 134 | dword |= 1 << 28; /* 6.22 */ |
| 135 | dword |= 1 << 27; /* 6.23 */ |
| 136 | } else if (rev >= REV_SB800_A14) { |
| 137 | dword |= 1 << 3; |
| 138 | dword &= ~(1 << 28); /* 6.22 */ |
| 139 | dword |= 1 << 8; |
| 140 | dword &= ~(1 << 27); /* 6.23 */ |
| 141 | } |
| 142 | printk(BIOS_DEBUG, "rpr 6.23, final dword=%x\n", dword); |
| 143 | #endif |
| 144 | } |
| 145 | |
Zheng Bao | d098575 | 2011-01-20 04:45:48 +0000 | [diff] [blame] | 146 | static struct device_operations usb_ops = { |
Kyösti Mälkki | fb387df | 2013-06-07 22:16:52 +0300 | [diff] [blame] | 147 | .read_resources = pci_ehci_read_resources, |
| 148 | .set_resources = pci_dev_set_resources, |
Zheng Bao | d098575 | 2011-01-20 04:45:48 +0000 | [diff] [blame] | 149 | .enable_resources = pci_dev_enable_resources, |
| 150 | .init = usb_init, |
| 151 | .scan_bus = 0, |
| 152 | .ops_pci = &lops_pci, |
| 153 | }; |
| 154 | |
| 155 | static const struct pci_driver usb_0_driver __pci_driver = { |
| 156 | .ops = &usb_ops, |
| 157 | .vendor = PCI_VENDOR_ID_ATI, |
| 158 | .device = PCI_DEVICE_ID_ATI_SB800_USB_18_0, |
| 159 | }; |
| 160 | static const struct pci_driver usb_1_driver __pci_driver = { |
| 161 | .ops = &usb_ops, |
| 162 | .vendor = PCI_VENDOR_ID_ATI, |
| 163 | .device = PCI_DEVICE_ID_ATI_SB800_USB_18_2, |
| 164 | }; |
| 165 | |
| 166 | /* the pci id of usb ctrl 0 and 1 are the same. */ |
| 167 | /* |
| 168 | * static const struct pci_driver usb_3_driver __pci_driver = { |
| 169 | * .ops = &usb_ops, |
| 170 | * .vendor = PCI_VENDOR_ID_ATI, |
| 171 | * .device = PCI_DEVICE_ID_ATI_SB800_USB_19_0, |
| 172 | * }; |
| 173 | * static const struct pci_driver usb_4_driver __pci_driver = { |
| 174 | * .ops = &usb_ops, |
| 175 | * .vendor = PCI_VENDOR_ID_ATI, |
| 176 | * .device = PCI_DEVICE_ID_ATI_SB800_USB_19_1, |
| 177 | * }; |
| 178 | */ |
| 179 | |
| 180 | static const struct pci_driver usb_4_driver __pci_driver = { |
| 181 | .ops = &usb_ops, |
| 182 | .vendor = PCI_VENDOR_ID_ATI, |
| 183 | .device = PCI_DEVICE_ID_ATI_SB800_USB_20_5, |
| 184 | }; |
| 185 | |
| 186 | static struct device_operations usb_ops2 = { |
Kyösti Mälkki | fb387df | 2013-06-07 22:16:52 +0300 | [diff] [blame] | 187 | .read_resources = pci_ehci_read_resources, |
| 188 | .set_resources = pci_dev_set_resources, |
Zheng Bao | d098575 | 2011-01-20 04:45:48 +0000 | [diff] [blame] | 189 | .enable_resources = pci_dev_enable_resources, |
| 190 | .init = usb_init2, |
| 191 | .scan_bus = 0, |
| 192 | .ops_pci = &lops_pci, |
| 193 | }; |
| 194 | |
| 195 | static const struct pci_driver usb_5_driver __pci_driver = { |
| 196 | .ops = &usb_ops2, |
| 197 | .vendor = PCI_VENDOR_ID_ATI, |
| 198 | .device = PCI_DEVICE_ID_ATI_SB800_USB_18_2, |
| 199 | }; |
| 200 | /* |
| 201 | * static const struct pci_driver usb_5_driver __pci_driver = { |
| 202 | * .ops = &usb_ops2, |
| 203 | * .vendor = PCI_VENDOR_ID_ATI, |
| 204 | * .device = PCI_DEVICE_ID_ATI_SB800_USB_19_2, |
| 205 | * }; |
| 206 | */ |