External Component on External Bus Interface


Introduction

The External Bus Interface is designed to ensure the successful data transfer between several external devices and the ARM processor-based device. The External Bus Interface of the device consists of a Static Memory Controller (SMC).

The SMC generates the signals that control the access to external memory devices or peripheral devices. It has 4 Chip Selects and a 26-bit address bus. The 16-bit data bus can be configured to interface with 8- or 16-bit external devices. Separate read and write control signals allow for direct memory and peripheral interfacing. Read and write signal waveforms are fully parametrizable.

A major rework of the NAND controller [1] involved the addition of an EBI driver [2], SMC helpers [3], and Device Tree bindings changes [4, 5, 6]. It took place from Linux v4.10 up to v4.13.

Instantiating Device on EBI bus

SMC timings

For previous kernel versions, the SMC configuration was set in the board files: https://elixir.bootlin.com/linux/v3.18/source/arch/arm/mach-at91/board-sam9261ek.c#L99 For boards with DT support only, it had to be set by bootloaders.

As a result of the NAND controller rework, the SMC timings are now defined in the DT. Here is a list of the SMC properties relevant for children device nodes connected on the EBI: https://elixir.bootlin.com/linux/v4.12/source/Documentation/devicetree/bindings/memory-controllers/atmel,ebi.txt#L35

Note: If the device is an ONFi compliant NAND memory, timings are automatically computed.

Address translation

When ready to set the reg property of a device connected to EBI, it may seem like magic due to the address translation mechanism. Let's continue and see how it works.

A ranges property is defined for the EBI. ranges is a list of address translations. Each entry contains the child bus address, the parent bus address, and the length. These fields depend on the child's #address-cells, the parent's #address-cells and the child's #size, respectively.

ebi: ebi@10000000 {
   compatible = "atmel,sama5d3-ebi";
   #address-cells = <2>;
   #size-cells = <1>;
   reg = <0x10000000 0x10000000
   0x60000000 0x28000000>;
   ranges = <0x0 0x0 0x10000000 0x10000000
        0x1 0x0 0x60000000 0x10000000
        0x2 0x0 0x70000000 0x10000000
        0x3 0x0 0x80000000 0x8000000>;
   [...]
};

It means that the two first cells of each entry of ranges are the child bus address, the third one is the parent bus address and the last one the length. The reg property of the child nodes contains the chip select id, the offset and the length of the memory region requested by the device.

To be crystal clear, the last entry in the ranges property can be interpreted this way, offset 0 from chip select 3 is mapped to address range 0x80000000...0x88000000.

Example

As an example, we are going to add an Ethernet MAC Controller on the EBI. The Ethernet MAC Controller is a KSZ8851-16MLL device [7, 8]. Its bindings are:

Required properties:
- compatible = "micrel,ks8851-mll" of parallel interface
- reg : 2 physical address and size of registers for data and command
- interrupts : interrupt connection

Its CSN signal is connected to NCS2 and its CMD signal connected to A1. So it has to be instantiated in this way:

&ebi {
   mac0@2,0 {
      compatible = "micrel,ks8851-mll";
      reg = <0x2 0x0 0x2
             0x2 0x2 0x2>;

      [...] /* pinctrl, interrupt, clock stuff */

      atmel,smc-read-mode = "nrd";
      atmel,smc-write-mode = "nwe";
      atmel,smc-bus-width = <16>;
      atmel,smc-ncs-rd-setup-ns = <20>;
      atmel,smc-ncs-rd-pulse-ns = <80>;
      atmel,smc-ncs-wr-setup-ns = <20>;
      atmel,smc-ncs-wr-pulse-ns = <80>;
      atmel,smc-tdf-ns = <12>;
      atmel,smc-nrd-pulse-ns = <80>;
      atmel,smc-nrd-cycle-ns = <120>;
      atmel,smc-nrd-setup-ns = <20>;
      atmel,smc-nwe-pulse-ns = <80>;
      atmel,smc-nwe-cycle-ns = <120>;
      atmel,smc-nwe-setup-ns = <20>;
   };
};

When the driver requests the resources, the translation is done automatically. 0x2 0x0 becomes =0x70000000= and 0x2 0x2 becomes =0x70000002= according to the 'ranges' property of the EBI node. Note that timings are not optimized.

[1] https://elixir.bootlin.com/linux/v4.14/source/drivers/mtd/nand/atmel/nand-controller.c

[2] https://elixir.bootlin.com/linux/v4.14/source/drivers/memory/atmel-ebi.c

[3] https://elixir.bootlin.com/linux/v4.14/source/drivers/mfd/atmel-smc.c

[4] https://elixir.bootlin.com/linux/v4.14/source/Documentation/devicetree/bindings/memory-controllers/atmel,ebi.txt

[5] https://elixir.bootlin.com/linux/v4.14/source/Documentation/devicetree/bindings/mfd/atmel-smc.txt

[6] https://elixir.bootlin.com/linux/v4.14/source/Documentation/devicetree/bindings/mtd/atmel-nand.txt

[7] https://microchip.com/wwwproducts/en/KSZ8851

[8] http://ww1.microchip.com/downloads/en/DeviceDoc/KSZ8851-16MLL-Single-Port-Ethernet-MAC-Controller-with-8-Bit-or-16-Bit-Non-PCI-Interface-DS00002357B.pdf