blob: 7ddc15d4ebab15c3071120053fa8985b0197bba4 [file] [log] [blame]
Angel Ponsc74dae92020-04-02 23:48:16 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Yinghai Lu13f1c2a2005-07-08 02:49:49 +00002
3#include <console/console.h>
4#include <device/device.h>
5#include <device/pci.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02006#include <device/pci_ops.h>
Yinghai Lu13f1c2a2005-07-08 02:49:49 +00007#include <device/pcix.h>
Elyes Haouas04c3b5a2022-10-07 10:08:05 +02008#include <stdint.h>
Yinghai Lu13f1c2a2005-07-08 02:49:49 +00009
Elyes HAOUASb9e82f02018-05-02 21:29:55 +020010static void pcix_tune_dev(struct device *dev)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000011{
Uwe Hermannd453dd02010-10-18 00:00:57 +000012 u32 status;
13 u16 orig_cmd, cmd;
14 unsigned int cap, max_read, max_tran;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000015
Uwe Hermannd453dd02010-10-18 00:00:57 +000016 if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000017 return;
Uwe Hermannd453dd02010-10-18 00:00:57 +000018
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000019 cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
Uwe Hermannd453dd02010-10-18 00:00:57 +000020 if (!cap)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000021 return;
Uwe Hermannd453dd02010-10-18 00:00:57 +000022
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000023 printk(BIOS_DEBUG, "%s PCI-X tuning\n", dev_path(dev));
Uwe Hermannd453dd02010-10-18 00:00:57 +000024
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000025 status = pci_read_config32(dev, cap + PCI_X_STATUS);
Uwe Hermannd453dd02010-10-18 00:00:57 +000026 orig_cmd = cmd = pci_read_config16(dev, cap + PCI_X_CMD);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000027
28 max_read = (status & PCI_X_STATUS_MAX_READ) >> 21;
29 max_tran = (status & PCI_X_STATUS_MAX_SPLIT) >> 23;
30 if (max_read != ((cmd & PCI_X_CMD_MAX_READ) >> 2)) {
31 cmd &= ~PCI_X_CMD_MAX_READ;
32 cmd |= max_read << 2;
33 }
34 if (max_tran != ((cmd & PCI_X_CMD_MAX_SPLIT) >> 4)) {
35 cmd &= ~PCI_X_CMD_MAX_SPLIT;
36 cmd |= max_tran << 4;
37 }
Uwe Hermannd453dd02010-10-18 00:00:57 +000038
39 /* Don't attempt to handle PCI-X errors. */
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000040 cmd &= ~PCI_X_CMD_DPERR_E;
Uwe Hermannd453dd02010-10-18 00:00:57 +000041
Uwe Hermanne4870472010-11-04 23:23:47 +000042 /* Enable relaxed ordering. */
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000043 cmd |= PCI_X_CMD_ERO;
Uwe Hermannd453dd02010-10-18 00:00:57 +000044
45 if (orig_cmd != cmd)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000046 pci_write_config16(dev, cap + PCI_X_CMD, cmd);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000047}
48
Myles Watson894a3472010-06-09 22:41:35 +000049static void pcix_tune_bus(struct bus *bus)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000050{
Elyes HAOUASb9e82f02018-05-02 21:29:55 +020051 struct device *child;
Uwe Hermannd453dd02010-10-18 00:00:57 +000052
53 for (child = bus->children; child; child = child->sibling)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000054 pcix_tune_dev(child);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000055}
56
Uwe Hermannd453dd02010-10-18 00:00:57 +000057const char *pcix_speed(u16 sstatus)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000058{
59 static const char conventional[] = "Conventional PCI";
60 static const char pcix_66mhz[] = "66MHz PCI-X";
61 static const char pcix_100mhz[] = "100MHz PCI-X";
62 static const char pcix_133mhz[] = "133MHz PCI-X";
63 static const char pcix_266mhz[] = "266MHz PCI-X";
64 static const char pcix_533mhz[] = "533MHZ PCI-X";
65 static const char unknown[] = "Unknown";
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000066 const char *result;
Uwe Hermannd453dd02010-10-18 00:00:57 +000067
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000068 result = unknown;
Uwe Hermannd453dd02010-10-18 00:00:57 +000069
70 switch (PCI_X_SSTATUS_MFREQ(sstatus)) {
Stefan Reinauer14e22772010-04-27 06:56:47 +000071 case PCI_X_SSTATUS_CONVENTIONAL_PCI:
72 result = conventional;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000073 break;
74 case PCI_X_SSTATUS_MODE1_66MHZ:
75 result = pcix_66mhz;
76 break;
77 case PCI_X_SSTATUS_MODE1_100MHZ:
78 result = pcix_100mhz;
79 break;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000080 case PCI_X_SSTATUS_MODE1_133MHZ:
81 result = pcix_133mhz;
82 break;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000083 case PCI_X_SSTATUS_MODE2_266MHZ_REF_66MHZ:
84 case PCI_X_SSTATUS_MODE2_266MHZ_REF_100MHZ:
85 case PCI_X_SSTATUS_MODE2_266MHZ_REF_133MHZ:
86 result = pcix_266mhz;
87 break;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000088 case PCI_X_SSTATUS_MODE2_533MHZ_REF_66MHZ:
89 case PCI_X_SSTATUS_MODE2_533MHZ_REF_100MHZ:
90 case PCI_X_SSTATUS_MODE2_533MHZ_REF_133MHZ:
91 result = pcix_533mhz;
92 break;
93 }
Uwe Hermanne4870472010-11-04 23:23:47 +000094
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000095 return result;
96}
97
Elyes HAOUASb9e82f02018-05-02 21:29:55 +020098void pcix_scan_bridge(struct device *dev)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000099{
Uwe Hermannd453dd02010-10-18 00:00:57 +0000100 unsigned int pos;
101 u16 sstatus;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000102
Kyösti Mälkki580e7222015-03-19 21:04:23 +0200103 do_pci_scan_bridge(dev, pci_scan_bus);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000104
105 /* Find the PCI-X capability. */
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000106 pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
107 sstatus = pci_read_config16(dev, pos + PCI_X_SEC_STATUS);
108
Uwe Hermannd453dd02010-10-18 00:00:57 +0000109 if (PCI_X_SSTATUS_MFREQ(sstatus) != PCI_X_SSTATUS_CONVENTIONAL_PCI)
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200110 pcix_tune_bus(dev->downstream);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000111
Uwe Hermannd453dd02010-10-18 00:00:57 +0000112 /* Print the PCI-X bus speed. */
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200113 printk(BIOS_DEBUG, "PCI: %02x:%02x: %s\n", dev->downstream->segment_group,
114 dev->downstream->secondary, pcix_speed(sstatus));
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000115}
116
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000117/** Default device operations for PCI-X bridges */
118static struct pci_operations pcix_bus_ops_pci = {
119 .set_subsystem = 0,
120};
121
122struct device_operations default_pcix_ops_bus = {
123 .read_resources = pci_bus_read_resources,
124 .set_resources = pci_dev_set_resources,
125 .enable_resources = pci_bus_enable_resources,
Uwe Hermannd453dd02010-10-18 00:00:57 +0000126 .scan_bus = pcix_scan_bridge,
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000127 .reset_bus = pci_bus_reset,
128 .ops_pci = &pcix_bus_ops_pci,
129};