xref: /openbmc/linux/drivers/bcma/driver_pci.c (revision 2be25cac8402fab56bb51166f464d1b420bcf744)
18369ae33SRafał Miłecki /*
28369ae33SRafał Miłecki  * Broadcom specific AMBA
38369ae33SRafał Miłecki  * PCI Core
48369ae33SRafał Miłecki  *
58369ae33SRafał Miłecki  * Copyright 2005, Broadcom Corporation
6eb032b98SMichael Büsch  * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
7*2be25cacSHauke Mehrtens  * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
88369ae33SRafał Miłecki  *
98369ae33SRafał Miłecki  * Licensed under the GNU/GPL. See COPYING for details.
108369ae33SRafał Miłecki  */
118369ae33SRafał Miłecki 
128369ae33SRafał Miłecki #include "bcma_private.h"
1344a8e377SPaul Gortmaker #include <linux/export.h>
148369ae33SRafał Miłecki #include <linux/bcma/bcma.h>
158369ae33SRafał Miłecki 
168369ae33SRafał Miłecki /**************************************************
178369ae33SRafał Miłecki  * R/W ops.
188369ae33SRafał Miłecki  **************************************************/
198369ae33SRafał Miłecki 
208369ae33SRafał Miłecki static u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address)
218369ae33SRafał Miłecki {
22*2be25cacSHauke Mehrtens 	pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_ADDR, address);
23*2be25cacSHauke Mehrtens 	pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_ADDR);
24*2be25cacSHauke Mehrtens 	return pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_DATA);
258369ae33SRafał Miłecki }
268369ae33SRafał Miłecki 
278369ae33SRafał Miłecki #if 0
288369ae33SRafał Miłecki static void bcma_pcie_write(struct bcma_drv_pci *pc, u32 address, u32 data)
298369ae33SRafał Miłecki {
30*2be25cacSHauke Mehrtens 	pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_ADDR, address);
31*2be25cacSHauke Mehrtens 	pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_ADDR);
32*2be25cacSHauke Mehrtens 	pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_DATA, data);
338369ae33SRafał Miłecki }
348369ae33SRafał Miłecki #endif
358369ae33SRafał Miłecki 
368369ae33SRafał Miłecki static void bcma_pcie_mdio_set_phy(struct bcma_drv_pci *pc, u8 phy)
378369ae33SRafał Miłecki {
388369ae33SRafał Miłecki 	u32 v;
398369ae33SRafał Miłecki 	int i;
408369ae33SRafał Miłecki 
41*2be25cacSHauke Mehrtens 	v = BCMA_CORE_PCI_MDIODATA_START;
42*2be25cacSHauke Mehrtens 	v |= BCMA_CORE_PCI_MDIODATA_WRITE;
43*2be25cacSHauke Mehrtens 	v |= (BCMA_CORE_PCI_MDIODATA_DEV_ADDR <<
44*2be25cacSHauke Mehrtens 	      BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF);
45*2be25cacSHauke Mehrtens 	v |= (BCMA_CORE_PCI_MDIODATA_BLK_ADDR <<
46*2be25cacSHauke Mehrtens 	      BCMA_CORE_PCI_MDIODATA_REGADDR_SHF);
47*2be25cacSHauke Mehrtens 	v |= BCMA_CORE_PCI_MDIODATA_TA;
488369ae33SRafał Miłecki 	v |= (phy << 4);
49*2be25cacSHauke Mehrtens 	pcicore_write32(pc, BCMA_CORE_PCI_MDIO_DATA, v);
508369ae33SRafał Miłecki 
518369ae33SRafał Miłecki 	udelay(10);
528369ae33SRafał Miłecki 	for (i = 0; i < 200; i++) {
53*2be25cacSHauke Mehrtens 		v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
54*2be25cacSHauke Mehrtens 		if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE)
558369ae33SRafał Miłecki 			break;
568369ae33SRafał Miłecki 		msleep(1);
578369ae33SRafał Miłecki 	}
588369ae33SRafał Miłecki }
598369ae33SRafał Miłecki 
608369ae33SRafał Miłecki static u16 bcma_pcie_mdio_read(struct bcma_drv_pci *pc, u8 device, u8 address)
618369ae33SRafał Miłecki {
628369ae33SRafał Miłecki 	int max_retries = 10;
638369ae33SRafał Miłecki 	u16 ret = 0;
648369ae33SRafał Miłecki 	u32 v;
658369ae33SRafał Miłecki 	int i;
668369ae33SRafał Miłecki 
67*2be25cacSHauke Mehrtens 	/* enable mdio access to SERDES */
68*2be25cacSHauke Mehrtens 	v = BCMA_CORE_PCI_MDIOCTL_PREAM_EN;
69*2be25cacSHauke Mehrtens 	v |= BCMA_CORE_PCI_MDIOCTL_DIVISOR_VAL;
70*2be25cacSHauke Mehrtens 	pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, v);
718369ae33SRafał Miłecki 
728369ae33SRafał Miłecki 	if (pc->core->id.rev >= 10) {
738369ae33SRafał Miłecki 		max_retries = 200;
748369ae33SRafał Miłecki 		bcma_pcie_mdio_set_phy(pc, device);
75*2be25cacSHauke Mehrtens 		v = (BCMA_CORE_PCI_MDIODATA_DEV_ADDR <<
76*2be25cacSHauke Mehrtens 		     BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF);
77*2be25cacSHauke Mehrtens 		v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF);
78*2be25cacSHauke Mehrtens 	} else {
79*2be25cacSHauke Mehrtens 		v = (device << BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF_OLD);
80*2be25cacSHauke Mehrtens 		v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD);
818369ae33SRafał Miłecki 	}
828369ae33SRafał Miłecki 
83*2be25cacSHauke Mehrtens 	v = BCMA_CORE_PCI_MDIODATA_START;
84*2be25cacSHauke Mehrtens 	v |= BCMA_CORE_PCI_MDIODATA_READ;
85*2be25cacSHauke Mehrtens 	v |= BCMA_CORE_PCI_MDIODATA_TA;
86*2be25cacSHauke Mehrtens 
87*2be25cacSHauke Mehrtens 	pcicore_write32(pc, BCMA_CORE_PCI_MDIO_DATA, v);
888369ae33SRafał Miłecki 	/* Wait for the device to complete the transaction */
898369ae33SRafał Miłecki 	udelay(10);
90f1a9c1e6SRafał Miłecki 	for (i = 0; i < max_retries; i++) {
91*2be25cacSHauke Mehrtens 		v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
92*2be25cacSHauke Mehrtens 		if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE) {
938369ae33SRafał Miłecki 			udelay(10);
94*2be25cacSHauke Mehrtens 			ret = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_DATA);
958369ae33SRafał Miłecki 			break;
968369ae33SRafał Miłecki 		}
978369ae33SRafał Miłecki 		msleep(1);
988369ae33SRafał Miłecki 	}
99*2be25cacSHauke Mehrtens 	pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0);
1008369ae33SRafał Miłecki 	return ret;
1018369ae33SRafał Miłecki }
1028369ae33SRafał Miłecki 
1038369ae33SRafał Miłecki static void bcma_pcie_mdio_write(struct bcma_drv_pci *pc, u8 device,
1048369ae33SRafał Miłecki 				u8 address, u16 data)
1058369ae33SRafał Miłecki {
1068369ae33SRafał Miłecki 	int max_retries = 10;
1078369ae33SRafał Miłecki 	u32 v;
1088369ae33SRafał Miłecki 	int i;
1098369ae33SRafał Miłecki 
110*2be25cacSHauke Mehrtens 	/* enable mdio access to SERDES */
111*2be25cacSHauke Mehrtens 	v = BCMA_CORE_PCI_MDIOCTL_PREAM_EN;
112*2be25cacSHauke Mehrtens 	v |= BCMA_CORE_PCI_MDIOCTL_DIVISOR_VAL;
113*2be25cacSHauke Mehrtens 	pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, v);
1148369ae33SRafał Miłecki 
1158369ae33SRafał Miłecki 	if (pc->core->id.rev >= 10) {
1168369ae33SRafał Miłecki 		max_retries = 200;
1178369ae33SRafał Miłecki 		bcma_pcie_mdio_set_phy(pc, device);
118*2be25cacSHauke Mehrtens 		v = (BCMA_CORE_PCI_MDIODATA_DEV_ADDR <<
119*2be25cacSHauke Mehrtens 		     BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF);
120*2be25cacSHauke Mehrtens 		v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF);
121*2be25cacSHauke Mehrtens 	} else {
122*2be25cacSHauke Mehrtens 		v = (device << BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF_OLD);
123*2be25cacSHauke Mehrtens 		v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD);
1248369ae33SRafał Miłecki 	}
1258369ae33SRafał Miłecki 
126*2be25cacSHauke Mehrtens 	v = BCMA_CORE_PCI_MDIODATA_START;
127*2be25cacSHauke Mehrtens 	v |= BCMA_CORE_PCI_MDIODATA_WRITE;
128*2be25cacSHauke Mehrtens 	v |= BCMA_CORE_PCI_MDIODATA_TA;
1298369ae33SRafał Miłecki 	v |= data;
130*2be25cacSHauke Mehrtens 	pcicore_write32(pc, BCMA_CORE_PCI_MDIO_DATA, v);
1318369ae33SRafał Miłecki 	/* Wait for the device to complete the transaction */
1328369ae33SRafał Miłecki 	udelay(10);
1338369ae33SRafał Miłecki 	for (i = 0; i < max_retries; i++) {
134*2be25cacSHauke Mehrtens 		v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
135*2be25cacSHauke Mehrtens 		if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE)
1368369ae33SRafał Miłecki 			break;
1378369ae33SRafał Miłecki 		msleep(1);
1388369ae33SRafał Miłecki 	}
139*2be25cacSHauke Mehrtens 	pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0);
1408369ae33SRafał Miłecki }
1418369ae33SRafał Miłecki 
1428369ae33SRafał Miłecki /**************************************************
1438369ae33SRafał Miłecki  * Workarounds.
1448369ae33SRafał Miłecki  **************************************************/
1458369ae33SRafał Miłecki 
1468369ae33SRafał Miłecki static u8 bcma_pcicore_polarity_workaround(struct bcma_drv_pci *pc)
1478369ae33SRafał Miłecki {
148*2be25cacSHauke Mehrtens 	u32 tmp;
149*2be25cacSHauke Mehrtens 
150*2be25cacSHauke Mehrtens 	tmp = bcma_pcie_read(pc, BCMA_CORE_PCI_PLP_STATUSREG);
151*2be25cacSHauke Mehrtens 	if (tmp & BCMA_CORE_PCI_PLP_POLARITYINV_STAT)
152*2be25cacSHauke Mehrtens 		return BCMA_CORE_PCI_SERDES_RX_CTRL_FORCE |
153*2be25cacSHauke Mehrtens 		       BCMA_CORE_PCI_SERDES_RX_CTRL_POLARITY;
154*2be25cacSHauke Mehrtens 	else
155*2be25cacSHauke Mehrtens 		return BCMA_CORE_PCI_SERDES_RX_CTRL_FORCE;
1568369ae33SRafał Miłecki }
1578369ae33SRafał Miłecki 
1588369ae33SRafał Miłecki static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
1598369ae33SRafał Miłecki {
1608369ae33SRafał Miłecki 	u16 tmp;
1618369ae33SRafał Miłecki 
162*2be25cacSHauke Mehrtens 	bcma_pcie_mdio_write(pc, BCMA_CORE_PCI_MDIODATA_DEV_RX,
163*2be25cacSHauke Mehrtens 	                     BCMA_CORE_PCI_SERDES_RX_CTRL,
1648369ae33SRafał Miłecki 			     bcma_pcicore_polarity_workaround(pc));
165*2be25cacSHauke Mehrtens 	tmp = bcma_pcie_mdio_read(pc, BCMA_CORE_PCI_MDIODATA_DEV_PLL,
166*2be25cacSHauke Mehrtens 	                          BCMA_CORE_PCI_SERDES_PLL_CTRL);
167*2be25cacSHauke Mehrtens 	if (tmp & BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN)
168*2be25cacSHauke Mehrtens 		bcma_pcie_mdio_write(pc, BCMA_CORE_PCI_MDIODATA_DEV_PLL,
169*2be25cacSHauke Mehrtens 		                     BCMA_CORE_PCI_SERDES_PLL_CTRL,
170*2be25cacSHauke Mehrtens 		                     tmp & ~BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN);
1718369ae33SRafał Miłecki }
1728369ae33SRafał Miłecki 
1738369ae33SRafał Miłecki /**************************************************
1748369ae33SRafał Miłecki  * Init.
1758369ae33SRafał Miłecki  **************************************************/
1768369ae33SRafał Miłecki 
1779352f69cSRafał Miłecki static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
1788369ae33SRafał Miłecki {
1798369ae33SRafał Miłecki 	bcma_pcicore_serdes_workaround(pc);
1808369ae33SRafał Miłecki }
1811de520f4SRafał Miłecki 
1829352f69cSRafał Miłecki static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
1839352f69cSRafał Miłecki {
1849352f69cSRafał Miłecki 	struct bcma_bus *bus = pc->core->bus;
1859352f69cSRafał Miłecki 	u16 chipid_top;
1869352f69cSRafał Miłecki 
1879352f69cSRafał Miłecki 	chipid_top = (bus->chipinfo.id & 0xFF00);
1889352f69cSRafał Miłecki 	if (chipid_top != 0x4700 &&
1899352f69cSRafał Miłecki 	    chipid_top != 0x5300)
1909352f69cSRafał Miłecki 		return false;
1919352f69cSRafał Miłecki 
1926e6e8c51SJohn W. Linville #ifdef CONFIG_SSB_DRIVER_PCICORE
19326f2622eSRafał Miłecki 	if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI)
1949352f69cSRafał Miłecki 		return false;
1956e6e8c51SJohn W. Linville #endif /* CONFIG_SSB_DRIVER_PCICORE */
1969352f69cSRafał Miłecki 
1979352f69cSRafał Miłecki #if 0
1989352f69cSRafał Miłecki 	/* TODO: on BCMA we use address from EROM instead of magic formula */
1999352f69cSRafał Miłecki 	u32 tmp;
2009352f69cSRafał Miłecki 	return !mips_busprobe32(tmp, (bus->mmio +
2019352f69cSRafał Miłecki 		(pc->core->core_index * BCMA_CORE_SIZE)));
2029352f69cSRafał Miłecki #endif
2039352f69cSRafał Miłecki 
2049352f69cSRafał Miłecki 	return true;
2059352f69cSRafał Miłecki }
2069352f69cSRafał Miłecki 
2079352f69cSRafał Miłecki void bcma_core_pci_init(struct bcma_drv_pci *pc)
2089352f69cSRafał Miłecki {
209517f43e5SHauke Mehrtens 	if (pc->setup_done)
210517f43e5SHauke Mehrtens 		return;
211517f43e5SHauke Mehrtens 
2129352f69cSRafał Miłecki 	if (bcma_core_pci_is_in_hostmode(pc)) {
2139352f69cSRafał Miłecki #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
2149352f69cSRafał Miłecki 		bcma_core_pci_hostmode_init(pc);
2159352f69cSRafał Miłecki #else
2169352f69cSRafał Miłecki 		pr_err("Driver compiled without support for hostmode PCI\n");
2179352f69cSRafał Miłecki #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
2189352f69cSRafał Miłecki 	} else {
2199352f69cSRafał Miłecki 		bcma_core_pci_clientmode_init(pc);
2209352f69cSRafał Miłecki 	}
221517f43e5SHauke Mehrtens 
222517f43e5SHauke Mehrtens 	pc->setup_done = true;
2239352f69cSRafał Miłecki }
2249352f69cSRafał Miłecki 
2251de520f4SRafał Miłecki int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
2261de520f4SRafał Miłecki 			  bool enable)
2271de520f4SRafał Miłecki {
2281de520f4SRafał Miłecki 	struct pci_dev *pdev = pc->core->bus->host_pci;
2291de520f4SRafał Miłecki 	u32 coremask, tmp;
230ecd177c2SHauke Mehrtens 	int err = 0;
231ecd177c2SHauke Mehrtens 
232ecd177c2SHauke Mehrtens 	if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
233ecd177c2SHauke Mehrtens 		/* This bcma device is not on a PCI host-bus. So the IRQs are
234ecd177c2SHauke Mehrtens 		 * not routed through the PCI core.
235ecd177c2SHauke Mehrtens 		 * So we must not enable routing through the PCI core. */
236ecd177c2SHauke Mehrtens 		goto out;
237ecd177c2SHauke Mehrtens 	}
2381de520f4SRafał Miłecki 
2391de520f4SRafał Miłecki 	err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
2401de520f4SRafał Miłecki 	if (err)
2411de520f4SRafał Miłecki 		goto out;
2421de520f4SRafał Miłecki 
2431de520f4SRafał Miłecki 	coremask = BIT(core->core_index) << 8;
2441de520f4SRafał Miłecki 	if (enable)
2451de520f4SRafał Miłecki 		tmp |= coremask;
2461de520f4SRafał Miłecki 	else
2471de520f4SRafał Miłecki 		tmp &= ~coremask;
2481de520f4SRafał Miłecki 
2491de520f4SRafał Miłecki 	err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp);
2501de520f4SRafał Miłecki 
2511de520f4SRafał Miłecki out:
2521de520f4SRafał Miłecki 	return err;
2531de520f4SRafał Miłecki }
254440ca98fSRafał Miłecki EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl);
255