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
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.
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
.
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