18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Generic SH-4 / SH-4A PCIC operations (SH7751, SH7780). 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2002 - 2009 Paul Mundt 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/pci.h> 88c2ecf20Sopenharmony_ci#include <linux/io.h> 98c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 108c2ecf20Sopenharmony_ci#include <asm/addrspace.h> 118c2ecf20Sopenharmony_ci#include "pci-sh4.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/* 148c2ecf20Sopenharmony_ci * Direct access to PCI hardware... 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci#define CONFIG_CMD(bus, devfn, where) \ 178c2ecf20Sopenharmony_ci (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3)) 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * Functions for accessing PCI configuration space with type 1 accesses 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_cistatic int sh4_pci_read(struct pci_bus *bus, unsigned int devfn, 238c2ecf20Sopenharmony_ci int where, int size, u32 *val) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci struct pci_channel *chan = bus->sysdata; 268c2ecf20Sopenharmony_ci unsigned long flags; 278c2ecf20Sopenharmony_ci u32 data; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci /* 308c2ecf20Sopenharmony_ci * PCIPDR may only be accessed as 32 bit words, 318c2ecf20Sopenharmony_ci * so we must do byte alignment by hand 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&pci_config_lock, flags); 348c2ecf20Sopenharmony_ci pci_write_reg(chan, CONFIG_CMD(bus, devfn, where), SH4_PCIPAR); 358c2ecf20Sopenharmony_ci data = pci_read_reg(chan, SH4_PCIPDR); 368c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&pci_config_lock, flags); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci switch (size) { 398c2ecf20Sopenharmony_ci case 1: 408c2ecf20Sopenharmony_ci *val = (data >> ((where & 3) << 3)) & 0xff; 418c2ecf20Sopenharmony_ci break; 428c2ecf20Sopenharmony_ci case 2: 438c2ecf20Sopenharmony_ci *val = (data >> ((where & 2) << 3)) & 0xffff; 448c2ecf20Sopenharmony_ci break; 458c2ecf20Sopenharmony_ci case 4: 468c2ecf20Sopenharmony_ci *val = data; 478c2ecf20Sopenharmony_ci break; 488c2ecf20Sopenharmony_ci default: 498c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* 568c2ecf20Sopenharmony_ci * Since SH4 only does 32bit access we'll have to do a read, 578c2ecf20Sopenharmony_ci * mask,write operation. 588c2ecf20Sopenharmony_ci * We'll allow an odd byte offset, though it should be illegal. 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_cistatic int sh4_pci_write(struct pci_bus *bus, unsigned int devfn, 618c2ecf20Sopenharmony_ci int where, int size, u32 val) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci struct pci_channel *chan = bus->sysdata; 648c2ecf20Sopenharmony_ci unsigned long flags; 658c2ecf20Sopenharmony_ci int shift; 668c2ecf20Sopenharmony_ci u32 data; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&pci_config_lock, flags); 698c2ecf20Sopenharmony_ci pci_write_reg(chan, CONFIG_CMD(bus, devfn, where), SH4_PCIPAR); 708c2ecf20Sopenharmony_ci data = pci_read_reg(chan, SH4_PCIPDR); 718c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&pci_config_lock, flags); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci switch (size) { 748c2ecf20Sopenharmony_ci case 1: 758c2ecf20Sopenharmony_ci shift = (where & 3) << 3; 768c2ecf20Sopenharmony_ci data &= ~(0xff << shift); 778c2ecf20Sopenharmony_ci data |= ((val & 0xff) << shift); 788c2ecf20Sopenharmony_ci break; 798c2ecf20Sopenharmony_ci case 2: 808c2ecf20Sopenharmony_ci shift = (where & 2) << 3; 818c2ecf20Sopenharmony_ci data &= ~(0xffff << shift); 828c2ecf20Sopenharmony_ci data |= ((val & 0xffff) << shift); 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci case 4: 858c2ecf20Sopenharmony_ci data = val; 868c2ecf20Sopenharmony_ci break; 878c2ecf20Sopenharmony_ci default: 888c2ecf20Sopenharmony_ci return PCIBIOS_FUNC_NOT_SUPPORTED; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci pci_write_reg(chan, data, SH4_PCIPDR); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistruct pci_ops sh4_pci_ops = { 978c2ecf20Sopenharmony_ci .read = sh4_pci_read, 988c2ecf20Sopenharmony_ci .write = sh4_pci_write, 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ciint __attribute__((weak)) pci_fixup_pcic(struct pci_channel *chan) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci /* Nothing to do. */ 1048c2ecf20Sopenharmony_ci return 0; 1058c2ecf20Sopenharmony_ci} 106