18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Define the pci_ops for the PCIC on Toshiba TX4927, TX4938, etc.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Based on linux/arch/mips/pci/ops-tx4938.c,
68c2ecf20Sopenharmony_ci *	    linux/arch/mips/pci/fixup-rbtx4938.c,
78c2ecf20Sopenharmony_ci *	    linux/arch/mips/txx9/rbtx4938/setup.c,
88c2ecf20Sopenharmony_ci *	    and RBTX49xx patch from CELF patch archive.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * 2003-2005 (c) MontaVista Software, Inc.
118c2ecf20Sopenharmony_ci * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
128c2ecf20Sopenharmony_ci * (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-2007
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
168c2ecf20Sopenharmony_ci#include <linux/irq.h>
178c2ecf20Sopenharmony_ci#include <asm/txx9/pci.h>
188c2ecf20Sopenharmony_ci#include <asm/txx9/tx4927pcic.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic struct {
218c2ecf20Sopenharmony_ci	struct pci_controller *channel;
228c2ecf20Sopenharmony_ci	struct tx4927_pcic_reg __iomem *pcicptr;
238c2ecf20Sopenharmony_ci} pcicptrs[2];	/* TX4938 has 2 pcic */
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic void __init set_tx4927_pcicptr(struct pci_controller *channel,
268c2ecf20Sopenharmony_ci				      struct tx4927_pcic_reg __iomem *pcicptr)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	int i;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pcicptrs); i++) {
318c2ecf20Sopenharmony_ci		if (pcicptrs[i].channel == channel) {
328c2ecf20Sopenharmony_ci			pcicptrs[i].pcicptr = pcicptr;
338c2ecf20Sopenharmony_ci			return;
348c2ecf20Sopenharmony_ci		}
358c2ecf20Sopenharmony_ci	}
368c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pcicptrs); i++) {
378c2ecf20Sopenharmony_ci		if (!pcicptrs[i].channel) {
388c2ecf20Sopenharmony_ci			pcicptrs[i].channel = channel;
398c2ecf20Sopenharmony_ci			pcicptrs[i].pcicptr = pcicptr;
408c2ecf20Sopenharmony_ci			return;
418c2ecf20Sopenharmony_ci		}
428c2ecf20Sopenharmony_ci	}
438c2ecf20Sopenharmony_ci	BUG();
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistruct tx4927_pcic_reg __iomem *get_tx4927_pcicptr(
478c2ecf20Sopenharmony_ci	struct pci_controller *channel)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	int i;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pcicptrs); i++) {
528c2ecf20Sopenharmony_ci		if (pcicptrs[i].channel == channel)
538c2ecf20Sopenharmony_ci			return pcicptrs[i].pcicptr;
548c2ecf20Sopenharmony_ci	}
558c2ecf20Sopenharmony_ci	return NULL;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic int mkaddr(struct pci_bus *bus, unsigned int devfn, int where,
598c2ecf20Sopenharmony_ci		  struct tx4927_pcic_reg __iomem *pcicptr)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	if (bus->parent == NULL &&
628c2ecf20Sopenharmony_ci	    devfn >= PCI_DEVFN(TX4927_PCIC_MAX_DEVNU, 0))
638c2ecf20Sopenharmony_ci		return -1;
648c2ecf20Sopenharmony_ci	__raw_writel(((bus->number & 0xff) << 0x10)
658c2ecf20Sopenharmony_ci		     | ((devfn & 0xff) << 0x08) | (where & 0xfc)
668c2ecf20Sopenharmony_ci		     | (bus->parent ? 1 : 0),
678c2ecf20Sopenharmony_ci		     &pcicptr->g2pcfgadrs);
688c2ecf20Sopenharmony_ci	/* clear M_ABORT and Disable M_ABORT Int. */
698c2ecf20Sopenharmony_ci	__raw_writel((__raw_readl(&pcicptr->pcistatus) & 0x0000ffff)
708c2ecf20Sopenharmony_ci		     | (PCI_STATUS_REC_MASTER_ABORT << 16),
718c2ecf20Sopenharmony_ci		     &pcicptr->pcistatus);
728c2ecf20Sopenharmony_ci	return 0;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic int check_abort(struct tx4927_pcic_reg __iomem *pcicptr)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	int code = PCIBIOS_SUCCESSFUL;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	/* wait write cycle completion before checking error status */
808c2ecf20Sopenharmony_ci	while (__raw_readl(&pcicptr->pcicstatus) & TX4927_PCIC_PCICSTATUS_IWB)
818c2ecf20Sopenharmony_ci		;
828c2ecf20Sopenharmony_ci	if (__raw_readl(&pcicptr->pcistatus)
838c2ecf20Sopenharmony_ci	    & (PCI_STATUS_REC_MASTER_ABORT << 16)) {
848c2ecf20Sopenharmony_ci		__raw_writel((__raw_readl(&pcicptr->pcistatus) & 0x0000ffff)
858c2ecf20Sopenharmony_ci			     | (PCI_STATUS_REC_MASTER_ABORT << 16),
868c2ecf20Sopenharmony_ci			     &pcicptr->pcistatus);
878c2ecf20Sopenharmony_ci		/* flush write buffer */
888c2ecf20Sopenharmony_ci		iob();
898c2ecf20Sopenharmony_ci		code = PCIBIOS_DEVICE_NOT_FOUND;
908c2ecf20Sopenharmony_ci	}
918c2ecf20Sopenharmony_ci	return code;
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic u8 icd_readb(int offset, struct tx4927_pcic_reg __iomem *pcicptr)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
978c2ecf20Sopenharmony_ci	offset ^= 3;
988c2ecf20Sopenharmony_ci#endif
998c2ecf20Sopenharmony_ci	return __raw_readb((void __iomem *)&pcicptr->g2pcfgdata + offset);
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_cistatic u16 icd_readw(int offset, struct tx4927_pcic_reg __iomem *pcicptr)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
1048c2ecf20Sopenharmony_ci	offset ^= 2;
1058c2ecf20Sopenharmony_ci#endif
1068c2ecf20Sopenharmony_ci	return __raw_readw((void __iomem *)&pcicptr->g2pcfgdata + offset);
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_cistatic u32 icd_readl(struct tx4927_pcic_reg __iomem *pcicptr)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	return __raw_readl(&pcicptr->g2pcfgdata);
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_cistatic void icd_writeb(u8 val, int offset,
1138c2ecf20Sopenharmony_ci		       struct tx4927_pcic_reg __iomem *pcicptr)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
1168c2ecf20Sopenharmony_ci	offset ^= 3;
1178c2ecf20Sopenharmony_ci#endif
1188c2ecf20Sopenharmony_ci	__raw_writeb(val, (void __iomem *)&pcicptr->g2pcfgdata + offset);
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_cistatic void icd_writew(u16 val, int offset,
1218c2ecf20Sopenharmony_ci		       struct tx4927_pcic_reg __iomem *pcicptr)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
1248c2ecf20Sopenharmony_ci	offset ^= 2;
1258c2ecf20Sopenharmony_ci#endif
1268c2ecf20Sopenharmony_ci	__raw_writew(val, (void __iomem *)&pcicptr->g2pcfgdata + offset);
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_cistatic void icd_writel(u32 val, struct tx4927_pcic_reg __iomem *pcicptr)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	__raw_writel(val, &pcicptr->g2pcfgdata);
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic struct tx4927_pcic_reg __iomem *pci_bus_to_pcicptr(struct pci_bus *bus)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	struct pci_controller *channel = bus->sysdata;
1368c2ecf20Sopenharmony_ci	return get_tx4927_pcicptr(channel);
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic int tx4927_pci_config_read(struct pci_bus *bus, unsigned int devfn,
1408c2ecf20Sopenharmony_ci				  int where, int size, u32 *val)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	struct tx4927_pcic_reg __iomem *pcicptr = pci_bus_to_pcicptr(bus);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	if (mkaddr(bus, devfn, where, pcicptr)) {
1458c2ecf20Sopenharmony_ci		*val = 0xffffffff;
1468c2ecf20Sopenharmony_ci		return -1;
1478c2ecf20Sopenharmony_ci	}
1488c2ecf20Sopenharmony_ci	switch (size) {
1498c2ecf20Sopenharmony_ci	case 1:
1508c2ecf20Sopenharmony_ci		*val = icd_readb(where & 3, pcicptr);
1518c2ecf20Sopenharmony_ci		break;
1528c2ecf20Sopenharmony_ci	case 2:
1538c2ecf20Sopenharmony_ci		*val = icd_readw(where & 3, pcicptr);
1548c2ecf20Sopenharmony_ci		break;
1558c2ecf20Sopenharmony_ci	default:
1568c2ecf20Sopenharmony_ci		*val = icd_readl(pcicptr);
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci	return check_abort(pcicptr);
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic int tx4927_pci_config_write(struct pci_bus *bus, unsigned int devfn,
1628c2ecf20Sopenharmony_ci				   int where, int size, u32 val)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	struct tx4927_pcic_reg __iomem *pcicptr = pci_bus_to_pcicptr(bus);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	if (mkaddr(bus, devfn, where, pcicptr))
1678c2ecf20Sopenharmony_ci		return -1;
1688c2ecf20Sopenharmony_ci	switch (size) {
1698c2ecf20Sopenharmony_ci	case 1:
1708c2ecf20Sopenharmony_ci		icd_writeb(val, where & 3, pcicptr);
1718c2ecf20Sopenharmony_ci		break;
1728c2ecf20Sopenharmony_ci	case 2:
1738c2ecf20Sopenharmony_ci		icd_writew(val, where & 3, pcicptr);
1748c2ecf20Sopenharmony_ci		break;
1758c2ecf20Sopenharmony_ci	default:
1768c2ecf20Sopenharmony_ci		icd_writel(val, pcicptr);
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci	return check_abort(pcicptr);
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic struct pci_ops tx4927_pci_ops = {
1828c2ecf20Sopenharmony_ci	.read = tx4927_pci_config_read,
1838c2ecf20Sopenharmony_ci	.write = tx4927_pci_config_write,
1848c2ecf20Sopenharmony_ci};
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic struct {
1878c2ecf20Sopenharmony_ci	u8 trdyto;
1888c2ecf20Sopenharmony_ci	u8 retryto;
1898c2ecf20Sopenharmony_ci	u16 gbwc;
1908c2ecf20Sopenharmony_ci} tx4927_pci_opts = {
1918c2ecf20Sopenharmony_ci	.trdyto = 0,
1928c2ecf20Sopenharmony_ci	.retryto = 0,
1938c2ecf20Sopenharmony_ci	.gbwc = 0xfe0,	/* 4064 GBUSCLK for CCFG.GTOT=0b11 */
1948c2ecf20Sopenharmony_ci};
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cichar *tx4927_pcibios_setup(char *str)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	if (!strncmp(str, "trdyto=", 7)) {
1998c2ecf20Sopenharmony_ci		u8 val = 0;
2008c2ecf20Sopenharmony_ci		if (kstrtou8(str + 7, 0, &val) == 0)
2018c2ecf20Sopenharmony_ci			tx4927_pci_opts.trdyto = val;
2028c2ecf20Sopenharmony_ci		return NULL;
2038c2ecf20Sopenharmony_ci	}
2048c2ecf20Sopenharmony_ci	if (!strncmp(str, "retryto=", 8)) {
2058c2ecf20Sopenharmony_ci		u8 val = 0;
2068c2ecf20Sopenharmony_ci		if (kstrtou8(str + 8, 0, &val) == 0)
2078c2ecf20Sopenharmony_ci			tx4927_pci_opts.retryto = val;
2088c2ecf20Sopenharmony_ci		return NULL;
2098c2ecf20Sopenharmony_ci	}
2108c2ecf20Sopenharmony_ci	if (!strncmp(str, "gbwc=", 5)) {
2118c2ecf20Sopenharmony_ci		u16 val;
2128c2ecf20Sopenharmony_ci		if (kstrtou16(str + 5, 0, &val) == 0)
2138c2ecf20Sopenharmony_ci			tx4927_pci_opts.gbwc = val;
2148c2ecf20Sopenharmony_ci		return NULL;
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci	return str;
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_civoid __init tx4927_pcic_setup(struct tx4927_pcic_reg __iomem *pcicptr,
2208c2ecf20Sopenharmony_ci			      struct pci_controller *channel, int extarb)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	int i;
2238c2ecf20Sopenharmony_ci	unsigned long flags;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	set_tx4927_pcicptr(channel, pcicptr);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	if (!channel->pci_ops)
2288c2ecf20Sopenharmony_ci		printk(KERN_INFO
2298c2ecf20Sopenharmony_ci		       "PCIC -- DID:%04x VID:%04x RID:%02x Arbiter:%s\n",
2308c2ecf20Sopenharmony_ci		       __raw_readl(&pcicptr->pciid) >> 16,
2318c2ecf20Sopenharmony_ci		       __raw_readl(&pcicptr->pciid) & 0xffff,
2328c2ecf20Sopenharmony_ci		       __raw_readl(&pcicptr->pciccrev) & 0xff,
2338c2ecf20Sopenharmony_ci			extarb ? "External" : "Internal");
2348c2ecf20Sopenharmony_ci	channel->pci_ops = &tx4927_pci_ops;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	local_irq_save(flags);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	/* Disable All Initiator Space */
2398c2ecf20Sopenharmony_ci	__raw_writel(__raw_readl(&pcicptr->pciccfg)
2408c2ecf20Sopenharmony_ci		     & ~(TX4927_PCIC_PCICCFG_G2PMEN(0)
2418c2ecf20Sopenharmony_ci			 | TX4927_PCIC_PCICCFG_G2PMEN(1)
2428c2ecf20Sopenharmony_ci			 | TX4927_PCIC_PCICCFG_G2PMEN(2)
2438c2ecf20Sopenharmony_ci			 | TX4927_PCIC_PCICCFG_G2PIOEN),
2448c2ecf20Sopenharmony_ci		     &pcicptr->pciccfg);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	/* GB->PCI mappings */
2478c2ecf20Sopenharmony_ci	__raw_writel((channel->io_resource->end - channel->io_resource->start)
2488c2ecf20Sopenharmony_ci		     >> 4,
2498c2ecf20Sopenharmony_ci		     &pcicptr->g2piomask);
2508c2ecf20Sopenharmony_ci	____raw_writeq((channel->io_resource->start +
2518c2ecf20Sopenharmony_ci			channel->io_map_base - IO_BASE) |
2528c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
2538c2ecf20Sopenharmony_ci		       TX4927_PCIC_G2PIOGBASE_ECHG
2548c2ecf20Sopenharmony_ci#else
2558c2ecf20Sopenharmony_ci		       TX4927_PCIC_G2PIOGBASE_BSDIS
2568c2ecf20Sopenharmony_ci#endif
2578c2ecf20Sopenharmony_ci		       , &pcicptr->g2piogbase);
2588c2ecf20Sopenharmony_ci	____raw_writeq(channel->io_resource->start - channel->io_offset,
2598c2ecf20Sopenharmony_ci		       &pcicptr->g2piopbase);
2608c2ecf20Sopenharmony_ci	for (i = 0; i < 3; i++) {
2618c2ecf20Sopenharmony_ci		__raw_writel(0, &pcicptr->g2pmmask[i]);
2628c2ecf20Sopenharmony_ci		____raw_writeq(0, &pcicptr->g2pmgbase[i]);
2638c2ecf20Sopenharmony_ci		____raw_writeq(0, &pcicptr->g2pmpbase[i]);
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci	if (channel->mem_resource->end) {
2668c2ecf20Sopenharmony_ci		__raw_writel((channel->mem_resource->end
2678c2ecf20Sopenharmony_ci			      - channel->mem_resource->start) >> 4,
2688c2ecf20Sopenharmony_ci			     &pcicptr->g2pmmask[0]);
2698c2ecf20Sopenharmony_ci		____raw_writeq(channel->mem_resource->start |
2708c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
2718c2ecf20Sopenharmony_ci			       TX4927_PCIC_G2PMnGBASE_ECHG
2728c2ecf20Sopenharmony_ci#else
2738c2ecf20Sopenharmony_ci			       TX4927_PCIC_G2PMnGBASE_BSDIS
2748c2ecf20Sopenharmony_ci#endif
2758c2ecf20Sopenharmony_ci			       , &pcicptr->g2pmgbase[0]);
2768c2ecf20Sopenharmony_ci		____raw_writeq(channel->mem_resource->start -
2778c2ecf20Sopenharmony_ci			       channel->mem_offset,
2788c2ecf20Sopenharmony_ci			       &pcicptr->g2pmpbase[0]);
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci	/* PCI->GB mappings (I/O 256B) */
2818c2ecf20Sopenharmony_ci	__raw_writel(0, &pcicptr->p2giopbase); /* 256B */
2828c2ecf20Sopenharmony_ci	____raw_writeq(0, &pcicptr->p2giogbase);
2838c2ecf20Sopenharmony_ci	/* PCI->GB mappings (MEM 512MB (64MB on R1.x)) */
2848c2ecf20Sopenharmony_ci	__raw_writel(0, &pcicptr->p2gm0plbase);
2858c2ecf20Sopenharmony_ci	__raw_writel(0, &pcicptr->p2gm0pubase);
2868c2ecf20Sopenharmony_ci	____raw_writeq(TX4927_PCIC_P2GMnGBASE_TMEMEN |
2878c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
2888c2ecf20Sopenharmony_ci		       TX4927_PCIC_P2GMnGBASE_TECHG
2898c2ecf20Sopenharmony_ci#else
2908c2ecf20Sopenharmony_ci		       TX4927_PCIC_P2GMnGBASE_TBSDIS
2918c2ecf20Sopenharmony_ci#endif
2928c2ecf20Sopenharmony_ci		       , &pcicptr->p2gmgbase[0]);
2938c2ecf20Sopenharmony_ci	/* PCI->GB mappings (MEM 16MB) */
2948c2ecf20Sopenharmony_ci	__raw_writel(0xffffffff, &pcicptr->p2gm1plbase);
2958c2ecf20Sopenharmony_ci	__raw_writel(0xffffffff, &pcicptr->p2gm1pubase);
2968c2ecf20Sopenharmony_ci	____raw_writeq(0, &pcicptr->p2gmgbase[1]);
2978c2ecf20Sopenharmony_ci	/* PCI->GB mappings (MEM 1MB) */
2988c2ecf20Sopenharmony_ci	__raw_writel(0xffffffff, &pcicptr->p2gm2pbase); /* 1MB */
2998c2ecf20Sopenharmony_ci	____raw_writeq(0, &pcicptr->p2gmgbase[2]);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	/* Clear all (including IRBER) except for GBWC */
3028c2ecf20Sopenharmony_ci	__raw_writel((tx4927_pci_opts.gbwc << 16)
3038c2ecf20Sopenharmony_ci		     & TX4927_PCIC_PCICCFG_GBWC_MASK,
3048c2ecf20Sopenharmony_ci		     &pcicptr->pciccfg);
3058c2ecf20Sopenharmony_ci	/* Enable Initiator Memory Space */
3068c2ecf20Sopenharmony_ci	if (channel->mem_resource->end)
3078c2ecf20Sopenharmony_ci		__raw_writel(__raw_readl(&pcicptr->pciccfg)
3088c2ecf20Sopenharmony_ci			     | TX4927_PCIC_PCICCFG_G2PMEN(0),
3098c2ecf20Sopenharmony_ci			     &pcicptr->pciccfg);
3108c2ecf20Sopenharmony_ci	/* Enable Initiator I/O Space */
3118c2ecf20Sopenharmony_ci	if (channel->io_resource->end)
3128c2ecf20Sopenharmony_ci		__raw_writel(__raw_readl(&pcicptr->pciccfg)
3138c2ecf20Sopenharmony_ci			     | TX4927_PCIC_PCICCFG_G2PIOEN,
3148c2ecf20Sopenharmony_ci			     &pcicptr->pciccfg);
3158c2ecf20Sopenharmony_ci	/* Enable Initiator Config */
3168c2ecf20Sopenharmony_ci	__raw_writel(__raw_readl(&pcicptr->pciccfg)
3178c2ecf20Sopenharmony_ci		     | TX4927_PCIC_PCICCFG_ICAEN | TX4927_PCIC_PCICCFG_TCAR,
3188c2ecf20Sopenharmony_ci		     &pcicptr->pciccfg);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	/* Do not use MEMMUL, MEMINF: YMFPCI card causes M_ABORT. */
3218c2ecf20Sopenharmony_ci	__raw_writel(0, &pcicptr->pcicfg1);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	__raw_writel((__raw_readl(&pcicptr->g2ptocnt) & ~0xffff)
3248c2ecf20Sopenharmony_ci		     | (tx4927_pci_opts.trdyto & 0xff)
3258c2ecf20Sopenharmony_ci		     | ((tx4927_pci_opts.retryto & 0xff) << 8),
3268c2ecf20Sopenharmony_ci		     &pcicptr->g2ptocnt);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	/* Clear All Local Bus Status */
3298c2ecf20Sopenharmony_ci	__raw_writel(TX4927_PCIC_PCICSTATUS_ALL, &pcicptr->pcicstatus);
3308c2ecf20Sopenharmony_ci	/* Enable All Local Bus Interrupts */
3318c2ecf20Sopenharmony_ci	__raw_writel(TX4927_PCIC_PCICSTATUS_ALL, &pcicptr->pcicmask);
3328c2ecf20Sopenharmony_ci	/* Clear All Initiator Status */
3338c2ecf20Sopenharmony_ci	__raw_writel(TX4927_PCIC_G2PSTATUS_ALL, &pcicptr->g2pstatus);
3348c2ecf20Sopenharmony_ci	/* Enable All Initiator Interrupts */
3358c2ecf20Sopenharmony_ci	__raw_writel(TX4927_PCIC_G2PSTATUS_ALL, &pcicptr->g2pmask);
3368c2ecf20Sopenharmony_ci	/* Clear All PCI Status Error */
3378c2ecf20Sopenharmony_ci	__raw_writel((__raw_readl(&pcicptr->pcistatus) & 0x0000ffff)
3388c2ecf20Sopenharmony_ci		     | (TX4927_PCIC_PCISTATUS_ALL << 16),
3398c2ecf20Sopenharmony_ci		     &pcicptr->pcistatus);
3408c2ecf20Sopenharmony_ci	/* Enable All PCI Status Error Interrupts */
3418c2ecf20Sopenharmony_ci	__raw_writel(TX4927_PCIC_PCISTATUS_ALL, &pcicptr->pcimask);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	if (!extarb) {
3448c2ecf20Sopenharmony_ci		/* Reset Bus Arbiter */
3458c2ecf20Sopenharmony_ci		__raw_writel(TX4927_PCIC_PBACFG_RPBA, &pcicptr->pbacfg);
3468c2ecf20Sopenharmony_ci		__raw_writel(0, &pcicptr->pbabm);
3478c2ecf20Sopenharmony_ci		/* Enable Bus Arbiter */
3488c2ecf20Sopenharmony_ci		__raw_writel(TX4927_PCIC_PBACFG_PBAEN, &pcicptr->pbacfg);
3498c2ecf20Sopenharmony_ci	}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	__raw_writel(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY
3528c2ecf20Sopenharmony_ci		     | PCI_COMMAND_PARITY | PCI_COMMAND_SERR,
3538c2ecf20Sopenharmony_ci		     &pcicptr->pcistatus);
3548c2ecf20Sopenharmony_ci	local_irq_restore(flags);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	printk(KERN_DEBUG
3578c2ecf20Sopenharmony_ci	       "PCI: COMMAND=%04x,PCIMASK=%04x,"
3588c2ecf20Sopenharmony_ci	       "TRDYTO=%02x,RETRYTO=%02x,GBWC=%03x\n",
3598c2ecf20Sopenharmony_ci	       __raw_readl(&pcicptr->pcistatus) & 0xffff,
3608c2ecf20Sopenharmony_ci	       __raw_readl(&pcicptr->pcimask) & 0xffff,
3618c2ecf20Sopenharmony_ci	       __raw_readl(&pcicptr->g2ptocnt) & 0xff,
3628c2ecf20Sopenharmony_ci	       (__raw_readl(&pcicptr->g2ptocnt) & 0xff00) >> 8,
3638c2ecf20Sopenharmony_ci	       (__raw_readl(&pcicptr->pciccfg) >> 16) & 0xfff);
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cistatic void tx4927_report_pcic_status1(struct tx4927_pcic_reg __iomem *pcicptr)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	__u16 pcistatus = (__u16)(__raw_readl(&pcicptr->pcistatus) >> 16);
3698c2ecf20Sopenharmony_ci	__u32 g2pstatus = __raw_readl(&pcicptr->g2pstatus);
3708c2ecf20Sopenharmony_ci	__u32 pcicstatus = __raw_readl(&pcicptr->pcicstatus);
3718c2ecf20Sopenharmony_ci	static struct {
3728c2ecf20Sopenharmony_ci		__u32 flag;
3738c2ecf20Sopenharmony_ci		const char *str;
3748c2ecf20Sopenharmony_ci	} pcistat_tbl[] = {
3758c2ecf20Sopenharmony_ci		{ PCI_STATUS_DETECTED_PARITY,	"DetectedParityError" },
3768c2ecf20Sopenharmony_ci		{ PCI_STATUS_SIG_SYSTEM_ERROR,	"SignaledSystemError" },
3778c2ecf20Sopenharmony_ci		{ PCI_STATUS_REC_MASTER_ABORT,	"ReceivedMasterAbort" },
3788c2ecf20Sopenharmony_ci		{ PCI_STATUS_REC_TARGET_ABORT,	"ReceivedTargetAbort" },
3798c2ecf20Sopenharmony_ci		{ PCI_STATUS_SIG_TARGET_ABORT,	"SignaledTargetAbort" },
3808c2ecf20Sopenharmony_ci		{ PCI_STATUS_PARITY,	"MasterParityError" },
3818c2ecf20Sopenharmony_ci	}, g2pstat_tbl[] = {
3828c2ecf20Sopenharmony_ci		{ TX4927_PCIC_G2PSTATUS_TTOE,	"TIOE" },
3838c2ecf20Sopenharmony_ci		{ TX4927_PCIC_G2PSTATUS_RTOE,	"RTOE" },
3848c2ecf20Sopenharmony_ci	}, pcicstat_tbl[] = {
3858c2ecf20Sopenharmony_ci		{ TX4927_PCIC_PCICSTATUS_PME,	"PME" },
3868c2ecf20Sopenharmony_ci		{ TX4927_PCIC_PCICSTATUS_TLB,	"TLB" },
3878c2ecf20Sopenharmony_ci		{ TX4927_PCIC_PCICSTATUS_NIB,	"NIB" },
3888c2ecf20Sopenharmony_ci		{ TX4927_PCIC_PCICSTATUS_ZIB,	"ZIB" },
3898c2ecf20Sopenharmony_ci		{ TX4927_PCIC_PCICSTATUS_PERR,	"PERR" },
3908c2ecf20Sopenharmony_ci		{ TX4927_PCIC_PCICSTATUS_SERR,	"SERR" },
3918c2ecf20Sopenharmony_ci		{ TX4927_PCIC_PCICSTATUS_GBE,	"GBE" },
3928c2ecf20Sopenharmony_ci		{ TX4927_PCIC_PCICSTATUS_IWB,	"IWB" },
3938c2ecf20Sopenharmony_ci	};
3948c2ecf20Sopenharmony_ci	int i, cont;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	printk(KERN_ERR "");
3978c2ecf20Sopenharmony_ci	if (pcistatus & TX4927_PCIC_PCISTATUS_ALL) {
3988c2ecf20Sopenharmony_ci		printk(KERN_CONT "pcistat:%04x(", pcistatus);
3998c2ecf20Sopenharmony_ci		for (i = 0, cont = 0; i < ARRAY_SIZE(pcistat_tbl); i++)
4008c2ecf20Sopenharmony_ci			if (pcistatus & pcistat_tbl[i].flag)
4018c2ecf20Sopenharmony_ci				printk(KERN_CONT "%s%s",
4028c2ecf20Sopenharmony_ci				       cont++ ? " " : "", pcistat_tbl[i].str);
4038c2ecf20Sopenharmony_ci		printk(KERN_CONT ") ");
4048c2ecf20Sopenharmony_ci	}
4058c2ecf20Sopenharmony_ci	if (g2pstatus & TX4927_PCIC_G2PSTATUS_ALL) {
4068c2ecf20Sopenharmony_ci		printk(KERN_CONT "g2pstatus:%08x(", g2pstatus);
4078c2ecf20Sopenharmony_ci		for (i = 0, cont = 0; i < ARRAY_SIZE(g2pstat_tbl); i++)
4088c2ecf20Sopenharmony_ci			if (g2pstatus & g2pstat_tbl[i].flag)
4098c2ecf20Sopenharmony_ci				printk(KERN_CONT "%s%s",
4108c2ecf20Sopenharmony_ci				       cont++ ? " " : "", g2pstat_tbl[i].str);
4118c2ecf20Sopenharmony_ci		printk(KERN_CONT ") ");
4128c2ecf20Sopenharmony_ci	}
4138c2ecf20Sopenharmony_ci	if (pcicstatus & TX4927_PCIC_PCICSTATUS_ALL) {
4148c2ecf20Sopenharmony_ci		printk(KERN_CONT "pcicstatus:%08x(", pcicstatus);
4158c2ecf20Sopenharmony_ci		for (i = 0, cont = 0; i < ARRAY_SIZE(pcicstat_tbl); i++)
4168c2ecf20Sopenharmony_ci			if (pcicstatus & pcicstat_tbl[i].flag)
4178c2ecf20Sopenharmony_ci				printk(KERN_CONT "%s%s",
4188c2ecf20Sopenharmony_ci				       cont++ ? " " : "", pcicstat_tbl[i].str);
4198c2ecf20Sopenharmony_ci		printk(KERN_CONT ")");
4208c2ecf20Sopenharmony_ci	}
4218c2ecf20Sopenharmony_ci	printk(KERN_CONT "\n");
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_civoid tx4927_report_pcic_status(void)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	int i;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pcicptrs); i++) {
4298c2ecf20Sopenharmony_ci		if (pcicptrs[i].pcicptr)
4308c2ecf20Sopenharmony_ci			tx4927_report_pcic_status1(pcicptrs[i].pcicptr);
4318c2ecf20Sopenharmony_ci	}
4328c2ecf20Sopenharmony_ci}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_cistatic void tx4927_dump_pcic_settings1(struct tx4927_pcic_reg __iomem *pcicptr)
4358c2ecf20Sopenharmony_ci{
4368c2ecf20Sopenharmony_ci	int i;
4378c2ecf20Sopenharmony_ci	__u32 __iomem *preg = (__u32 __iomem *)pcicptr;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	printk(KERN_INFO "tx4927 pcic (0x%p) settings:", pcicptr);
4408c2ecf20Sopenharmony_ci	for (i = 0; i < sizeof(struct tx4927_pcic_reg); i += 4, preg++) {
4418c2ecf20Sopenharmony_ci		if (i % 32 == 0) {
4428c2ecf20Sopenharmony_ci			printk(KERN_CONT "\n");
4438c2ecf20Sopenharmony_ci			printk(KERN_INFO "%04x:", i);
4448c2ecf20Sopenharmony_ci		}
4458c2ecf20Sopenharmony_ci		/* skip registers with side-effects */
4468c2ecf20Sopenharmony_ci		if (i == offsetof(struct tx4927_pcic_reg, g2pintack)
4478c2ecf20Sopenharmony_ci		    || i == offsetof(struct tx4927_pcic_reg, g2pspc)
4488c2ecf20Sopenharmony_ci		    || i == offsetof(struct tx4927_pcic_reg, g2pcfgadrs)
4498c2ecf20Sopenharmony_ci		    || i == offsetof(struct tx4927_pcic_reg, g2pcfgdata)) {
4508c2ecf20Sopenharmony_ci			printk(KERN_CONT " XXXXXXXX");
4518c2ecf20Sopenharmony_ci			continue;
4528c2ecf20Sopenharmony_ci		}
4538c2ecf20Sopenharmony_ci		printk(KERN_CONT " %08x", __raw_readl(preg));
4548c2ecf20Sopenharmony_ci	}
4558c2ecf20Sopenharmony_ci	printk(KERN_CONT "\n");
4568c2ecf20Sopenharmony_ci}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_civoid tx4927_dump_pcic_settings(void)
4598c2ecf20Sopenharmony_ci{
4608c2ecf20Sopenharmony_ci	int i;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pcicptrs); i++) {
4638c2ecf20Sopenharmony_ci		if (pcicptrs[i].pcicptr)
4648c2ecf20Sopenharmony_ci			tx4927_dump_pcic_settings1(pcicptrs[i].pcicptr);
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ciirqreturn_t tx4927_pcierr_interrupt(int irq, void *dev_id)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	struct pt_regs *regs = get_irq_regs();
4718c2ecf20Sopenharmony_ci	struct tx4927_pcic_reg __iomem *pcicptr =
4728c2ecf20Sopenharmony_ci		(struct tx4927_pcic_reg __iomem *)(unsigned long)dev_id;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	if (txx9_pci_err_action != TXX9_PCI_ERR_IGNORE) {
4758c2ecf20Sopenharmony_ci		printk(KERN_WARNING "PCIERR interrupt at 0x%0*lx\n",
4768c2ecf20Sopenharmony_ci		       (int)(2 * sizeof(unsigned long)), regs->cp0_epc);
4778c2ecf20Sopenharmony_ci		tx4927_report_pcic_status1(pcicptr);
4788c2ecf20Sopenharmony_ci	}
4798c2ecf20Sopenharmony_ci	if (txx9_pci_err_action != TXX9_PCI_ERR_PANIC) {
4808c2ecf20Sopenharmony_ci		/* clear all pci errors */
4818c2ecf20Sopenharmony_ci		__raw_writel((__raw_readl(&pcicptr->pcistatus) & 0x0000ffff)
4828c2ecf20Sopenharmony_ci			     | (TX4927_PCIC_PCISTATUS_ALL << 16),
4838c2ecf20Sopenharmony_ci			     &pcicptr->pcistatus);
4848c2ecf20Sopenharmony_ci		__raw_writel(TX4927_PCIC_G2PSTATUS_ALL, &pcicptr->g2pstatus);
4858c2ecf20Sopenharmony_ci		__raw_writel(TX4927_PCIC_PBASTATUS_ALL, &pcicptr->pbastatus);
4868c2ecf20Sopenharmony_ci		__raw_writel(TX4927_PCIC_PCICSTATUS_ALL, &pcicptr->pcicstatus);
4878c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
4888c2ecf20Sopenharmony_ci	}
4898c2ecf20Sopenharmony_ci	console_verbose();
4908c2ecf20Sopenharmony_ci	tx4927_dump_pcic_settings1(pcicptr);
4918c2ecf20Sopenharmony_ci	panic("PCI error.");
4928c2ecf20Sopenharmony_ci}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci#ifdef CONFIG_TOSHIBA_FPCIB0
4958c2ecf20Sopenharmony_cistatic void tx4927_quirk_slc90e66_bridge(struct pci_dev *dev)
4968c2ecf20Sopenharmony_ci{
4978c2ecf20Sopenharmony_ci	struct tx4927_pcic_reg __iomem *pcicptr = pci_bus_to_pcicptr(dev->bus);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if (!pcicptr)
5008c2ecf20Sopenharmony_ci		return;
5018c2ecf20Sopenharmony_ci	if (__raw_readl(&pcicptr->pbacfg) & TX4927_PCIC_PBACFG_PBAEN) {
5028c2ecf20Sopenharmony_ci		/* Reset Bus Arbiter */
5038c2ecf20Sopenharmony_ci		__raw_writel(TX4927_PCIC_PBACFG_RPBA, &pcicptr->pbacfg);
5048c2ecf20Sopenharmony_ci		/*
5058c2ecf20Sopenharmony_ci		 * swap reqBP and reqXP (raise priority of SLC90E66).
5068c2ecf20Sopenharmony_ci		 * SLC90E66(PCI-ISA bridge) is connected to REQ2 on
5078c2ecf20Sopenharmony_ci		 * PCI Backplane board.
5088c2ecf20Sopenharmony_ci		 */
5098c2ecf20Sopenharmony_ci		__raw_writel(0x72543610, &pcicptr->pbareqport);
5108c2ecf20Sopenharmony_ci		__raw_writel(0, &pcicptr->pbabm);
5118c2ecf20Sopenharmony_ci		/* Use Fixed ParkMaster (required by SLC90E66) */
5128c2ecf20Sopenharmony_ci		__raw_writel(TX4927_PCIC_PBACFG_FIXPA, &pcicptr->pbacfg);
5138c2ecf20Sopenharmony_ci		/* Enable Bus Arbiter */
5148c2ecf20Sopenharmony_ci		__raw_writel(TX4927_PCIC_PBACFG_FIXPA |
5158c2ecf20Sopenharmony_ci			     TX4927_PCIC_PBACFG_PBAEN,
5168c2ecf20Sopenharmony_ci			     &pcicptr->pbacfg);
5178c2ecf20Sopenharmony_ci		printk(KERN_INFO "PCI: Use Fixed Park Master (REQPORT %08x)\n",
5188c2ecf20Sopenharmony_ci		       __raw_readl(&pcicptr->pbareqport));
5198c2ecf20Sopenharmony_ci	}
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_EFAR_SLC90E66_0 0x9460
5228c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_0,
5238c2ecf20Sopenharmony_ci	tx4927_quirk_slc90e66_bridge);
5248c2ecf20Sopenharmony_ci#endif
525