1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2a88b5ba8SSam Ravnborg /* pci_fire.c: Sun4u platform PCI-E controller support. 3a88b5ba8SSam Ravnborg * 4a88b5ba8SSam Ravnborg * Copyright (C) 2007 David S. Miller (davem@davemloft.net) 5a88b5ba8SSam Ravnborg */ 6a88b5ba8SSam Ravnborg #include <linux/kernel.h> 7a88b5ba8SSam Ravnborg #include <linux/pci.h> 8a88b5ba8SSam Ravnborg #include <linux/slab.h> 9a88b5ba8SSam Ravnborg #include <linux/init.h> 10a88b5ba8SSam Ravnborg #include <linux/msi.h> 117b64db60SPaul Gortmaker #include <linux/export.h> 12a88b5ba8SSam Ravnborg #include <linux/irq.h> 13a88b5ba8SSam Ravnborg #include <linux/of_device.h> 14*98fa15f3SAnshuman Khandual #include <linux/numa.h> 15a88b5ba8SSam Ravnborg 16a88b5ba8SSam Ravnborg #include <asm/prom.h> 17a88b5ba8SSam Ravnborg #include <asm/irq.h> 18a88b5ba8SSam Ravnborg #include <asm/upa.h> 19a88b5ba8SSam Ravnborg 20a88b5ba8SSam Ravnborg #include "pci_impl.h" 21a88b5ba8SSam Ravnborg 22a88b5ba8SSam Ravnborg #define DRIVER_NAME "fire" 23a88b5ba8SSam Ravnborg #define PFX DRIVER_NAME ": " 24a88b5ba8SSam Ravnborg 25a88b5ba8SSam Ravnborg #define FIRE_IOMMU_CONTROL 0x40000UL 26a88b5ba8SSam Ravnborg #define FIRE_IOMMU_TSBBASE 0x40008UL 27a88b5ba8SSam Ravnborg #define FIRE_IOMMU_FLUSH 0x40100UL 28a88b5ba8SSam Ravnborg #define FIRE_IOMMU_FLUSHINV 0x40108UL 29a88b5ba8SSam Ravnborg 30a88b5ba8SSam Ravnborg static int pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm) 31a88b5ba8SSam Ravnborg { 32a88b5ba8SSam Ravnborg struct iommu *iommu = pbm->iommu; 33a88b5ba8SSam Ravnborg u32 vdma[2], dma_mask; 34a88b5ba8SSam Ravnborg u64 control; 35a88b5ba8SSam Ravnborg int tsbsize, err; 36a88b5ba8SSam Ravnborg 37a88b5ba8SSam Ravnborg /* No virtual-dma property on these guys, use largest size. */ 38a88b5ba8SSam Ravnborg vdma[0] = 0xc0000000; /* base */ 39a88b5ba8SSam Ravnborg vdma[1] = 0x40000000; /* size */ 40a88b5ba8SSam Ravnborg dma_mask = 0xffffffff; 41a88b5ba8SSam Ravnborg tsbsize = 128; 42a88b5ba8SSam Ravnborg 43a88b5ba8SSam Ravnborg /* Register addresses. */ 44a88b5ba8SSam Ravnborg iommu->iommu_control = pbm->pbm_regs + FIRE_IOMMU_CONTROL; 45a88b5ba8SSam Ravnborg iommu->iommu_tsbbase = pbm->pbm_regs + FIRE_IOMMU_TSBBASE; 46a88b5ba8SSam Ravnborg iommu->iommu_flush = pbm->pbm_regs + FIRE_IOMMU_FLUSH; 47a88b5ba8SSam Ravnborg iommu->iommu_flushinv = pbm->pbm_regs + FIRE_IOMMU_FLUSHINV; 48a88b5ba8SSam Ravnborg 49a88b5ba8SSam Ravnborg /* We use the main control/status register of FIRE as the write 50a88b5ba8SSam Ravnborg * completion register. 51a88b5ba8SSam Ravnborg */ 52a88b5ba8SSam Ravnborg iommu->write_complete_reg = pbm->controller_regs + 0x410000UL; 53a88b5ba8SSam Ravnborg 54a88b5ba8SSam Ravnborg /* 55a88b5ba8SSam Ravnborg * Invalidate TLB Entries. 56a88b5ba8SSam Ravnborg */ 57a88b5ba8SSam Ravnborg upa_writeq(~(u64)0, iommu->iommu_flushinv); 58a88b5ba8SSam Ravnborg 59a88b5ba8SSam Ravnborg err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask, 60a88b5ba8SSam Ravnborg pbm->numa_node); 61a88b5ba8SSam Ravnborg if (err) 62a88b5ba8SSam Ravnborg return err; 63a88b5ba8SSam Ravnborg 64a88b5ba8SSam Ravnborg upa_writeq(__pa(iommu->page_table) | 0x7UL, iommu->iommu_tsbbase); 65a88b5ba8SSam Ravnborg 66a88b5ba8SSam Ravnborg control = upa_readq(iommu->iommu_control); 67a88b5ba8SSam Ravnborg control |= (0x00000400 /* TSB cache snoop enable */ | 68a88b5ba8SSam Ravnborg 0x00000300 /* Cache mode */ | 69a88b5ba8SSam Ravnborg 0x00000002 /* Bypass enable */ | 70a88b5ba8SSam Ravnborg 0x00000001 /* Translation enable */); 71a88b5ba8SSam Ravnborg upa_writeq(control, iommu->iommu_control); 72a88b5ba8SSam Ravnborg 73a88b5ba8SSam Ravnborg return 0; 74a88b5ba8SSam Ravnborg } 75a88b5ba8SSam Ravnborg 76a88b5ba8SSam Ravnborg #ifdef CONFIG_PCI_MSI 77a88b5ba8SSam Ravnborg struct pci_msiq_entry { 78a88b5ba8SSam Ravnborg u64 word0; 79a88b5ba8SSam Ravnborg #define MSIQ_WORD0_RESV 0x8000000000000000UL 80a88b5ba8SSam Ravnborg #define MSIQ_WORD0_FMT_TYPE 0x7f00000000000000UL 81a88b5ba8SSam Ravnborg #define MSIQ_WORD0_FMT_TYPE_SHIFT 56 82a88b5ba8SSam Ravnborg #define MSIQ_WORD0_LEN 0x00ffc00000000000UL 83a88b5ba8SSam Ravnborg #define MSIQ_WORD0_LEN_SHIFT 46 84a88b5ba8SSam Ravnborg #define MSIQ_WORD0_ADDR0 0x00003fff00000000UL 85a88b5ba8SSam Ravnborg #define MSIQ_WORD0_ADDR0_SHIFT 32 86a88b5ba8SSam Ravnborg #define MSIQ_WORD0_RID 0x00000000ffff0000UL 87a88b5ba8SSam Ravnborg #define MSIQ_WORD0_RID_SHIFT 16 88a88b5ba8SSam Ravnborg #define MSIQ_WORD0_DATA0 0x000000000000ffffUL 89a88b5ba8SSam Ravnborg #define MSIQ_WORD0_DATA0_SHIFT 0 90a88b5ba8SSam Ravnborg 91a88b5ba8SSam Ravnborg #define MSIQ_TYPE_MSG 0x6 92a88b5ba8SSam Ravnborg #define MSIQ_TYPE_MSI32 0xb 93a88b5ba8SSam Ravnborg #define MSIQ_TYPE_MSI64 0xf 94a88b5ba8SSam Ravnborg 95a88b5ba8SSam Ravnborg u64 word1; 96a88b5ba8SSam Ravnborg #define MSIQ_WORD1_ADDR1 0xffffffffffff0000UL 97a88b5ba8SSam Ravnborg #define MSIQ_WORD1_ADDR1_SHIFT 16 98a88b5ba8SSam Ravnborg #define MSIQ_WORD1_DATA1 0x000000000000ffffUL 99a88b5ba8SSam Ravnborg #define MSIQ_WORD1_DATA1_SHIFT 0 100a88b5ba8SSam Ravnborg 101a88b5ba8SSam Ravnborg u64 resv[6]; 102a88b5ba8SSam Ravnborg }; 103a88b5ba8SSam Ravnborg 104a88b5ba8SSam Ravnborg /* All MSI registers are offset from pbm->pbm_regs */ 105a88b5ba8SSam Ravnborg #define EVENT_QUEUE_BASE_ADDR_REG 0x010000UL 106a88b5ba8SSam Ravnborg #define EVENT_QUEUE_BASE_ADDR_ALL_ONES 0xfffc000000000000UL 107a88b5ba8SSam Ravnborg 108a88b5ba8SSam Ravnborg #define EVENT_QUEUE_CONTROL_SET(EQ) (0x011000UL + (EQ) * 0x8UL) 109a88b5ba8SSam Ravnborg #define EVENT_QUEUE_CONTROL_SET_OFLOW 0x0200000000000000UL 110a88b5ba8SSam Ravnborg #define EVENT_QUEUE_CONTROL_SET_EN 0x0000100000000000UL 111a88b5ba8SSam Ravnborg 112a88b5ba8SSam Ravnborg #define EVENT_QUEUE_CONTROL_CLEAR(EQ) (0x011200UL + (EQ) * 0x8UL) 113a88b5ba8SSam Ravnborg #define EVENT_QUEUE_CONTROL_CLEAR_OF 0x0200000000000000UL 114a88b5ba8SSam Ravnborg #define EVENT_QUEUE_CONTROL_CLEAR_E2I 0x0000800000000000UL 115a88b5ba8SSam Ravnborg #define EVENT_QUEUE_CONTROL_CLEAR_DIS 0x0000100000000000UL 116a88b5ba8SSam Ravnborg 117a88b5ba8SSam Ravnborg #define EVENT_QUEUE_STATE(EQ) (0x011400UL + (EQ) * 0x8UL) 118a88b5ba8SSam Ravnborg #define EVENT_QUEUE_STATE_MASK 0x0000000000000007UL 119a88b5ba8SSam Ravnborg #define EVENT_QUEUE_STATE_IDLE 0x0000000000000001UL 120a88b5ba8SSam Ravnborg #define EVENT_QUEUE_STATE_ACTIVE 0x0000000000000002UL 121a88b5ba8SSam Ravnborg #define EVENT_QUEUE_STATE_ERROR 0x0000000000000004UL 122a88b5ba8SSam Ravnborg 123a88b5ba8SSam Ravnborg #define EVENT_QUEUE_TAIL(EQ) (0x011600UL + (EQ) * 0x8UL) 124a88b5ba8SSam Ravnborg #define EVENT_QUEUE_TAIL_OFLOW 0x0200000000000000UL 125a88b5ba8SSam Ravnborg #define EVENT_QUEUE_TAIL_VAL 0x000000000000007fUL 126a88b5ba8SSam Ravnborg 127a88b5ba8SSam Ravnborg #define EVENT_QUEUE_HEAD(EQ) (0x011800UL + (EQ) * 0x8UL) 128a88b5ba8SSam Ravnborg #define EVENT_QUEUE_HEAD_VAL 0x000000000000007fUL 129a88b5ba8SSam Ravnborg 130a88b5ba8SSam Ravnborg #define MSI_MAP(MSI) (0x020000UL + (MSI) * 0x8UL) 131a88b5ba8SSam Ravnborg #define MSI_MAP_VALID 0x8000000000000000UL 132a88b5ba8SSam Ravnborg #define MSI_MAP_EQWR_N 0x4000000000000000UL 133a88b5ba8SSam Ravnborg #define MSI_MAP_EQNUM 0x000000000000003fUL 134a88b5ba8SSam Ravnborg 135a88b5ba8SSam Ravnborg #define MSI_CLEAR(MSI) (0x028000UL + (MSI) * 0x8UL) 136a88b5ba8SSam Ravnborg #define MSI_CLEAR_EQWR_N 0x4000000000000000UL 137a88b5ba8SSam Ravnborg 138a88b5ba8SSam Ravnborg #define IMONDO_DATA0 0x02C000UL 139a88b5ba8SSam Ravnborg #define IMONDO_DATA0_DATA 0xffffffffffffffc0UL 140a88b5ba8SSam Ravnborg 141a88b5ba8SSam Ravnborg #define IMONDO_DATA1 0x02C008UL 142a88b5ba8SSam Ravnborg #define IMONDO_DATA1_DATA 0xffffffffffffffffUL 143a88b5ba8SSam Ravnborg 144a88b5ba8SSam Ravnborg #define MSI_32BIT_ADDR 0x034000UL 145a88b5ba8SSam Ravnborg #define MSI_32BIT_ADDR_VAL 0x00000000ffff0000UL 146a88b5ba8SSam Ravnborg 147a88b5ba8SSam Ravnborg #define MSI_64BIT_ADDR 0x034008UL 148a88b5ba8SSam Ravnborg #define MSI_64BIT_ADDR_VAL 0xffffffffffff0000UL 149a88b5ba8SSam Ravnborg 150a88b5ba8SSam Ravnborg static int pci_fire_get_head(struct pci_pbm_info *pbm, unsigned long msiqid, 151a88b5ba8SSam Ravnborg unsigned long *head) 152a88b5ba8SSam Ravnborg { 153a88b5ba8SSam Ravnborg *head = upa_readq(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid)); 154a88b5ba8SSam Ravnborg return 0; 155a88b5ba8SSam Ravnborg } 156a88b5ba8SSam Ravnborg 157a88b5ba8SSam Ravnborg static int pci_fire_dequeue_msi(struct pci_pbm_info *pbm, unsigned long msiqid, 158a88b5ba8SSam Ravnborg unsigned long *head, unsigned long *msi) 159a88b5ba8SSam Ravnborg { 160a88b5ba8SSam Ravnborg unsigned long type_fmt, type, msi_num; 161a88b5ba8SSam Ravnborg struct pci_msiq_entry *base, *ep; 162a88b5ba8SSam Ravnborg 163a88b5ba8SSam Ravnborg base = (pbm->msi_queues + ((msiqid - pbm->msiq_first) * 8192)); 164a88b5ba8SSam Ravnborg ep = &base[*head]; 165a88b5ba8SSam Ravnborg 166a88b5ba8SSam Ravnborg if ((ep->word0 & MSIQ_WORD0_FMT_TYPE) == 0) 167a88b5ba8SSam Ravnborg return 0; 168a88b5ba8SSam Ravnborg 169a88b5ba8SSam Ravnborg type_fmt = ((ep->word0 & MSIQ_WORD0_FMT_TYPE) >> 170a88b5ba8SSam Ravnborg MSIQ_WORD0_FMT_TYPE_SHIFT); 171a88b5ba8SSam Ravnborg type = (type_fmt >> 3); 172a88b5ba8SSam Ravnborg if (unlikely(type != MSIQ_TYPE_MSI32 && 173a88b5ba8SSam Ravnborg type != MSIQ_TYPE_MSI64)) 174a88b5ba8SSam Ravnborg return -EINVAL; 175a88b5ba8SSam Ravnborg 176a88b5ba8SSam Ravnborg *msi = msi_num = ((ep->word0 & MSIQ_WORD0_DATA0) >> 177a88b5ba8SSam Ravnborg MSIQ_WORD0_DATA0_SHIFT); 178a88b5ba8SSam Ravnborg 179a88b5ba8SSam Ravnborg upa_writeq(MSI_CLEAR_EQWR_N, pbm->pbm_regs + MSI_CLEAR(msi_num)); 180a88b5ba8SSam Ravnborg 181a88b5ba8SSam Ravnborg /* Clear the entry. */ 182a88b5ba8SSam Ravnborg ep->word0 &= ~MSIQ_WORD0_FMT_TYPE; 183a88b5ba8SSam Ravnborg 184a88b5ba8SSam Ravnborg /* Go to next entry in ring. */ 185a88b5ba8SSam Ravnborg (*head)++; 186a88b5ba8SSam Ravnborg if (*head >= pbm->msiq_ent_count) 187a88b5ba8SSam Ravnborg *head = 0; 188a88b5ba8SSam Ravnborg 189a88b5ba8SSam Ravnborg return 1; 190a88b5ba8SSam Ravnborg } 191a88b5ba8SSam Ravnborg 192a88b5ba8SSam Ravnborg static int pci_fire_set_head(struct pci_pbm_info *pbm, unsigned long msiqid, 193a88b5ba8SSam Ravnborg unsigned long head) 194a88b5ba8SSam Ravnborg { 195a88b5ba8SSam Ravnborg upa_writeq(head, pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid)); 196a88b5ba8SSam Ravnborg return 0; 197a88b5ba8SSam Ravnborg } 198a88b5ba8SSam Ravnborg 199a88b5ba8SSam Ravnborg static int pci_fire_msi_setup(struct pci_pbm_info *pbm, unsigned long msiqid, 200a88b5ba8SSam Ravnborg unsigned long msi, int is_msi64) 201a88b5ba8SSam Ravnborg { 202a88b5ba8SSam Ravnborg u64 val; 203a88b5ba8SSam Ravnborg 204a88b5ba8SSam Ravnborg val = upa_readq(pbm->pbm_regs + MSI_MAP(msi)); 205a88b5ba8SSam Ravnborg val &= ~(MSI_MAP_EQNUM); 206a88b5ba8SSam Ravnborg val |= msiqid; 207a88b5ba8SSam Ravnborg upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi)); 208a88b5ba8SSam Ravnborg 209a88b5ba8SSam Ravnborg upa_writeq(MSI_CLEAR_EQWR_N, pbm->pbm_regs + MSI_CLEAR(msi)); 210a88b5ba8SSam Ravnborg 211a88b5ba8SSam Ravnborg val = upa_readq(pbm->pbm_regs + MSI_MAP(msi)); 212a88b5ba8SSam Ravnborg val |= MSI_MAP_VALID; 213a88b5ba8SSam Ravnborg upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi)); 214a88b5ba8SSam Ravnborg 215a88b5ba8SSam Ravnborg return 0; 216a88b5ba8SSam Ravnborg } 217a88b5ba8SSam Ravnborg 218a88b5ba8SSam Ravnborg static int pci_fire_msi_teardown(struct pci_pbm_info *pbm, unsigned long msi) 219a88b5ba8SSam Ravnborg { 220a88b5ba8SSam Ravnborg u64 val; 221a88b5ba8SSam Ravnborg 222a88b5ba8SSam Ravnborg val = upa_readq(pbm->pbm_regs + MSI_MAP(msi)); 223a88b5ba8SSam Ravnborg 224a88b5ba8SSam Ravnborg val &= ~MSI_MAP_VALID; 225a88b5ba8SSam Ravnborg 226a88b5ba8SSam Ravnborg upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi)); 227a88b5ba8SSam Ravnborg 228a88b5ba8SSam Ravnborg return 0; 229a88b5ba8SSam Ravnborg } 230a88b5ba8SSam Ravnborg 231a88b5ba8SSam Ravnborg static int pci_fire_msiq_alloc(struct pci_pbm_info *pbm) 232a88b5ba8SSam Ravnborg { 233a88b5ba8SSam Ravnborg unsigned long pages, order, i; 234a88b5ba8SSam Ravnborg 235a88b5ba8SSam Ravnborg order = get_order(512 * 1024); 236a88b5ba8SSam Ravnborg pages = __get_free_pages(GFP_KERNEL | __GFP_COMP, order); 237a88b5ba8SSam Ravnborg if (pages == 0UL) { 238a88b5ba8SSam Ravnborg printk(KERN_ERR "MSI: Cannot allocate MSI queues (o=%lu).\n", 239a88b5ba8SSam Ravnborg order); 240a88b5ba8SSam Ravnborg return -ENOMEM; 241a88b5ba8SSam Ravnborg } 242a88b5ba8SSam Ravnborg memset((char *)pages, 0, PAGE_SIZE << order); 243a88b5ba8SSam Ravnborg pbm->msi_queues = (void *) pages; 244a88b5ba8SSam Ravnborg 245a88b5ba8SSam Ravnborg upa_writeq((EVENT_QUEUE_BASE_ADDR_ALL_ONES | 246a88b5ba8SSam Ravnborg __pa(pbm->msi_queues)), 247a88b5ba8SSam Ravnborg pbm->pbm_regs + EVENT_QUEUE_BASE_ADDR_REG); 248a88b5ba8SSam Ravnborg 249a88b5ba8SSam Ravnborg upa_writeq(pbm->portid << 6, pbm->pbm_regs + IMONDO_DATA0); 250a88b5ba8SSam Ravnborg upa_writeq(0, pbm->pbm_regs + IMONDO_DATA1); 251a88b5ba8SSam Ravnborg 252a88b5ba8SSam Ravnborg upa_writeq(pbm->msi32_start, pbm->pbm_regs + MSI_32BIT_ADDR); 253a88b5ba8SSam Ravnborg upa_writeq(pbm->msi64_start, pbm->pbm_regs + MSI_64BIT_ADDR); 254a88b5ba8SSam Ravnborg 255a88b5ba8SSam Ravnborg for (i = 0; i < pbm->msiq_num; i++) { 256a88b5ba8SSam Ravnborg upa_writeq(0, pbm->pbm_regs + EVENT_QUEUE_HEAD(i)); 257a88b5ba8SSam Ravnborg upa_writeq(0, pbm->pbm_regs + EVENT_QUEUE_TAIL(i)); 258a88b5ba8SSam Ravnborg } 259a88b5ba8SSam Ravnborg 260a88b5ba8SSam Ravnborg return 0; 261a88b5ba8SSam Ravnborg } 262a88b5ba8SSam Ravnborg 263a88b5ba8SSam Ravnborg static void pci_fire_msiq_free(struct pci_pbm_info *pbm) 264a88b5ba8SSam Ravnborg { 265a88b5ba8SSam Ravnborg unsigned long pages, order; 266a88b5ba8SSam Ravnborg 267a88b5ba8SSam Ravnborg order = get_order(512 * 1024); 268a88b5ba8SSam Ravnborg pages = (unsigned long) pbm->msi_queues; 269a88b5ba8SSam Ravnborg 270a88b5ba8SSam Ravnborg free_pages(pages, order); 271a88b5ba8SSam Ravnborg 272a88b5ba8SSam Ravnborg pbm->msi_queues = NULL; 273a88b5ba8SSam Ravnborg } 274a88b5ba8SSam Ravnborg 275a88b5ba8SSam Ravnborg static int pci_fire_msiq_build_irq(struct pci_pbm_info *pbm, 276a88b5ba8SSam Ravnborg unsigned long msiqid, 277a88b5ba8SSam Ravnborg unsigned long devino) 278a88b5ba8SSam Ravnborg { 279a88b5ba8SSam Ravnborg unsigned long cregs = (unsigned long) pbm->pbm_regs; 280a88b5ba8SSam Ravnborg unsigned long imap_reg, iclr_reg, int_ctrlr; 28144ed3c0cSSam Ravnborg unsigned int irq; 282a88b5ba8SSam Ravnborg int fixup; 283a88b5ba8SSam Ravnborg u64 val; 284a88b5ba8SSam Ravnborg 285a88b5ba8SSam Ravnborg imap_reg = cregs + (0x001000UL + (devino * 0x08UL)); 286a88b5ba8SSam Ravnborg iclr_reg = cregs + (0x001400UL + (devino * 0x08UL)); 287a88b5ba8SSam Ravnborg 288a88b5ba8SSam Ravnborg /* XXX iterate amongst the 4 IRQ controllers XXX */ 289a88b5ba8SSam Ravnborg int_ctrlr = (1UL << 6); 290a88b5ba8SSam Ravnborg 291a88b5ba8SSam Ravnborg val = upa_readq(imap_reg); 292a88b5ba8SSam Ravnborg val |= (1UL << 63) | int_ctrlr; 293a88b5ba8SSam Ravnborg upa_writeq(val, imap_reg); 294a88b5ba8SSam Ravnborg 295a88b5ba8SSam Ravnborg fixup = ((pbm->portid << 6) | devino) - int_ctrlr; 296a88b5ba8SSam Ravnborg 29744ed3c0cSSam Ravnborg irq = build_irq(fixup, iclr_reg, imap_reg); 29844ed3c0cSSam Ravnborg if (!irq) 299a88b5ba8SSam Ravnborg return -ENOMEM; 300a88b5ba8SSam Ravnborg 301a88b5ba8SSam Ravnborg upa_writeq(EVENT_QUEUE_CONTROL_SET_EN, 302a88b5ba8SSam Ravnborg pbm->pbm_regs + EVENT_QUEUE_CONTROL_SET(msiqid)); 303a88b5ba8SSam Ravnborg 30444ed3c0cSSam Ravnborg return irq; 305a88b5ba8SSam Ravnborg } 306a88b5ba8SSam Ravnborg 307a88b5ba8SSam Ravnborg static const struct sparc64_msiq_ops pci_fire_msiq_ops = { 308a88b5ba8SSam Ravnborg .get_head = pci_fire_get_head, 309a88b5ba8SSam Ravnborg .dequeue_msi = pci_fire_dequeue_msi, 310a88b5ba8SSam Ravnborg .set_head = pci_fire_set_head, 311a88b5ba8SSam Ravnborg .msi_setup = pci_fire_msi_setup, 312a88b5ba8SSam Ravnborg .msi_teardown = pci_fire_msi_teardown, 313a88b5ba8SSam Ravnborg .msiq_alloc = pci_fire_msiq_alloc, 314a88b5ba8SSam Ravnborg .msiq_free = pci_fire_msiq_free, 315a88b5ba8SSam Ravnborg .msiq_build_irq = pci_fire_msiq_build_irq, 316a88b5ba8SSam Ravnborg }; 317a88b5ba8SSam Ravnborg 318a88b5ba8SSam Ravnborg static void pci_fire_msi_init(struct pci_pbm_info *pbm) 319a88b5ba8SSam Ravnborg { 320a88b5ba8SSam Ravnborg sparc64_pbm_msi_init(pbm, &pci_fire_msiq_ops); 321a88b5ba8SSam Ravnborg } 322a88b5ba8SSam Ravnborg #else /* CONFIG_PCI_MSI */ 323a88b5ba8SSam Ravnborg static void pci_fire_msi_init(struct pci_pbm_info *pbm) 324a88b5ba8SSam Ravnborg { 325a88b5ba8SSam Ravnborg } 326a88b5ba8SSam Ravnborg #endif /* !(CONFIG_PCI_MSI) */ 327a88b5ba8SSam Ravnborg 328a88b5ba8SSam Ravnborg /* Based at pbm->controller_regs */ 329a88b5ba8SSam Ravnborg #define FIRE_PARITY_CONTROL 0x470010UL 330a88b5ba8SSam Ravnborg #define FIRE_PARITY_ENAB 0x8000000000000000UL 331a88b5ba8SSam Ravnborg #define FIRE_FATAL_RESET_CTL 0x471028UL 332a88b5ba8SSam Ravnborg #define FIRE_FATAL_RESET_SPARE 0x0000000004000000UL 333a88b5ba8SSam Ravnborg #define FIRE_FATAL_RESET_MB 0x0000000002000000UL 334a88b5ba8SSam Ravnborg #define FIRE_FATAL_RESET_CPE 0x0000000000008000UL 335a88b5ba8SSam Ravnborg #define FIRE_FATAL_RESET_APE 0x0000000000004000UL 336a88b5ba8SSam Ravnborg #define FIRE_FATAL_RESET_PIO 0x0000000000000040UL 337a88b5ba8SSam Ravnborg #define FIRE_FATAL_RESET_JW 0x0000000000000004UL 338a88b5ba8SSam Ravnborg #define FIRE_FATAL_RESET_JI 0x0000000000000002UL 339a88b5ba8SSam Ravnborg #define FIRE_FATAL_RESET_JR 0x0000000000000001UL 340a88b5ba8SSam Ravnborg #define FIRE_CORE_INTR_ENABLE 0x471800UL 341a88b5ba8SSam Ravnborg 342a88b5ba8SSam Ravnborg /* Based at pbm->pbm_regs */ 343a88b5ba8SSam Ravnborg #define FIRE_TLU_CTRL 0x80000UL 344a88b5ba8SSam Ravnborg #define FIRE_TLU_CTRL_TIM 0x00000000da000000UL 345a88b5ba8SSam Ravnborg #define FIRE_TLU_CTRL_QDET 0x0000000000000100UL 346a88b5ba8SSam Ravnborg #define FIRE_TLU_CTRL_CFG 0x0000000000000001UL 347a88b5ba8SSam Ravnborg #define FIRE_TLU_DEV_CTRL 0x90008UL 348a88b5ba8SSam Ravnborg #define FIRE_TLU_LINK_CTRL 0x90020UL 349a88b5ba8SSam Ravnborg #define FIRE_TLU_LINK_CTRL_CLK 0x0000000000000040UL 350a88b5ba8SSam Ravnborg #define FIRE_LPU_RESET 0xe2008UL 351a88b5ba8SSam Ravnborg #define FIRE_LPU_LLCFG 0xe2200UL 352a88b5ba8SSam Ravnborg #define FIRE_LPU_LLCFG_VC0 0x0000000000000100UL 353a88b5ba8SSam Ravnborg #define FIRE_LPU_FCTRL_UCTRL 0xe2240UL 354a88b5ba8SSam Ravnborg #define FIRE_LPU_FCTRL_UCTRL_N 0x0000000000000002UL 355a88b5ba8SSam Ravnborg #define FIRE_LPU_FCTRL_UCTRL_P 0x0000000000000001UL 356a88b5ba8SSam Ravnborg #define FIRE_LPU_TXL_FIFOP 0xe2430UL 357a88b5ba8SSam Ravnborg #define FIRE_LPU_LTSSM_CFG2 0xe2788UL 358a88b5ba8SSam Ravnborg #define FIRE_LPU_LTSSM_CFG3 0xe2790UL 359a88b5ba8SSam Ravnborg #define FIRE_LPU_LTSSM_CFG4 0xe2798UL 360a88b5ba8SSam Ravnborg #define FIRE_LPU_LTSSM_CFG5 0xe27a0UL 361a88b5ba8SSam Ravnborg #define FIRE_DMC_IENAB 0x31800UL 362a88b5ba8SSam Ravnborg #define FIRE_DMC_DBG_SEL_A 0x53000UL 363a88b5ba8SSam Ravnborg #define FIRE_DMC_DBG_SEL_B 0x53008UL 364a88b5ba8SSam Ravnborg #define FIRE_PEC_IENAB 0x51800UL 365a88b5ba8SSam Ravnborg 366a88b5ba8SSam Ravnborg static void pci_fire_hw_init(struct pci_pbm_info *pbm) 367a88b5ba8SSam Ravnborg { 368a88b5ba8SSam Ravnborg u64 val; 369a88b5ba8SSam Ravnborg 370a88b5ba8SSam Ravnborg upa_writeq(FIRE_PARITY_ENAB, 371a88b5ba8SSam Ravnborg pbm->controller_regs + FIRE_PARITY_CONTROL); 372a88b5ba8SSam Ravnborg 373a88b5ba8SSam Ravnborg upa_writeq((FIRE_FATAL_RESET_SPARE | 374a88b5ba8SSam Ravnborg FIRE_FATAL_RESET_MB | 375a88b5ba8SSam Ravnborg FIRE_FATAL_RESET_CPE | 376a88b5ba8SSam Ravnborg FIRE_FATAL_RESET_APE | 377a88b5ba8SSam Ravnborg FIRE_FATAL_RESET_PIO | 378a88b5ba8SSam Ravnborg FIRE_FATAL_RESET_JW | 379a88b5ba8SSam Ravnborg FIRE_FATAL_RESET_JI | 380a88b5ba8SSam Ravnborg FIRE_FATAL_RESET_JR), 381a88b5ba8SSam Ravnborg pbm->controller_regs + FIRE_FATAL_RESET_CTL); 382a88b5ba8SSam Ravnborg 383a88b5ba8SSam Ravnborg upa_writeq(~(u64)0, pbm->controller_regs + FIRE_CORE_INTR_ENABLE); 384a88b5ba8SSam Ravnborg 385a88b5ba8SSam Ravnborg val = upa_readq(pbm->pbm_regs + FIRE_TLU_CTRL); 386a88b5ba8SSam Ravnborg val |= (FIRE_TLU_CTRL_TIM | 387a88b5ba8SSam Ravnborg FIRE_TLU_CTRL_QDET | 388a88b5ba8SSam Ravnborg FIRE_TLU_CTRL_CFG); 389a88b5ba8SSam Ravnborg upa_writeq(val, pbm->pbm_regs + FIRE_TLU_CTRL); 390a88b5ba8SSam Ravnborg upa_writeq(0, pbm->pbm_regs + FIRE_TLU_DEV_CTRL); 391a88b5ba8SSam Ravnborg upa_writeq(FIRE_TLU_LINK_CTRL_CLK, 392a88b5ba8SSam Ravnborg pbm->pbm_regs + FIRE_TLU_LINK_CTRL); 393a88b5ba8SSam Ravnborg 394a88b5ba8SSam Ravnborg upa_writeq(0, pbm->pbm_regs + FIRE_LPU_RESET); 395a88b5ba8SSam Ravnborg upa_writeq(FIRE_LPU_LLCFG_VC0, pbm->pbm_regs + FIRE_LPU_LLCFG); 396a88b5ba8SSam Ravnborg upa_writeq((FIRE_LPU_FCTRL_UCTRL_N | FIRE_LPU_FCTRL_UCTRL_P), 397a88b5ba8SSam Ravnborg pbm->pbm_regs + FIRE_LPU_FCTRL_UCTRL); 398a88b5ba8SSam Ravnborg upa_writeq(((0xffff << 16) | (0x0000 << 0)), 399a88b5ba8SSam Ravnborg pbm->pbm_regs + FIRE_LPU_TXL_FIFOP); 400a88b5ba8SSam Ravnborg upa_writeq(3000000, pbm->pbm_regs + FIRE_LPU_LTSSM_CFG2); 401a88b5ba8SSam Ravnborg upa_writeq(500000, pbm->pbm_regs + FIRE_LPU_LTSSM_CFG3); 402a88b5ba8SSam Ravnborg upa_writeq((2 << 16) | (140 << 8), 403a88b5ba8SSam Ravnborg pbm->pbm_regs + FIRE_LPU_LTSSM_CFG4); 404a88b5ba8SSam Ravnborg upa_writeq(0, pbm->pbm_regs + FIRE_LPU_LTSSM_CFG5); 405a88b5ba8SSam Ravnborg 406a88b5ba8SSam Ravnborg upa_writeq(~(u64)0, pbm->pbm_regs + FIRE_DMC_IENAB); 407a88b5ba8SSam Ravnborg upa_writeq(0, pbm->pbm_regs + FIRE_DMC_DBG_SEL_A); 408a88b5ba8SSam Ravnborg upa_writeq(0, pbm->pbm_regs + FIRE_DMC_DBG_SEL_B); 409a88b5ba8SSam Ravnborg 410a88b5ba8SSam Ravnborg upa_writeq(~(u64)0, pbm->pbm_regs + FIRE_PEC_IENAB); 411a88b5ba8SSam Ravnborg } 412a88b5ba8SSam Ravnborg 4137c9503b8SGreg Kroah-Hartman static int pci_fire_pbm_init(struct pci_pbm_info *pbm, 414cd4cd730SGrant Likely struct platform_device *op, u32 portid) 415a88b5ba8SSam Ravnborg { 416a88b5ba8SSam Ravnborg const struct linux_prom64_registers *regs; 41761c7a080SGrant Likely struct device_node *dp = op->dev.of_node; 418a88b5ba8SSam Ravnborg int err; 419a88b5ba8SSam Ravnborg 420*98fa15f3SAnshuman Khandual pbm->numa_node = NUMA_NO_NODE; 421a88b5ba8SSam Ravnborg 422a88b5ba8SSam Ravnborg pbm->pci_ops = &sun4u_pci_ops; 423a88b5ba8SSam Ravnborg pbm->config_space_reg_bits = 12; 424a88b5ba8SSam Ravnborg 425a88b5ba8SSam Ravnborg pbm->index = pci_num_pbms++; 426a88b5ba8SSam Ravnborg 427a88b5ba8SSam Ravnborg pbm->portid = portid; 428a88b5ba8SSam Ravnborg pbm->op = op; 429a88b5ba8SSam Ravnborg pbm->name = dp->full_name; 430a88b5ba8SSam Ravnborg 431a88b5ba8SSam Ravnborg regs = of_get_property(dp, "reg", NULL); 432a88b5ba8SSam Ravnborg pbm->pbm_regs = regs[0].phys_addr; 433a88b5ba8SSam Ravnborg pbm->controller_regs = regs[1].phys_addr - 0x410000UL; 434a88b5ba8SSam Ravnborg 435a88b5ba8SSam Ravnborg printk("%s: SUN4U PCIE Bus Module\n", pbm->name); 436a88b5ba8SSam Ravnborg 437a88b5ba8SSam Ravnborg pci_determine_mem_io_space(pbm); 438a88b5ba8SSam Ravnborg 439a88b5ba8SSam Ravnborg pci_get_pbm_props(pbm); 440a88b5ba8SSam Ravnborg 441a88b5ba8SSam Ravnborg pci_fire_hw_init(pbm); 442a88b5ba8SSam Ravnborg 443a88b5ba8SSam Ravnborg err = pci_fire_pbm_iommu_init(pbm); 444a88b5ba8SSam Ravnborg if (err) 445a88b5ba8SSam Ravnborg return err; 446a88b5ba8SSam Ravnborg 447a88b5ba8SSam Ravnborg pci_fire_msi_init(pbm); 448a88b5ba8SSam Ravnborg 449a88b5ba8SSam Ravnborg pbm->pci_bus = pci_scan_one_pbm(pbm, &op->dev); 450a88b5ba8SSam Ravnborg 451a88b5ba8SSam Ravnborg /* XXX register error interrupt handlers XXX */ 452a88b5ba8SSam Ravnborg 453a88b5ba8SSam Ravnborg pbm->next = pci_pbm_root; 454a88b5ba8SSam Ravnborg pci_pbm_root = pbm; 455a88b5ba8SSam Ravnborg 456a88b5ba8SSam Ravnborg return 0; 457a88b5ba8SSam Ravnborg } 458a88b5ba8SSam Ravnborg 4597c9503b8SGreg Kroah-Hartman static int fire_probe(struct platform_device *op) 460a88b5ba8SSam Ravnborg { 46161c7a080SGrant Likely struct device_node *dp = op->dev.of_node; 462a88b5ba8SSam Ravnborg struct pci_pbm_info *pbm; 463a88b5ba8SSam Ravnborg struct iommu *iommu; 464a88b5ba8SSam Ravnborg u32 portid; 465a88b5ba8SSam Ravnborg int err; 466a88b5ba8SSam Ravnborg 467a88b5ba8SSam Ravnborg portid = of_getintprop_default(dp, "portid", 0xff); 468a88b5ba8SSam Ravnborg 469a88b5ba8SSam Ravnborg err = -ENOMEM; 470a88b5ba8SSam Ravnborg pbm = kzalloc(sizeof(*pbm), GFP_KERNEL); 471a88b5ba8SSam Ravnborg if (!pbm) { 472a88b5ba8SSam Ravnborg printk(KERN_ERR PFX "Cannot allocate pci_pbminfo.\n"); 473a88b5ba8SSam Ravnborg goto out_err; 474a88b5ba8SSam Ravnborg } 475a88b5ba8SSam Ravnborg 476a88b5ba8SSam Ravnborg iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL); 477a88b5ba8SSam Ravnborg if (!iommu) { 478a88b5ba8SSam Ravnborg printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n"); 479a88b5ba8SSam Ravnborg goto out_free_controller; 480a88b5ba8SSam Ravnborg } 481a88b5ba8SSam Ravnborg 482a88b5ba8SSam Ravnborg pbm->iommu = iommu; 483a88b5ba8SSam Ravnborg 484a88b5ba8SSam Ravnborg err = pci_fire_pbm_init(pbm, op, portid); 485a88b5ba8SSam Ravnborg if (err) 486a88b5ba8SSam Ravnborg goto out_free_iommu; 487a88b5ba8SSam Ravnborg 488a88b5ba8SSam Ravnborg dev_set_drvdata(&op->dev, pbm); 489a88b5ba8SSam Ravnborg 490a88b5ba8SSam Ravnborg return 0; 491a88b5ba8SSam Ravnborg 492a88b5ba8SSam Ravnborg out_free_iommu: 493a88b5ba8SSam Ravnborg kfree(pbm->iommu); 494a88b5ba8SSam Ravnborg 495a88b5ba8SSam Ravnborg out_free_controller: 496a88b5ba8SSam Ravnborg kfree(pbm); 497a88b5ba8SSam Ravnborg 498a88b5ba8SSam Ravnborg out_err: 499a88b5ba8SSam Ravnborg return err; 500a88b5ba8SSam Ravnborg } 501a88b5ba8SSam Ravnborg 5023628aa06SDavid S. Miller static const struct of_device_id fire_match[] = { 503a88b5ba8SSam Ravnborg { 504a88b5ba8SSam Ravnborg .name = "pci", 505a88b5ba8SSam Ravnborg .compatible = "pciex108e,80f0", 506a88b5ba8SSam Ravnborg }, 507a88b5ba8SSam Ravnborg {}, 508a88b5ba8SSam Ravnborg }; 509a88b5ba8SSam Ravnborg 5104ebb24f7SGrant Likely static struct platform_driver fire_driver = { 5114018294bSGrant Likely .driver = { 512a88b5ba8SSam Ravnborg .name = DRIVER_NAME, 5134018294bSGrant Likely .of_match_table = fire_match, 5144018294bSGrant Likely }, 515a88b5ba8SSam Ravnborg .probe = fire_probe, 516a88b5ba8SSam Ravnborg }; 517a88b5ba8SSam Ravnborg 518a88b5ba8SSam Ravnborg static int __init fire_init(void) 519a88b5ba8SSam Ravnborg { 5204ebb24f7SGrant Likely return platform_driver_register(&fire_driver); 521a88b5ba8SSam Ravnborg } 522a88b5ba8SSam Ravnborg 523a88b5ba8SSam Ravnborg subsys_initcall(fire_init); 524