Lines Matching +full:pci +full:- +full:fnc
1 // SPDX-License-Identifier: GPL-2.0
3 * Support for V3 Semiconductor PCI Local Bus to PCI Bridge
6 * Based on the code from arch/arm/mach-integrator/pci_v3.c
8 * Copyright (C) 2000-2001 Deep Blue Solutions Ltd
27 #include <linux/pci.h>
36 #include "../pci.h"
91 /* PCI STATUS bits */
107 /* PCI COMMAND bits */
120 /* PCI CFG bits */
136 /* PCI BASE bits (PCI -> Local Bus) */
143 /* PCI MAP bits (PCI -> Local bus) */
152 /* LB_BASE0,1 bits (Local bus -> PCI) */
174 /* LB_MAP0,1 bits (Local bus -> PCI) */
187 /* LB_BASE2 bits (Local bus -> PCI IO) */
194 /* LB_MAP2 bits (Local bus -> PCI IO) */
231 /* ARM Integrator-specific extended control registers */
251 * The V3 PCI interface chip in Integrator provides several windows from
252 * local bus memory into the PCI memory areas. Unfortunately, there
254 * one of the windows for access to PCI configuration space. On the
259 * 40000000 - 4FFFFFFF PCI memory. 256M non-prefetchable
260 * 50000000 - 5FFFFFFF PCI memory. 256M prefetchable
261 * 60000000 - 60FFFFFF PCI IO. 16M
262 * 61000000 - 61FFFFFF PCI Configuration. 16M
266 * Base0 and Base1 can be used for any type of PCI memory access. Base2
267 * can be used either for PCI I/O or for I20 accesses. By default, uHAL
268 * uses this only for PCI IO space.
274 * Mem 40000000 - 4FFFFFFF LB_BASE0/LB_MAP0
275 * Mem 50000000 - 5FFFFFFF LB_BASE1/LB_MAP1
276 * IO 60000000 - 60FFFFFF LB_BASE2/LB_MAP2
277 * Cfg 61000000 - 61FFFFFF
279 * This means that I20 and PCI configuration space accesses will fail.
280 * When PCI configuration accesses are needed (via the uHAL PCI
285 * Mem 40000000 - 4FFFFFFF LB_BASE0/LB_MAP0
286 * Mem 50000000 - 5FFFFFFF LB_BASE0/LB_MAP0
287 * IO 60000000 - 60FFFFFF LB_BASE2/LB_MAP2
288 * Cfg 61000000 - 61FFFFFF LB_BASE1/LB_MAP1
298 * To allow PCI Configuration space access, the code enlarges the
303 * At the end of the PCI Configuration space accesses,
304 * LB_BASE1/LB_MAP1 is reset to map PCI Memory. Finally the window
310 * the mappings into PCI memory.
315 struct v3_pci *v3 = bus->sysdata; in v3_map_bus()
318 busnr = bus->number; in v3_map_bus()
325 * build the PCI configuration "address" with one-hot in in v3_map_bus()
326 * A31-A11 in v3_map_bus()
330 * 0 = PCI A1 & A0 are 0 (0) in v3_map_bus()
339 mapaddress |= BIT(slot - 5); in v3_map_bus()
356 * 0 = PCI A1 & A0 from host bus (1) in v3_map_bus()
364 * prefetchable), this frees up base1 for re-use by in v3_map_bus()
367 writel(v3_addr_to_lb_base(v3->non_pre_mem) | in v3_map_bus()
369 v3->base + V3_LB_BASE0); in v3_map_bus()
375 writel(v3_addr_to_lb_base(v3->config_mem) | in v3_map_bus()
377 v3->base + V3_LB_BASE1); in v3_map_bus()
378 writew(mapaddress, v3->base + V3_LB_MAP1); in v3_map_bus()
380 return v3->config_base + address + offset; in v3_map_bus()
386 * Reassign base1 for use by prefetchable PCI memory in v3_unmap_bus()
388 writel(v3_addr_to_lb_base(v3->pre_mem) | in v3_unmap_bus()
391 v3->base + V3_LB_BASE1); in v3_unmap_bus()
392 writew(v3_addr_to_lb_map(v3->pre_bus_addr) | in v3_unmap_bus()
394 v3->base + V3_LB_MAP1); in v3_unmap_bus()
399 writel(v3_addr_to_lb_base(v3->non_pre_mem) | in v3_unmap_bus()
401 v3->base + V3_LB_BASE0); in v3_unmap_bus()
407 struct v3_pci *v3 = bus->sysdata; in v3_pci_read_config()
410 dev_dbg(&bus->dev, in v3_pci_read_config()
411 "[read] slt: %.2d, fnc: %d, cnf: 0x%.2X, val (%d bytes): 0x%.8X\n", in v3_pci_read_config()
421 struct v3_pci *v3 = bus->sysdata; in v3_pci_write_config()
424 dev_dbg(&bus->dev, in v3_pci_write_config()
425 "[write] slt: %.2d, fnc: %d, cnf: 0x%.2X, val (%d bytes): 0x%.8X\n", in v3_pci_write_config()
441 struct device *dev = v3->dev; in v3_irq()
444 status = readw(v3->base + V3_PCI_STAT); in v3_irq()
453 writew(status, v3->base + V3_PCI_STAT); in v3_irq()
455 status = readb(v3->base + V3_LB_ISTAT); in v3_irq()
457 dev_info(dev, "PCI mailbox interrupt\n"); in v3_irq()
459 dev_err(dev, "PCI target LB->PCI READ abort interrupt\n"); in v3_irq()
461 dev_err(dev, "PCI target LB->PCI WRITE abort interrupt\n"); in v3_irq()
463 dev_info(dev, "PCI pin interrupt\n"); in v3_irq()
465 dev_err(dev, "PCI parity error interrupt\n"); in v3_irq()
473 writeb(0, v3->base + V3_LB_ISTAT); in v3_irq()
474 if (v3->map) in v3_irq()
475 regmap_write(v3->map, INTEGRATOR_SC_PCI_OFFSET, in v3_irq()
486 v3->map = in v3_integrator_init()
487 syscon_regmap_lookup_by_compatible("arm,integrator-ap-syscon"); in v3_integrator_init()
488 if (IS_ERR(v3->map)) { in v3_integrator_init()
489 dev_err(v3->dev, "no syscon\n"); in v3_integrator_init()
490 return -ENODEV; in v3_integrator_init()
493 regmap_read(v3->map, INTEGRATOR_SC_PCI_OFFSET, &val); in v3_integrator_init()
494 /* Take the PCI bridge out of reset, clear IRQs */ in v3_integrator_init()
495 regmap_write(v3->map, INTEGRATOR_SC_PCI_OFFSET, in v3_integrator_init()
504 writel(0x6200, v3->base + V3_LB_IO_BASE); in v3_integrator_init()
508 writeb(0xaa, v3->base + V3_MAIL_DATA); in v3_integrator_init()
509 writeb(0x55, v3->base + V3_MAIL_DATA + 4); in v3_integrator_init()
510 } while (readb(v3->base + V3_MAIL_DATA) != 0xaa && in v3_integrator_init()
511 readb(v3->base + V3_MAIL_DATA) != 0x55); in v3_integrator_init()
514 dev_info(v3->dev, "initialized PCI V3 Integrator/AP integration\n"); in v3_integrator_init()
523 struct device *dev = v3->dev; in v3_pci_setup_resource()
527 switch (resource_type(win->res)) { in v3_pci_setup_resource()
529 io = win->res; in v3_pci_setup_resource()
531 /* Setup window 2 - PCI I/O */ in v3_pci_setup_resource()
532 writel(v3_addr_to_lb_base2(pci_pio_to_address(io->start)) | in v3_pci_setup_resource()
534 v3->base + V3_LB_BASE2); in v3_pci_setup_resource()
535 writew(v3_addr_to_lb_map2(io->start - win->offset), in v3_pci_setup_resource()
536 v3->base + V3_LB_MAP2); in v3_pci_setup_resource()
539 mem = win->res; in v3_pci_setup_resource()
540 if (mem->flags & IORESOURCE_PREFETCH) { in v3_pci_setup_resource()
541 mem->name = "V3 PCI PRE-MEM"; in v3_pci_setup_resource()
542 v3->pre_mem = mem->start; in v3_pci_setup_resource()
543 v3->pre_bus_addr = mem->start - win->offset; in v3_pci_setup_resource()
545 mem, &v3->pre_bus_addr); in v3_pci_setup_resource()
548 return -EINVAL; in v3_pci_setup_resource()
550 if (v3->non_pre_mem && in v3_pci_setup_resource()
551 (mem->start != v3->non_pre_mem + SZ_256M)) { in v3_pci_setup_resource()
553 "prefetchable memory is not adjacent to non-prefetchable memory\n"); in v3_pci_setup_resource()
554 return -EINVAL; in v3_pci_setup_resource()
556 /* Setup window 1 - PCI prefetchable memory */ in v3_pci_setup_resource()
557 writel(v3_addr_to_lb_base(v3->pre_mem) | in v3_pci_setup_resource()
561 v3->base + V3_LB_BASE1); in v3_pci_setup_resource()
562 writew(v3_addr_to_lb_map(v3->pre_bus_addr) | in v3_pci_setup_resource()
564 v3->base + V3_LB_MAP1); in v3_pci_setup_resource()
566 mem->name = "V3 PCI NON-PRE-MEM"; in v3_pci_setup_resource()
567 v3->non_pre_mem = mem->start; in v3_pci_setup_resource()
568 v3->non_pre_bus_addr = mem->start - win->offset; in v3_pci_setup_resource()
569 dev_dbg(dev, "NON-PREFETCHABLE MEM window %pR, bus addr %pap\n", in v3_pci_setup_resource()
570 mem, &v3->non_pre_bus_addr); in v3_pci_setup_resource()
573 "non-prefetchable memory range is not 256MB\n"); in v3_pci_setup_resource()
574 return -EINVAL; in v3_pci_setup_resource()
576 /* Setup window 0 - PCI non-prefetchable memory */ in v3_pci_setup_resource()
577 writel(v3_addr_to_lb_base(v3->non_pre_mem) | in v3_pci_setup_resource()
580 v3->base + V3_LB_BASE0); in v3_pci_setup_resource()
581 writew(v3_addr_to_lb_map(v3->non_pre_bus_addr) | in v3_pci_setup_resource()
583 v3->base + V3_LB_MAP0); in v3_pci_setup_resource()
590 resource_type(win->res)); in v3_pci_setup_resource()
601 struct device *dev = v3->dev; in v3_get_dma_range_config()
602 u64 cpu_addr = entry->res->start; in v3_get_dma_range_config()
603 u64 cpu_end = entry->res->end; in v3_get_dma_range_config()
604 u64 pci_end = cpu_end - entry->offset; in v3_get_dma_range_config()
605 u64 pci_addr = entry->res->start - entry->offset; in v3_get_dma_range_config()
609 dev_err(dev, "illegal range, only PCI bits 31..20 allowed\n"); in v3_get_dma_range_config()
610 return -EINVAL; in v3_get_dma_range_config()
617 return -EINVAL; in v3_get_dma_range_config()
621 switch (resource_size(entry->res)) { in v3_get_dma_range_config()
659 dev_err(v3->dev, "illegal dma memory chunk size\n"); in v3_get_dma_range_config()
660 return -EINVAL; in v3_get_dma_range_config()
666 "DMA MEM CPU: 0x%016llx -> 0x%016llx => " in v3_get_dma_range_config()
667 "PCI: 0x%016llx -> 0x%016llx base %08x map %08x\n", in v3_get_dma_range_config()
679 struct device *dev = v3->dev; in v3_pci_parse_map_dma_ranges()
683 resource_list_for_each_entry(entry, &bridge->dma_ranges) { in v3_pci_parse_map_dma_ranges()
692 writel(pci_base, v3->base + V3_PCI_BASE0); in v3_pci_parse_map_dma_ranges()
693 writel(pci_map, v3->base + V3_PCI_MAP0); in v3_pci_parse_map_dma_ranges()
695 writel(pci_base, v3->base + V3_PCI_BASE1); in v3_pci_parse_map_dma_ranges()
696 writel(pci_map, v3->base + V3_PCI_MAP1); in v3_pci_parse_map_dma_ranges()
708 struct device *dev = &pdev->dev; in v3_pci_probe()
709 struct device_node *np = dev->of_node; in v3_pci_probe()
721 return -ENOMEM; in v3_pci_probe()
723 host->ops = &v3_pci_ops; in v3_pci_probe()
725 host->sysdata = v3; in v3_pci_probe()
726 v3->dev = dev; in v3_pci_probe()
741 v3->base = devm_ioremap_resource(dev, regs); in v3_pci_probe()
742 if (IS_ERR(v3->base)) in v3_pci_probe()
743 return PTR_ERR(v3->base); in v3_pci_probe()
749 if (readl(v3->base + V3_LB_IO_BASE) != (regs->start >> 16)) in v3_pci_probe()
751 readl(v3->base + V3_LB_IO_BASE), regs); in v3_pci_probe()
757 return -EINVAL; in v3_pci_probe()
759 v3->config_mem = regs->start; in v3_pci_probe()
760 v3->config_base = devm_ioremap_resource(dev, regs); in v3_pci_probe()
761 if (IS_ERR(v3->config_base)) in v3_pci_probe()
762 return PTR_ERR(v3->config_base); in v3_pci_probe()
781 if (readw(v3->base + V3_SYSTEM) & V3_SYSTEM_M_LOCK) in v3_pci_probe()
782 writew(V3_SYSTEM_UNLOCK, v3->base + V3_SYSTEM); in v3_pci_probe()
785 val = readw(v3->base + V3_PCI_CMD); in v3_pci_probe()
787 writew(val, v3->base + V3_PCI_CMD); in v3_pci_probe()
789 /* Put the PCI bus into reset */ in v3_pci_probe()
790 val = readw(v3->base + V3_SYSTEM); in v3_pci_probe()
792 writew(val, v3->base + V3_SYSTEM); in v3_pci_probe()
795 val = readw(v3->base + V3_PCI_CFG); in v3_pci_probe()
797 writew(val, v3->base + V3_PCI_CFG); in v3_pci_probe()
800 val = readw(v3->base + V3_LB_CFG); in v3_pci_probe()
805 writew(val, v3->base + V3_LB_CFG); in v3_pci_probe()
807 /* Enable the PCI bus master */ in v3_pci_probe()
808 val = readw(v3->base + V3_PCI_CMD); in v3_pci_probe()
810 writew(val, v3->base + V3_PCI_CMD); in v3_pci_probe()
813 resource_list_for_each_entry(win, &host->windows) { in v3_pci_probe()
825 * Disable PCI to host IO cycles, enable I/O buffers @3.3V, in v3_pci_probe()
829 writel(0x00000000, v3->base + V3_PCI_IO_BASE); in v3_pci_probe()
833 * DMA read and write from PCI bus commands types in v3_pci_probe()
837 writew(val, v3->base + V3_PCI_CFG); in v3_pci_probe()
842 * on aperture 1. Same for PCI. in v3_pci_probe()
848 v3->base + V3_FIFO_PRIORITY); in v3_pci_probe()
855 writeb(0, v3->base + V3_LB_ISTAT); in v3_pci_probe()
856 val = readw(v3->base + V3_LB_CFG); in v3_pci_probe()
858 writew(val, v3->base + V3_LB_CFG); in v3_pci_probe()
860 v3->base + V3_LB_IMASK); in v3_pci_probe()
863 if (of_device_is_compatible(np, "arm,integrator-ap-pci")) { in v3_pci_probe()
869 /* Post-init: enable PCI memory and invalidate (master already on) */ in v3_pci_probe()
870 val = readw(v3->base + V3_PCI_CMD); in v3_pci_probe()
872 writew(val, v3->base + V3_PCI_CMD); in v3_pci_probe()
875 writeb(0, v3->base + V3_LB_ISTAT); in v3_pci_probe()
878 v3->base + V3_LB_IMASK); in v3_pci_probe()
880 /* Take the PCI bus out of reset so devices can initialize */ in v3_pci_probe()
881 val = readw(v3->base + V3_SYSTEM); in v3_pci_probe()
883 writew(val, v3->base + V3_SYSTEM); in v3_pci_probe()
886 * Re-lock the system register. in v3_pci_probe()
888 val = readw(v3->base + V3_SYSTEM); in v3_pci_probe()
890 writew(val, v3->base + V3_SYSTEM); in v3_pci_probe()
897 .compatible = "v3,v360epc-pci",
904 .name = "pci-v3-semi",