18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ops-vr41xx.c, PCI configuration routines for the PCIU of NEC VR4100 series. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2001-2003 MontaVista Software Inc. 68c2ecf20Sopenharmony_ci * Author: Yoichi Yuasa <source@mvista.com> 78c2ecf20Sopenharmony_ci * Copyright (C) 2004-2005 Yoichi Yuasa <yuasa@linux-mips.org> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci/* 108c2ecf20Sopenharmony_ci * Changes: 118c2ecf20Sopenharmony_ci * MontaVista Software Inc. <source@mvista.com> 128c2ecf20Sopenharmony_ci * - New creation, NEC VR4122 and VR4131 are supported. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci#include <linux/pci.h> 158c2ecf20Sopenharmony_ci#include <linux/types.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <asm/io.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define PCICONFDREG (void __iomem *)KSEG1ADDR(0x0f000c14) 208c2ecf20Sopenharmony_ci#define PCICONFAREG (void __iomem *)KSEG1ADDR(0x0f000c18) 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic inline int set_pci_configuration_address(unsigned char number, 238c2ecf20Sopenharmony_ci unsigned int devfn, int where) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci if (number == 0) { 268c2ecf20Sopenharmony_ci /* 278c2ecf20Sopenharmony_ci * Type 0 configuration 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci if (PCI_SLOT(devfn) < 11 || where > 0xff) 308c2ecf20Sopenharmony_ci return -EINVAL; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci writel((1U << PCI_SLOT(devfn)) | (PCI_FUNC(devfn) << 8) | 338c2ecf20Sopenharmony_ci (where & 0xfc), PCICONFAREG); 348c2ecf20Sopenharmony_ci } else { 358c2ecf20Sopenharmony_ci /* 368c2ecf20Sopenharmony_ci * Type 1 configuration 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_ci if (where > 0xff) 398c2ecf20Sopenharmony_ci return -EINVAL; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci writel(((uint32_t)number << 16) | ((devfn & 0xff) << 8) | 428c2ecf20Sopenharmony_ci (where & 0xfc) | 1U, PCICONFAREG); 438c2ecf20Sopenharmony_ci } 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci return 0; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int pci_config_read(struct pci_bus *bus, unsigned int devfn, int where, 498c2ecf20Sopenharmony_ci int size, uint32_t *val) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci uint32_t data; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci *val = 0xffffffffU; 548c2ecf20Sopenharmony_ci if (set_pci_configuration_address(bus->number, devfn, where) < 0) 558c2ecf20Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci data = readl(PCICONFDREG); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci switch (size) { 608c2ecf20Sopenharmony_ci case 1: 618c2ecf20Sopenharmony_ci *val = (data >> ((where & 3) << 3)) & 0xffU; 628c2ecf20Sopenharmony_ci break; 638c2ecf20Sopenharmony_ci case 2: 648c2ecf20Sopenharmony_ci *val = (data >> ((where & 2) << 3)) & 0xffffU; 658c2ecf20Sopenharmony_ci break; 668c2ecf20Sopenharmony_ci case 4: 678c2ecf20Sopenharmony_ci *val = data; 688c2ecf20Sopenharmony_ci break; 698c2ecf20Sopenharmony_ci default: 708c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic int pci_config_write(struct pci_bus *bus, unsigned int devfn, int where, 778c2ecf20Sopenharmony_ci int size, uint32_t val) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci uint32_t data; 808c2ecf20Sopenharmony_ci int shift; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (set_pci_configuration_address(bus->number, devfn, where) < 0) 838c2ecf20Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci data = readl(PCICONFDREG); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci switch (size) { 888c2ecf20Sopenharmony_ci case 1: 898c2ecf20Sopenharmony_ci shift = (where & 3) << 3; 908c2ecf20Sopenharmony_ci data &= ~(0xffU << shift); 918c2ecf20Sopenharmony_ci data |= ((val & 0xffU) << shift); 928c2ecf20Sopenharmony_ci break; 938c2ecf20Sopenharmony_ci case 2: 948c2ecf20Sopenharmony_ci shift = (where & 2) << 3; 958c2ecf20Sopenharmony_ci data &= ~(0xffffU << shift); 968c2ecf20Sopenharmony_ci data |= ((val & 0xffffU) << shift); 978c2ecf20Sopenharmony_ci break; 988c2ecf20Sopenharmony_ci case 4: 998c2ecf20Sopenharmony_ci data = val; 1008c2ecf20Sopenharmony_ci break; 1018c2ecf20Sopenharmony_ci default: 1028c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci writel(data, PCICONFDREG); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistruct pci_ops vr41xx_pci_ops = { 1118c2ecf20Sopenharmony_ci .read = pci_config_read, 1128c2ecf20Sopenharmony_ci .write = pci_config_write, 1138c2ecf20Sopenharmony_ci}; 114