linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: arnd@arndb.de (Arnd Bergmann)
To: linux-arm-kernel@lists.infradead.org
Subject: [RFC] PCI: BCM5301X: add PCIe2 driver for BCM5301X SoCs
Date: Sat, 08 Nov 2014 20:47:34 +0100	[thread overview]
Message-ID: <1756974.RYWuW6FYtL@wuerfel> (raw)
In-Reply-To: <1415470392-28229-1-git-send-email-hauke@hauke-m.de>

On Saturday 08 November 2014 19:13:12 Hauke Mehrtens wrote:

> diff --git a/drivers/pci/host/pci-host-bcm5301x.c b/drivers/pci/host/pci-host-bcm5301x.c
> new file mode 100644
> index 0000000..8b7ba62
> --- /dev/null
> +++ b/drivers/pci/host/pci-host-bcm5301x.c
> @@ -0,0 +1,483 @@
> +/*
> + * Northstar PCI-Express driver
> + * Only supports Root-Complex (RC) mode
> + *
> + * Notes:
> + * PCI Domains are being used to identify the PCIe port 1:1.
> + *
> + * Only MEM access is supported, PAX does not support IO.

What is PAX?

> +static int bcma_pcie2_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
> +{
> +	struct pci_sys_data *sys = pdev->sysdata;
> +	struct bcma_device *bdev = sys->private_data;
> +
> +	/*
> +	 * Every PCIe controller has 5 IRQ number and the last one is
> +	 * triggered every time, use that one
> +	 */
> +	if (bdev && bdev->dev.of_node)
> +		return irq_of_parse_and_map(bdev->dev.of_node, 4);
> +
> +	return bdev->irq;
> +}

If you have an OF device node for the PCI host, you don't need this,
there should already be an interrupt-map property that correctly
maps this into the interrupt domain of the bcma bus, so you can use
the default of_irq_parse_and_map_pci function.

> +static u32 bcma_pcie2_cfg_base(struct bcma_device *bdev, int busno,
> +			       unsigned int devfn, int where)
> +{
> +	int slot = PCI_SLOT(devfn);
> +	int fn = PCI_FUNC(devfn);
> +	u32 addr_reg;
> +
> +	if (busno == 0) {
> +		if (slot >= 1)
> +			return 0;
> +		bcma_write32(bdev, BCMA_CORE_PCIE2_CONFIGINDADDR,
> +			     where & 0xffc);
> +		return BCMA_CORE_PCIE2_CONFIGINDDATA;
> +	}
> +	if (fn > 1)
> +		return 0;
> +	addr_reg = (busno & 0xff) << 20 | (slot << 15) | (fn << 12) |
> +		   (where & 0xffc) | (1 & 0x3);
> +
> +	bcma_write32(bdev, BCMA_CORE_PCIE2_CFG_ADDR, addr_reg);
> +	return BCMA_CORE_PCIE2_CFG_DATA;
> +}

The normal buses seem to be ECAM compliant, I wonder if we can have the
code to access those shared between this driver, pci-host-generic.c and
the ACPI PCI implementation.

The root bus is unfortunately not compliant, which for some reason
is common on a lot of controllers.

> +static u32 bcma_pcie2_read_config(struct bcma_device *bdev, int busno,
> +				  unsigned int devfn, int where, int size)
> +{
> +	u32 base;
> +	u32 data_reg;
> +	u32 mask;
> +	int shift;
> +
> +	base = bcma_pcie2_cfg_base(bdev, busno, devfn, where);
> +
> +	if (!base)
> +		return ~0UL;
> +
> +	data_reg = bcma_read32(bdev, base);
> +
> +	/* NS: CLASS field is R/O, and set to wrong 0x200 value */
> +	if (busno == 0 && devfn == 0) {
> +		/*
> +		 * RC's class is 0x0280, but Linux PCI driver needs 0x604
> +		 * for a PCIe bridge. So we must fixup the class code
> +		 * to 0x604 here.
> +		 */
> +		if ((where & 0xffc) == PCI_CLASS_REVISION) {
> +			data_reg &= 0xff;
> +			data_reg |= 0x604 << 16;
> +		}
> +	}
> +	/* HEADER_TYPE=00 indicates the port in EP mode */
> +
> +	if (size == 4)
> +		return data_reg;
> +
> +	mask = (1 << (size * 8)) - 1;
> +	shift = (where % 4) * 8;
> +	return (data_reg >> shift) & mask;
> +}

Interesting. 0x0280 is PCI_CLASS_NETWORK_OTHER, I guess this is the
same PCI core that is used on broadcom network adapters in endpoint
mode, and when someone tweaked the core to do root complex mode,
they forgot to fix this.

Which code depends on this? I think I've seem something similar in
other host drivers, so maybe we can change the core code instead.

> +
> +static u8 bcma_pcie2_read_config8(struct bcma_device *bdev, int busno,
> +				  unsigned int devfn, int where)
> +{
> +	return bcma_pcie2_read_config(bdev, busno, devfn, where, 1);
> +}
> +
> +static u16 bcma_pcie2_read_config16(struct bcma_device *bdev, int busno,
> +				    unsigned int devfn, int where)
> +{
> +	return bcma_pcie2_read_config(bdev, busno, devfn, where, 2);
> +}
> +
> +static u32 bcma_pcie2_read_config32(struct bcma_device *bdev, int busno,
> +				    unsigned int devfn, int where)
> +{
> +	return bcma_pcie2_read_config(bdev, busno, devfn, where, 4);
> +}

These all seem to be relatively pointless, I'd just open-code the
bcma_pcie2_read_config call in the calling function.

> +
> +/*
> + * Initializte the PCIe controller
> + */
> +static void bcma_pcie2_hw_init(struct bcma_device *bdev)
> +{
> +	u32 tmp32;
> +	u16 tmp16;
> +
> +	/* Change MPS and MRRS to 512 */
> +	tmp16 = bcma_pcie2_read_config16(bdev, 0, 0, 0x4d4);
> +	tmp16 &= ~7;
> +	tmp16 |= 2;
> +	bcma_pcie2_write_config16(bdev, 0, 0, 0x4d4, tmp16);
> +
> +	tmp32 = bcma_pcie2_read_config32(bdev, 0, 0, 0xb4);
> +	tmp32 &= ~((7 << 12) | (7 << 5));
> +	tmp32 |= (2 << 12) | (2 << 5);
> +	bcma_pcie2_write_config32(bdev, 0, 0, 0xb4, tmp32);
> +
> +	/*
> +	 * Turn-on Root-Complex (RC) mode, from reset default of EP
> +	 * The mode is set by straps, can be overwritten via DMU
> +	 * register <cru_straps_control> bit 5, "1" means RC
> +	 */
> +
> +	/* Send a downstream reset */
> +	bcma_write32(bdev, BCMA_CORE_PCIE2_CLK_CONTROL,
> +		     PCIE2_CLKC_RST_OE | PCIE2_CLKC_RST);
> +	udelay(250);
> +	bcma_write32(bdev, BCMA_CORE_PCIE2_CLK_CONTROL, PCIE2_CLKC_RST_OE);
> +	mdelay(250);
> +
> +	/* TBD: take care of PM, check we're on */
> +}

Can you turn the two delays into msleep()? Wasting 250ms of CPU time is
really nasty.

> +	/*
> +	 * Inbound address translation setup
> +	 * Northstar only maps up to 128 MiB inbound, DRAM could be up to 1 GiB.
> +	 *
> +	 * For now allow access to entire DRAM, assuming it is less than 128MiB,
> +	 * otherwise DMA bouncing mechanism may be required.
> +	 * Also consider DMA mask to limit DMA physical address
> +	 */
> +	/* 64-bit LE regs, write low word, high is 0 at reset */
> +	bcma_write32(bdev, BCMA_CORE_PCIE2_FUNC0_IMAP1, PHYS_OFFSET | 0x1);
> +	bcma_write32(bdev, BCMA_CORE_PCIE2_IARR1_LOWER,
> +			   PHYS_OFFSET | ((SZ_128M >> 20) & 0xff));

Maybe I should bully you into enabling swiotlb on arm32 ;-)

Do you have any machines with more than 128MB of RAM that use this?

According to wikidevi.com [http://tinyurl.com/pdtw2h4], most machines
with bcm4708/81/9 have 256MB or 512MB. I think it shouldn't be too hard
to get swiotlb to work on arm32, given that we already use it on arm64.

	Arnd

  reply	other threads:[~2014-11-08 19:47 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-11-08 18:13 [RFC] PCI: BCM5301X: add PCIe2 driver for BCM5301X SoCs Hauke Mehrtens
2014-11-08 19:47 ` Arnd Bergmann [this message]
2014-11-08 21:26   ` Hauke Mehrtens
2014-11-09 20:27     ` Arnd Bergmann
2015-04-17 14:09       ` Arnd Bergmann
2015-04-17 16:07         ` Ray Jui

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1756974.RYWuW6FYtL@wuerfel \
    --to=arnd@arndb.de \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).