1*e47d4889SJohn Crispin /* 2*e47d4889SJohn Crispin * This program is free software; you can redistribute it and/or modify it 3*e47d4889SJohn Crispin * under the terms of the GNU General Public License version 2 as published 4*e47d4889SJohn Crispin * by the Free Software Foundation. 5*e47d4889SJohn Crispin * 6*e47d4889SJohn Crispin * Copyright (C) 2010 John Crispin <blogic@openwrt.org> 7*e47d4889SJohn Crispin */ 8*e47d4889SJohn Crispin 9*e47d4889SJohn Crispin #include <linux/types.h> 10*e47d4889SJohn Crispin #include <linux/pci.h> 11*e47d4889SJohn Crispin #include <linux/kernel.h> 12*e47d4889SJohn Crispin #include <linux/init.h> 13*e47d4889SJohn Crispin #include <linux/delay.h> 14*e47d4889SJohn Crispin #include <linux/mm.h> 15*e47d4889SJohn Crispin #include <asm/addrspace.h> 16*e47d4889SJohn Crispin #include <linux/vmalloc.h> 17*e47d4889SJohn Crispin 18*e47d4889SJohn Crispin #include <lantiq_soc.h> 19*e47d4889SJohn Crispin 20*e47d4889SJohn Crispin #include "pci-lantiq.h" 21*e47d4889SJohn Crispin 22*e47d4889SJohn Crispin #define LTQ_PCI_CFG_BUSNUM_SHF 16 23*e47d4889SJohn Crispin #define LTQ_PCI_CFG_DEVNUM_SHF 11 24*e47d4889SJohn Crispin #define LTQ_PCI_CFG_FUNNUM_SHF 8 25*e47d4889SJohn Crispin 26*e47d4889SJohn Crispin #define PCI_ACCESS_READ 0 27*e47d4889SJohn Crispin #define PCI_ACCESS_WRITE 1 28*e47d4889SJohn Crispin 29*e47d4889SJohn Crispin static int ltq_pci_config_access(unsigned char access_type, struct pci_bus *bus, 30*e47d4889SJohn Crispin unsigned int devfn, unsigned int where, u32 *data) 31*e47d4889SJohn Crispin { 32*e47d4889SJohn Crispin unsigned long cfg_base; 33*e47d4889SJohn Crispin unsigned long flags; 34*e47d4889SJohn Crispin u32 temp; 35*e47d4889SJohn Crispin 36*e47d4889SJohn Crispin /* we support slot from 0 to 15 dev_fn & 0x68 (AD29) is the 37*e47d4889SJohn Crispin SoC itself */ 38*e47d4889SJohn Crispin if ((bus->number != 0) || ((devfn & 0xf8) > 0x78) 39*e47d4889SJohn Crispin || ((devfn & 0xf8) == 0) || ((devfn & 0xf8) == 0x68)) 40*e47d4889SJohn Crispin return 1; 41*e47d4889SJohn Crispin 42*e47d4889SJohn Crispin spin_lock_irqsave(&ebu_lock, flags); 43*e47d4889SJohn Crispin 44*e47d4889SJohn Crispin cfg_base = (unsigned long) ltq_pci_mapped_cfg; 45*e47d4889SJohn Crispin cfg_base |= (bus->number << LTQ_PCI_CFG_BUSNUM_SHF) | (devfn << 46*e47d4889SJohn Crispin LTQ_PCI_CFG_FUNNUM_SHF) | (where & ~0x3); 47*e47d4889SJohn Crispin 48*e47d4889SJohn Crispin /* Perform access */ 49*e47d4889SJohn Crispin if (access_type == PCI_ACCESS_WRITE) { 50*e47d4889SJohn Crispin ltq_w32(swab32(*data), ((u32 *)cfg_base)); 51*e47d4889SJohn Crispin } else { 52*e47d4889SJohn Crispin *data = ltq_r32(((u32 *)(cfg_base))); 53*e47d4889SJohn Crispin *data = swab32(*data); 54*e47d4889SJohn Crispin } 55*e47d4889SJohn Crispin wmb(); 56*e47d4889SJohn Crispin 57*e47d4889SJohn Crispin /* clean possible Master abort */ 58*e47d4889SJohn Crispin cfg_base = (unsigned long) ltq_pci_mapped_cfg; 59*e47d4889SJohn Crispin cfg_base |= (0x0 << LTQ_PCI_CFG_FUNNUM_SHF) + 4; 60*e47d4889SJohn Crispin temp = ltq_r32(((u32 *)(cfg_base))); 61*e47d4889SJohn Crispin temp = swab32(temp); 62*e47d4889SJohn Crispin cfg_base = (unsigned long) ltq_pci_mapped_cfg; 63*e47d4889SJohn Crispin cfg_base |= (0x68 << LTQ_PCI_CFG_FUNNUM_SHF) + 4; 64*e47d4889SJohn Crispin ltq_w32(temp, ((u32 *)cfg_base)); 65*e47d4889SJohn Crispin 66*e47d4889SJohn Crispin spin_unlock_irqrestore(&ebu_lock, flags); 67*e47d4889SJohn Crispin 68*e47d4889SJohn Crispin if (((*data) == 0xffffffff) && (access_type == PCI_ACCESS_READ)) 69*e47d4889SJohn Crispin return 1; 70*e47d4889SJohn Crispin 71*e47d4889SJohn Crispin return 0; 72*e47d4889SJohn Crispin } 73*e47d4889SJohn Crispin 74*e47d4889SJohn Crispin int ltq_pci_read_config_dword(struct pci_bus *bus, unsigned int devfn, 75*e47d4889SJohn Crispin int where, int size, u32 *val) 76*e47d4889SJohn Crispin { 77*e47d4889SJohn Crispin u32 data = 0; 78*e47d4889SJohn Crispin 79*e47d4889SJohn Crispin if (ltq_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) 80*e47d4889SJohn Crispin return PCIBIOS_DEVICE_NOT_FOUND; 81*e47d4889SJohn Crispin 82*e47d4889SJohn Crispin if (size == 1) 83*e47d4889SJohn Crispin *val = (data >> ((where & 3) << 3)) & 0xff; 84*e47d4889SJohn Crispin else if (size == 2) 85*e47d4889SJohn Crispin *val = (data >> ((where & 3) << 3)) & 0xffff; 86*e47d4889SJohn Crispin else 87*e47d4889SJohn Crispin *val = data; 88*e47d4889SJohn Crispin 89*e47d4889SJohn Crispin return PCIBIOS_SUCCESSFUL; 90*e47d4889SJohn Crispin } 91*e47d4889SJohn Crispin 92*e47d4889SJohn Crispin int ltq_pci_write_config_dword(struct pci_bus *bus, unsigned int devfn, 93*e47d4889SJohn Crispin int where, int size, u32 val) 94*e47d4889SJohn Crispin { 95*e47d4889SJohn Crispin u32 data = 0; 96*e47d4889SJohn Crispin 97*e47d4889SJohn Crispin if (size == 4) { 98*e47d4889SJohn Crispin data = val; 99*e47d4889SJohn Crispin } else { 100*e47d4889SJohn Crispin if (ltq_pci_config_access(PCI_ACCESS_READ, bus, 101*e47d4889SJohn Crispin devfn, where, &data)) 102*e47d4889SJohn Crispin return PCIBIOS_DEVICE_NOT_FOUND; 103*e47d4889SJohn Crispin 104*e47d4889SJohn Crispin if (size == 1) 105*e47d4889SJohn Crispin data = (data & ~(0xff << ((where & 3) << 3))) | 106*e47d4889SJohn Crispin (val << ((where & 3) << 3)); 107*e47d4889SJohn Crispin else if (size == 2) 108*e47d4889SJohn Crispin data = (data & ~(0xffff << ((where & 3) << 3))) | 109*e47d4889SJohn Crispin (val << ((where & 3) << 3)); 110*e47d4889SJohn Crispin } 111*e47d4889SJohn Crispin 112*e47d4889SJohn Crispin if (ltq_pci_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) 113*e47d4889SJohn Crispin return PCIBIOS_DEVICE_NOT_FOUND; 114*e47d4889SJohn Crispin 115*e47d4889SJohn Crispin return PCIBIOS_SUCCESSFUL; 116*e47d4889SJohn Crispin } 117