// SPDX-License-Identifier: GPL-2.0 /* * Alchemy PCI host mode support. * * Copyright 2001-2003, 2007-2008 MontaVista Software Inc. * Author: MontaVista Software, Inc. <source@mvista.com> * * Support for all devices (greater than 16) added by David Gathright.
*/
struct alchemy_pci_context { struct pci_controller alchemy_pci_ctrl; /* leave as first member! */ void __iomem *regs; /* ctrl base */ /* tools for wired entry for config space access */ unsignedlong last_elo0; unsignedlong last_elo1; int wired_entry; struct vm_struct *pci_cfg_vm;
unsignedlong pm[12];
int (*board_map_irq)(conststruct pci_dev *d, u8 slot, u8 pin); int (*board_pci_idsel)(unsignedint devsel, int assert);
};
/* for syscore_ops. There's only one PCI controller on Alchemy chips, so this * should suffice for now.
*/ staticstruct alchemy_pci_context *__alchemy_pci_ctx;
/* IO/MEM resources for PCI. Keep the memres in sync with fixup_bigphys_addr * in arch/mips/alchemy/common/setup.c
*/ staticstruct resource alchemy_pci_def_memres = {
.start = ALCHEMY_PCI_MEMWIN_START,
.end = ALCHEMY_PCI_MEMWIN_END,
.name = "PCI memory space",
.flags = IORESOURCE_MEM
};
local_irq_save(flags);
r = __raw_readl(ctx->regs + PCI_REG_STATCMD) & 0x0000ffff;
r |= PCI_STATCMD_STATUS(0x2000);
__raw_writel(r, ctx->regs + PCI_REG_STATCMD);
wmb();
/* Allow board vendors to implement their own off-chip IDSEL. * If it doesn't succeed, may as well bail out at this point.
*/ if (ctx->board_pci_idsel(device, 1) == 0) {
*data = 0xffffffff;
local_irq_restore(flags); return -1;
}
/* YAMON on all db1xxx boards wipes the TLB and writes zero to C0_wired * on resume, making it necessary to recreate it as soon as possible.
*/
ctx->wired_entry = 8191; /* impossibly high value */
alchemy_pci_wired_entry(ctx); /* install it */
}
/* need at least PCI IRQ mapping table */ if (!pd) {
dev_err(&pdev->dev, "need platform data for PCI setup\n");
ret = -ENODEV; goto out;
}
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) {
dev_err(&pdev->dev, "no memory for pcictl context\n");
ret = -ENOMEM; goto out;
}
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) {
dev_err(&pdev->dev, "no pcictl ctrl regs resource\n");
ret = -ENODEV; goto out1;
}
if (!request_mem_region(r->start, resource_size(r), pdev->name)) {
dev_err(&pdev->dev, "cannot claim pci regs\n");
ret = -ENODEV; goto out1;
}
c = clk_get(&pdev->dev, "pci_clko"); if (IS_ERR(c)) {
dev_err(&pdev->dev, "unable to find PCI clock\n");
ret = PTR_ERR(c); goto out2;
}
ret = clk_prepare_enable(c); if (ret) {
dev_err(&pdev->dev, "cannot enable PCI clock\n"); goto out6;
}
ctx->regs = ioremap(r->start, resource_size(r)); if (!ctx->regs) {
dev_err(&pdev->dev, "cannot map pci regs\n");
ret = -ENODEV; goto out5;
}
/* map parts of the PCI IO area */ /* REVISIT: if this changes with a newer variant (doubt it) make this * a platform resource.
*/
virt_io = ioremap(AU1500_PCI_IO_PHYS_ADDR, 0x00100000); if (!virt_io) {
dev_err(&pdev->dev, "cannot remap pci io space\n");
ret = -ENODEV; goto out3;
}
ctx->alchemy_pci_ctrl.io_map_base = (unsignedlong)virt_io;
/* Au1500 revisions older than AD have borked coherent PCI */ if (alchemy_get_cputype() == ALCHEMY_CPU_AU1500 &&
read_c0_prid() < 0x01030202 && !dma_default_coherent) {
val = __raw_readl(ctx->regs + PCI_REG_CONFIG);
val |= PCI_CONFIG_NC;
__raw_writel(val, ctx->regs + PCI_REG_CONFIG);
wmb();
dev_info(&pdev->dev, "non-coherent PCI on Au1500 AA/AB/AC\n");
}
if (pd->board_map_irq)
ctx->board_map_irq = pd->board_map_irq;
if (pd->board_pci_idsel)
ctx->board_pci_idsel = pd->board_pci_idsel; else
ctx->board_pci_idsel = alchemy_pci_def_idsel;
/* fill in relevant pci_controller members */
ctx->alchemy_pci_ctrl.pci_ops = &alchemy_pci_ops;
ctx->alchemy_pci_ctrl.mem_resource = &alchemy_pci_def_memres;
ctx->alchemy_pci_ctrl.io_resource = &alchemy_pci_def_iores;
/* we can't ioremap the entire pci config space because it's too large, * nor can we dynamically ioremap it because some drivers use the * PCI config routines from within atomic context and that becomes a * problem in get_vm_area(). Instead we use one wired TLB entry to * handle all config accesses for all busses.
*/
ctx->pci_cfg_vm = get_vm_area(0x2000, VM_IOREMAP); if (!ctx->pci_cfg_vm) {
dev_err(&pdev->dev, "unable to get vm area\n");
ret = -ENOMEM; goto out4;
}
ctx->wired_entry = 8191; /* impossibly high value */
alchemy_pci_wired_entry(ctx); /* install it */
/* board may want to modify bits in the config register, do it now */
val = __raw_readl(ctx->regs + PCI_REG_CONFIG);
val &= ~pd->pci_cfg_clr;
val |= pd->pci_cfg_set;
val &= ~PCI_CONFIG_PD; /* clear disable bit */
__raw_writel(val, ctx->regs + PCI_REG_CONFIG);
wmb();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.