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