[PATCH V3 1/3] Add PCIe driver for Samsung Exynos

Jingoo Han jg1.han at samsung.com
Wed Jun 12 12:59:21 EST 2013


On Friday, June 07, 2013 7:53 PM, Arnd Bergmann wrote:
> On Friday 07 June 2013 18:22:50 Jingoo Han wrote:
> 
> > diff --git a/Documentation/devicetree/bindings/pci/exynos-pcie.txt
> b/Documentation/devicetree/bindings/pci/exynos-pcie.txt
> > new file mode 100644
> > index 0000000..3eb4a2d
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/pci/exynos-pcie.txt
> > @@ -0,0 +1,56 @@
> > +* Samsung Exynos PCIe interface
> > +
> > +Required properties:
> > +-compatible: should be "samsung,exynos5440-pcie"
> > +-reg: base addresses and lengths of the pcie conteroller,
> > +	additional register for the pcie controller,
> > +	the phy controller,
> > +	additional register for the phy controller.
> > +- interrupts: interrupt values for level interrupt,
> > +	pulse interrupt, special interrupt.
> > +- device_type, set to "pci"
> > +- bus-range: PCI bus numbers covered
> 
> Why is it that only a subset of bus numbers are used? Can't you address
> the entire range?

I will remove 'bus-range' property from DT.

> 
> > +- ranges: ranges for the PCI memory and I/O regions
> > +- reset-gpio: gpio pin number of power good signal
> 
> The 'reset-gpio' property seems incorrect. I think this should either
> use the gpio binding or the reset-controller binding. Specifying
> bare numbers to use as gpio pins does not work, since the number
> space for Linux internal gpio numbers is not necessarily the same
> as used by the hardware.

As you mentioned, other Exynos SoCs such as Exynos5250 set
GPIO properties in DT, as below:
(./arch/arm/boot/dts/exynos5250-smdk5250.dts)
	hdmi {
		hpd-gpio = <&gpx3 7 0>;
	};
	usb at 12110000 {
		samsung,vbus-gpio = <&gpx2 6 0>;
	};

However, the situation of Exynos5440 GPIO is different.
The following bare numbers of GPIO work properly on Exynos5440.
(./arch/arm/boot/dts/exynos5440-ssdk5440.dts)
	pcie0 at 40000000 {
		reset-gpio = <5>;
	}
	pcie0 at 40000000 {
		reset-gpio = <22>;
	}

Thomas Abraham is the author of pinctrl driver for EXYNOS5440.
(./drivers/pinctrl/pinctrl-exynos5440.c)

Thomas Abraham or Kukjin Kim, can you confirm this?
If I am wrong, please let me know kindly. :)


> 
> I think you also need an interrupt-map property as mandated by
> the PCI binding, in order to use legacy interrupts, as well as
> #address-cells and #size-cells.
> 
> > +       pcie0 at 40000000 {
> > +               compatible = "samsung,exynos5440-pcie";
> > +               reg = <0x40000000 0x4000
> > +                       0x290000 0x1000
> > +                       0x270000 0x1000
> > +                       0x271000 0x40>;
> > +               interrupts = <0 20 0>, <0 21 0>, <0 22 0>;
> > +               device_type = "pci";
> > +               bus-range = <0x0 0xf>;
> > +               ranges = <0x00000800 0 0x40000000 0x40000000 0 0x00200000   /* configuration space */
> > +                         0x81000000 0 0          0x40200000 0 0x00004000   /* downstream I/O */
> > +                         0x82000000 0 0          0x40204000 0 0x10000000>; /* non-prefetchable memory */
> > +       };
> > +
> > +       pcie1 at 60000000 {
> > +               compatible = "samsung,exynos5440-pcie";
> > +               reg = <0x60000000 0x4000
> > +                       0x2a0000 0x1000
> > +                       0x272000 0x1000
> > +                       0x271040 0x40>;
> > +               interrupts = <0 23 0>, <0 24 0>, <0 25 0>;
> > +               device_type = "pci";
> > +               bus-range = <0x0 0xf>;
> > +               ranges = <0x00000800 0 0x60000000 0x60000000 0 0x00200000   /* configuration space */
> > +                         0x81000000 0 0          0x60200000 0 0x00004000   /* downstream I/O */
> > +                         0x82000000 0 0          0x60204000 0 0x10000000>; /* non-prefetchable memory */
> > +       };
> 
> Is it intentional that in this example you set up both buses to
> have both memory and I/O space start at address 0 in bus space?

No, it is not intentional.
I will fix it.

> 
> I think it would be more logical to have non-overlapping addresses.
> You can also choose to have an identity mapping for memory
> space where a PCI bus address maps directly to the physical address
> used to access it, although that will prevent you from using legacy
> VGA cards that require the use of the low 16 MB.
> 
> Using a 16kb I/O space rather than a 64KB I/O space per port will
> lead to pci_ioremap_io() map the start of your memory space into
> PCI_IO_VIRT_BASE, which you probably didn't intend.
> 
> If your hardware cannot handle a full 64KB window, I would recommend
> to at least leave a hole before the start of the memory window.

OK, I see.
I will fix both MEM space and I/O space.

> 
> > +struct pcie_port {
> > +	struct device		*dev;
> > +	u8			controller;
> > +	u8			root_bus_nr;
> > +	void __iomem		*dbi_base;
> > +	void __iomem		*va_dbi_base;
> > +	void __iomem		*elbi_base;
> > +	void __iomem		*va_elbi_base;
> > +	void __iomem		*base;
> > +	void __iomem		*phy_base;
> > +	void __iomem		*va_phy_base;
> > +	void __iomem		*purple_base;
> > +	void __iomem		*va_purple_base;
> > +	void __iomem		*cfg0_base;
> > +	void __iomem		*va_cfg0_base;
> > +	void __iomem		*cfg1_base;
> > +	void __iomem		*va_cfg1_base;
> > +	void __iomem		*io_base;
> > +	void __iomem		*mem_base;
> > +	spinlock_t		conf_lock;
> > +	struct resource		io;
> > +	struct resource		mem;
> > +	struct resource		busn;
> 
> A lot of the fields above appear to be duplicated. If you
> pass a physical address, that needs to be a phys_addr_t,
> not void __iomem*. I think most of the physical addresses
> can be removed there, and you just keep the virtual addresses
> but drop the va_ prefix.

OK, I see.
I will use the 'phys_addr_t' and remove redundant physical
addresses.

> 
> > +static int add_pcie_port(struct pcie_port *pp, struct platform_device *pdev)
> > +{
> > +	struct resource *dbi_base;
> > +	struct resource *elbi_base;
> > +	struct resource *phy_base;
> > +	struct resource *purple_base;
> > +	int ret;
> > +
> > +	dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	if (!dbi_base) {
> > +		dev_err(&pdev->dev, "couldn't get dbi base resource\n");
> > +		return -EINVAL;
> > +	}
> > +	if (!devm_request_mem_region(&pdev->dev, dbi_base->start,
> > +				resource_size(dbi_base), pdev->name)) {
> > +		dev_err(&pdev->dev, "dbi base resource is busy\n");
> > +		return -EBUSY;
> > +	}
> > +	pp->dbi_base = (void __iomem *) (unsigned long)dbi_base->start;
> 
> That will also let you get rid of the casts here.

Yes, I will remove unnecessary casts.

> 
> 
> > +static int __exit exynos_pcie_remove(struct platform_device *pdev)
> > +{
> > +	return 0;
> > +}
> > +
> 
> an empty 'remove' function seems incorrect. I don't know what a
> removable PCI should be doing here, but at least you need to undo
> everything you set up in the probe function.

I will remove the empty 'remove' function.

Thank you for your comments. :)
I will fix it and send v4 patch, soon.


Best regards,
Jingoo Han

> 
> 
> 	Arnd



More information about the devicetree-discuss mailing list