Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a45635df authored by Paul Mundt's avatar Paul Mundt
Browse files

sh: Reworked SH7780 PCI initialization.



This consolidates the PCI initialization code for all of the pci-sh7780
users, and sets up the memory window dynamically as opposed to using
hardcoded window positions.

A number of bugs were fixed at the same time, including the PIO handling
and master abort timeout settings being incorrect.

Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent 9762528f
Loading
Loading
Loading
Loading
+0 −12
Original line number Diff line number Diff line
@@ -22,15 +22,3 @@ int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
{
	return irq_tab[slot];
}

int pci_fixup_pcic(struct pci_channel *chan)
{
	pci_write_reg(chan, 0x000043ff, SH4_PCIINTM);
	pci_write_reg(chan, 0x00000000, SH7780_PCIIBAR);
	pci_write_reg(chan, 0x08000000, SH7780_PCICSCR0);
	pci_write_reg(chan, 0x0000001b, SH7780_PCICSAR0);
	pci_write_reg(chan, 0xfd000000, SH7780_PCICSCR1);
	pci_write_reg(chan, 0x0000000f, SH7780_PCICSAR1);

	return 0;
}
+0 −19
Original line number Diff line number Diff line
@@ -31,22 +31,3 @@ int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
{
       return sdk7780_irq_tab[pin-1][slot];
}
int pci_fixup_pcic(struct pci_channel *chan)
{
	/* Enable all interrupts, so we know what to fix */
	pci_write_reg(chan, 0x0000C3FF, SH7780_PCIIMR);

	/* Set up standard PCI config registers */
	pci_write_reg(chan, 0x08000000, SH7780_PCIMBAR0);	/* PCI */
	pci_write_reg(chan, 0x08000000, SH4_PCILAR0);	/* SHwy */
	pci_write_reg(chan, 0x07F00001, SH4_PCILSR0);	/* size 128M w/ MBAR */

	pci_write_reg(chan, 0x00000000, SH7780_PCIMBAR1);
	pci_write_reg(chan, 0x00000000, SH4_PCILAR1);
	pci_write_reg(chan, 0x00000000, SH4_PCILSR1);

	pci_write_reg(chan, 0xAB000801, SH7780_PCIIBAR);
	pci_write_reg(chan, 0xA5000C01, SH4_PCICR);

	return 0;
}
+12 −1
Original line number Diff line number Diff line
@@ -49,6 +49,17 @@
  #define SH4_PCIINT_MWPD	  0x00000002	/* Master Write PERR Detect */
  #define SH4_PCIINT_MRPD	  0x00000001	/* Master Read PERR Detect */
#define SH4_PCIINTM		0x118		/* PCI Interrupt Mask */
  #define SH4_PCIINTM_TTADIM	  BIT(14)	/* Target-target abort interrupt */
  #define SH4_PCIINTM_TMTOIM	  BIT(9)	/* Target retry timeout */
  #define SH4_PCIINTM_MDEIM	  BIT(8)	/* Master function disable error */
  #define SH4_PCIINTM_APEDIM	  BIT(7)	/* Address parity error detection */
  #define SH4_PCIINTM_SDIM	  BIT(6)	/* SERR detection */
  #define SH4_PCIINTM_DPEITWM	  BIT(5)	/* Data parity error for target write */
  #define SH4_PCIINTM_PEDITRM	  BIT(4)	/* PERR detection for target read */
  #define SH4_PCIINTM_TADIMM	  BIT(3)	/* Target abort for master */
  #define SH4_PCIINTM_MADIMM	  BIT(2)	/* Master abort for master */
  #define SH4_PCIINTM_MWPDIM	  BIT(1)	/* Master write data parity error */
  #define SH4_PCIINTM_MRDPEIM	  BIT(0)	/* Master read data parity error */
#define SH4_PCIALR		0x11C		/* Error Address Register */
#define SH4_PCICLR		0x120		/* Error Command/Data */
  #define SH4_PCICLR_MPIO	  0x80000000
@@ -61,7 +72,7 @@
#define SH4_PCIAINT		0x130		/* Arbiter Interrupt Register */
  #define SH4_PCIAINT_MBKN	  0x00002000	/* Master Broken Interrupt */
  #define SH4_PCIAINT_TBTO	  0x00001000	/* Target Bus Time Out */
  #define SH4_PCIAINT_MBTO	  0x00001000	/* Master Bus Time Out */
  #define SH4_PCIAINT_MBTO	  0x00000800	/* Master Bus Time Out */
  #define SH4_PCIAINT_TABT	  0x00000008	/* Target Abort */
  #define SH4_PCIAINT_MABT	  0x00000004	/* Master Abort */
  #define SH4_PCIAINT_RDPE	  0x00000002	/* Read Data Parity Error */
+83 −66
Original line number Diff line number Diff line
/*
 * Low-Level PCI Support for the SH7780
 *
 *  Copyright (C) 2005 - 2009  Paul Mundt
 *  Copyright (C) 2005 - 2010  Paul Mundt
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
@@ -14,11 +14,13 @@
#include <linux/errno.h>
#include <linux/delay.h>
#include "pci-sh4.h"
#include <asm/mmu.h>
#include <asm/sizes.h>

static struct resource sh7785_io_resource = {
	.name	= "SH7785_IO",
	.start	= SH7780_PCI_IO_BASE,
	.end	= SH7780_PCI_IO_BASE + SH7780_PCI_IO_SIZE - 1,
	.start	= 0x1000,
	.end	= SH7780_PCI_IO_SIZE - 1,
	.flags	= IORESOURCE_IO
};

@@ -38,25 +40,14 @@ static struct pci_channel sh7780_pci_controller = {
	.io_map_base	= SH7780_PCI_IO_BASE,
};

static struct sh4_pci_address_map sh7780_pci_map = {
	.window0	= {
#if defined(CONFIG_32BIT)
		.base	= SH7780_32BIT_DDR_BASE_ADDR,
		.size	= 0x40000000,
#else
		.base	= SH7780_CS0_BASE_ADDR,
		.size	= 0x20000000,
#endif
	},
};

static int __init sh7780_pci_init(void)
{
	struct pci_channel *chan = &sh7780_pci_controller;
	phys_addr_t memphys;
	size_t memsize;
	unsigned int id;
	const char *type = NULL;
	const char *type;
	int ret;
	u32 word;

	printk(KERN_NOTICE "PCI: Starting intialization.\n");

@@ -65,17 +56,24 @@ static int __init sh7780_pci_init(void)
	/* Enable CPU access to the PCIC registers. */
	__raw_writel(PCIECR_ENBL, PCIECR);

	id = __raw_readw(chan->reg_base + SH7780_PCIVID);
	if (id != SH7780_VENDOR_ID) {
	/* Reset */
	__raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_PRST,
		     chan->reg_base + SH4_PCICR);

	/* Wait for it to come back up.. */
	mdelay(100);

	id = __raw_readw(chan->reg_base + PCI_VENDOR_ID);
	if (id != PCI_VENDOR_ID_RENESAS) {
		printk(KERN_ERR "PCI: Unknown vendor ID 0x%04x.\n", id);
		return -ENODEV;
	}

	id = __raw_readw(chan->reg_base + SH7780_PCIDID);
	type = (id == SH7763_DEVICE_ID)	? "SH7763" :
	       (id == SH7780_DEVICE_ID) ? "SH7780" :
	       (id == SH7781_DEVICE_ID) ? "SH7781" :
	       (id == SH7785_DEVICE_ID) ? "SH7785" :
	id = __raw_readw(chan->reg_base + PCI_DEVICE_ID);
	type = (id == PCI_DEVICE_ID_RENESAS_SH7763) ? "SH7763" :
	       (id == PCI_DEVICE_ID_RENESAS_SH7780) ? "SH7780" :
	       (id == PCI_DEVICE_ID_RENESAS_SH7781) ? "SH7781" :
	       (id == PCI_DEVICE_ID_RENESAS_SH7785) ? "SH7785" :
					  NULL;
	if (unlikely(!type)) {
		printk(KERN_ERR "PCI: Found an unsupported Renesas host "
@@ -85,59 +83,78 @@ static int __init sh7780_pci_init(void)

	printk(KERN_NOTICE "PCI: Found a Renesas %s host "
	       "controller, revision %d.\n", type,
	       __raw_readb(chan->reg_base + SH7780_PCIRID));
	       __raw_readb(chan->reg_base + PCI_REVISION_ID));

	if ((ret = sh4_pci_check_direct(chan)) != 0)
		return ret;

	/*
	 * Set the class and sub-class codes.
	 * Now throw it in to register initialization mode and
	 * start the real work.
	 */
	__raw_writeb(PCI_CLASS_BRIDGE_HOST >> 8,
		     chan->reg_base + SH7780_PCIBCC);
	__raw_writeb(PCI_CLASS_BRIDGE_HOST & 0xff,
		     chan->reg_base + SH7780_PCISUB);
	__raw_writel(SH4_PCICR_PREFIX, chan->reg_base + SH4_PCICR);

	memphys = __pa(memory_start);
	memsize = memory_end - memory_start;

	/*
	 * Set IO and Mem windows to local address
	 * Make PCI and local address the same for easy 1 to 1 mapping
	 */
	pci_write_reg(chan, sh7780_pci_map.window0.size - 0xfffff, SH4_PCILSR0);
	/* Set the values on window 0 PCI config registers */
	pci_write_reg(chan, sh7780_pci_map.window0.base, SH4_PCILAR0);
	pci_write_reg(chan, sh7780_pci_map.window0.base, SH7780_PCIMBAR0);

	pci_write_reg(chan, 0x0000380f, SH4_PCIAINTM);

	/* Set up standard PCI config registers */
	__raw_writew(0xFB00, chan->reg_base + SH7780_PCISTATUS);
	__raw_writew(0x0047, chan->reg_base + SH7780_PCICMD);
	__raw_writew(0x1912, chan->reg_base + SH7780_PCISVID);
	__raw_writew(0x0001, chan->reg_base + SH7780_PCISID);

	__raw_writeb(0x00, chan->reg_base + SH7780_PCIPIF);

	/* Apply any last-minute PCIC fixups */
	pci_fixup_pcic(chan);

	pci_write_reg(chan, 0xfd000000, SH7780_PCIMBR0);
	pci_write_reg(chan, 0x00fc0000, SH7780_PCIMBMR0);

#ifdef CONFIG_32BIT
	pci_write_reg(chan, 0xc0000000, SH7780_PCIMBR2);
	pci_write_reg(chan, 0x20000000 - SH7780_PCI_IO_SIZE, SH7780_PCIMBMR2);
#endif

	/* Set IOBR for windows containing area specified in pci.h */
	pci_write_reg(chan, chan->io_resource->start & ~(SH7780_PCI_IO_SIZE-1),
		      SH7780_PCIIOBR);
	pci_write_reg(chan, ((SH7780_PCI_IO_SIZE-1) & (7<<18)),
		      SH7780_PCIIOBMR);

	/* SH7780 init done, set central function init complete */
	/* use round robin mode to stop a device starving/overruning */
	word = SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO;
	pci_write_reg(chan, word, SH4_PCICR);
	__raw_writel(0, chan->reg_base + PCI_BASE_ADDRESS_0);

	__raw_writel(memphys, chan->reg_base + SH4_PCILAR0);
	__raw_writel((memsize - 1) << 9 | 1,
		     chan->reg_base + SH4_PCILSR0);

	/* Clear out PCI arbiter IRQs */
	__raw_writel(0, chan->reg_base + SH4_PCIAINT);

	/* Unmask all of the arbiter IRQs. */
	__raw_writel(SH4_PCIAINT_MBKN | SH4_PCIAINT_TBTO | SH4_PCIAINT_MBTO | \
		     SH4_PCIAINT_TABT | SH4_PCIAINT_MABT | SH4_PCIAINT_RDPE | \
		     SH4_PCIAINT_WDPE, chan->reg_base + SH4_PCIAINTM);

	/* Clear all error conditions */
	__raw_writew(PCI_STATUS_DETECTED_PARITY  | \
		     PCI_STATUS_SIG_SYSTEM_ERROR | \
		     PCI_STATUS_REC_MASTER_ABORT | \
		     PCI_STATUS_REC_TARGET_ABORT | \
		     PCI_STATUS_SIG_TARGET_ABORT | \
		     PCI_STATUS_PARITY, chan->reg_base + PCI_STATUS);

	__raw_writew(PCI_COMMAND_SERR | PCI_COMMAND_WAIT | \
		     PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | \
		     PCI_COMMAND_MEMORY, chan->reg_base + PCI_COMMAND);

	/* Unmask all of the PCI IRQs */
	__raw_writel(SH4_PCIINTM_TTADIM  | SH4_PCIINTM_TMTOIM  | \
		     SH4_PCIINTM_MDEIM   | SH4_PCIINTM_APEDIM  | \
		     SH4_PCIINTM_SDIM    | SH4_PCIINTM_DPEITWM | \
		     SH4_PCIINTM_PEDITRM | SH4_PCIINTM_TADIMM  | \
		     SH4_PCIINTM_MADIMM  | SH4_PCIINTM_MWPDIM  | \
		     SH4_PCIINTM_MRDPEIM, chan->reg_base + SH4_PCIINTM);

	/*
	 * Disable the cache snoop controller for non-coherent DMA.
	 */
	__raw_writel(0, chan->reg_base + SH7780_PCICSCR0);
	__raw_writel(0, chan->reg_base + SH7780_PCICSAR0);
	__raw_writel(0, chan->reg_base + SH7780_PCICSCR1);
	__raw_writel(0, chan->reg_base + SH7780_PCICSAR1);

	__raw_writel(0xfd000000, chan->reg_base + SH7780_PCIMBR0);
	__raw_writel(0x00fc0000, chan->reg_base + SH7780_PCIMBMR0);

	__raw_writel(0, chan->reg_base + SH7780_PCIIOBR);
	__raw_writel(0, chan->reg_base + SH7780_PCIIOBMR);

	/*
	 * Initialization mode complete, release the control register and
	 * enable round robin mode to stop device overruns/starvation.
	 */
	__raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO,
		     chan->reg_base + SH4_PCICR);

	register_pci_controller(chan);

+7 −47
Original line number Diff line number Diff line
@@ -12,12 +12,11 @@
#ifndef _PCI_SH7780_H_
#define _PCI_SH7780_H_

/* Platform Specific Values */
#define SH7780_VENDOR_ID	0x1912
#define SH7781_DEVICE_ID	0x0001
#define SH7780_DEVICE_ID	0x0002
#define SH7763_DEVICE_ID	0x0004
#define SH7785_DEVICE_ID	0x0007
#define PCI_VENDOR_ID_RENESAS		0x1912
#define PCI_DEVICE_ID_RENESAS_SH7781	0x0001
#define PCI_DEVICE_ID_RENESAS_SH7780	0x0002
#define PCI_DEVICE_ID_RENESAS_SH7763	0x0004
#define PCI_DEVICE_ID_RENESAS_SH7785	0x0007

/* SH7780 Control Registers */
#define	PCIECR			0xFE000008
@@ -36,35 +35,6 @@
#define SH7780_PCIREG_BASE	0xFE040000	/* PCI regs base address */

/* SH7780 PCI Config Registers */
#define SH7780_PCIVID		0x000		/* Vendor ID */
#define SH7780_PCIDID		0x002		/* Device ID */
#define SH7780_PCICMD		0x004		/* Command */
#define SH7780_PCISTATUS	0x006		/* Status */
#define SH7780_PCIRID		0x008		/* Revision ID */
#define SH7780_PCIPIF		0x009		/* Program Interface */
#define SH7780_PCISUB		0x00a		/* Sub class code */
#define SH7780_PCIBCC		0x00b		/* Base class code */
#define SH7780_PCICLS		0x00c		/* Cache line size */
#define SH7780_PCILTM		0x00d		/* latency timer */
#define SH7780_PCIHDR		0x00e		/* Header type */
#define SH7780_PCIBIST		0x00f		/* BIST */
#define SH7780_PCIIBAR		0x010		/* IO Base address */
#define SH7780_PCIMBAR0		0x014		/* Memory base address0 */
#define SH7780_PCIMBAR1		0x018		/* Memory base address1 */
#define SH7780_PCISVID		0x02c		/* Sub system vendor ID */
#define SH7780_PCISID		0x02e		/* Sub system ID */
#define SH7780_PCICP		0x034
#define SH7780_PCIINTLINE	0x03c		/* Interrupt line */
#define SH7780_PCIINTPIN	0x03d		/* Interrupt pin */
#define SH7780_PCIMINGNT	0x03e		/* Minumum grand */
#define SH7780_PCIMAXLAT	0x03f		/* Maxmum latency */
#define SH7780_PCICID		0x040
#define SH7780_PCINIP		0x041
#define SH7780_PCIPMC		0x042
#define SH7780_PCIPMCSR		0x044
#define SH7780_PCIPMCSR_BSE	0x046
#define SH7780_PCICDD		0x047

#define SH7780_PCIIR		0x114		/* PCI Interrupt Register */
#define SH7780_PCIIMR		0x118		/* PCI Interrupt Mask Register */
#define SH7780_PCIAIR		0x11C		/* Error Address Register */
@@ -78,6 +48,8 @@

#define SH7780_PCIMBR0		0x1E0
#define SH7780_PCIMBMR0		0x1E4
#define SH7780_PCIMBR1		0x1E8
#define SH7780_PCIMBMR1		0x1EC
#define SH7780_PCIMBR2		0x1F0
#define SH7780_PCIMBMR2		0x1F4
#define SH7780_PCIIOBR		0x1F8
@@ -87,16 +59,4 @@
#define SH7780_PCICSAR0		0x218	/* Cache Snoop1 Addr. Register */
#define SH7780_PCICSAR1		0x21C	/* Cache Snoop2 Addr. Register */

/* General Memory Config Addresses */
#define SH7780_CS0_BASE_ADDR	0x0
#define SH7780_MEM_REGION_SIZE	0x04000000
#define SH7780_CS1_BASE_ADDR	(SH7780_CS0_BASE_ADDR + SH7780_MEM_REGION_SIZE)
#define SH7780_CS2_BASE_ADDR	(SH7780_CS1_BASE_ADDR + SH7780_MEM_REGION_SIZE)
#define SH7780_CS3_BASE_ADDR	(SH7780_CS2_BASE_ADDR + SH7780_MEM_REGION_SIZE)
#define SH7780_CS4_BASE_ADDR	(SH7780_CS3_BASE_ADDR + SH7780_MEM_REGION_SIZE)
#define SH7780_CS5_BASE_ADDR	(SH7780_CS4_BASE_ADDR + SH7780_MEM_REGION_SIZE)
#define SH7780_CS6_BASE_ADDR	(SH7780_CS5_BASE_ADDR + SH7780_MEM_REGION_SIZE)

#define SH7780_32BIT_DDR_BASE_ADDR	0x40000000

#endif /* _PCI_SH7780_H_ */