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