18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *	Copyright (C) 2004, 2006  MIPS Technologies, Inc.  All rights reserved.
48c2ecf20Sopenharmony_ci *	    Author:	Maciej W. Rozycki <macro@mips.com>
58c2ecf20Sopenharmony_ci *	Copyright (C) 2018  Maciej W. Rozycki
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
98c2ecf20Sopenharmony_ci#include <linux/pci.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci/*
128c2ecf20Sopenharmony_ci * Set the BCM1250, etc. PCI host bridge's TRDY timeout
138c2ecf20Sopenharmony_ci * to the finite max.
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_cistatic void quirk_sb1250_pci(struct pci_dev *dev)
168c2ecf20Sopenharmony_ci{
178c2ecf20Sopenharmony_ci	pci_write_config_byte(dev, 0x40, 0xff);
188c2ecf20Sopenharmony_ci}
198c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_PCI,
208c2ecf20Sopenharmony_ci			quirk_sb1250_pci);
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/*
238c2ecf20Sopenharmony_ci * The BCM1250, etc. PCI host bridge does not support DAC on its 32-bit
248c2ecf20Sopenharmony_ci * bus, so we set the bus's DMA limit accordingly.  However the HT link
258c2ecf20Sopenharmony_ci * down the artificial PCI-HT bridge supports 40-bit addressing and the
268c2ecf20Sopenharmony_ci * SP1011 HT-PCI bridge downstream supports both DAC and a 64-bit bus
278c2ecf20Sopenharmony_ci * width, so we record the PCI-HT bridge's secondary and subordinate bus
288c2ecf20Sopenharmony_ci * numbers and do not set the limit for devices present in the inclusive
298c2ecf20Sopenharmony_ci * range of those.
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_cistruct sb1250_bus_dma_limit_exclude {
328c2ecf20Sopenharmony_ci	bool set;
338c2ecf20Sopenharmony_ci	unsigned char start;
348c2ecf20Sopenharmony_ci	unsigned char end;
358c2ecf20Sopenharmony_ci};
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic int sb1250_bus_dma_limit(struct pci_dev *dev, void *data)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	struct sb1250_bus_dma_limit_exclude *exclude = data;
408c2ecf20Sopenharmony_ci	bool exclude_this;
418c2ecf20Sopenharmony_ci	bool ht_bridge;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	exclude_this = exclude->set && (dev->bus->number >= exclude->start &&
448c2ecf20Sopenharmony_ci					dev->bus->number <= exclude->end);
458c2ecf20Sopenharmony_ci	ht_bridge = !exclude->set && (dev->vendor == PCI_VENDOR_ID_SIBYTE &&
468c2ecf20Sopenharmony_ci				      dev->device == PCI_DEVICE_ID_BCM1250_HT);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	if (exclude_this) {
498c2ecf20Sopenharmony_ci		dev_dbg(&dev->dev, "not disabling DAC for device");
508c2ecf20Sopenharmony_ci	} else if (ht_bridge) {
518c2ecf20Sopenharmony_ci		exclude->start = dev->subordinate->number;
528c2ecf20Sopenharmony_ci		exclude->end = pci_bus_max_busnr(dev->subordinate);
538c2ecf20Sopenharmony_ci		exclude->set = true;
548c2ecf20Sopenharmony_ci		dev_dbg(&dev->dev, "not disabling DAC for [bus %02x-%02x]",
558c2ecf20Sopenharmony_ci			exclude->start, exclude->end);
568c2ecf20Sopenharmony_ci	} else {
578c2ecf20Sopenharmony_ci		dev_dbg(&dev->dev, "disabling DAC for device");
588c2ecf20Sopenharmony_ci		dev->dev.bus_dma_limit = DMA_BIT_MASK(32);
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	return 0;
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic void quirk_sb1250_pci_dac(struct pci_dev *dev)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	struct sb1250_bus_dma_limit_exclude exclude = { .set = false };
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	pci_walk_bus(dev->bus, sb1250_bus_dma_limit, &exclude);
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_PCI,
718c2ecf20Sopenharmony_ci			quirk_sb1250_pci_dac);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/*
748c2ecf20Sopenharmony_ci * The BCM1250, etc. PCI/HT bridge reports as a host bridge.
758c2ecf20Sopenharmony_ci */
768c2ecf20Sopenharmony_cistatic void quirk_sb1250_ht(struct pci_dev *dev)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	dev->class = PCI_CLASS_BRIDGE_PCI << 8;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_HT,
818c2ecf20Sopenharmony_ci			quirk_sb1250_ht);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci/*
848c2ecf20Sopenharmony_ci * Set the SP1011 HT/PCI bridge's TRDY timeout to the finite max.
858c2ecf20Sopenharmony_ci */
868c2ecf20Sopenharmony_cistatic void quirk_sp1011(struct pci_dev *dev)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	pci_write_config_byte(dev, 0x64, 0xff);
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIPACKETS, PCI_DEVICE_ID_SP1011,
918c2ecf20Sopenharmony_ci			quirk_sp1011);
92