Orion NAS customisation guide

= About =

Up-to-date support for the Marvell Orion SoC is currently available in the Orion git repository (http://git.kernel.org/?p=linux/kernel/git/nico/orion.git). Some Orion SoCs support have been merged into mainline for 2.6.28, but Orion git is including some enhancements (and boards support) not yet merged into mainline kernel. A large number of NAS devices and some storage enabled routers are based on the Marvell Orion. General_NAS_customisation_guide contains general information about customising your NAS device, this article primarily focuses on getting kernel support for your device into the mainline kernel.

= Kernel Support =

Booting
Because there are many different boards using ARM based chips, a machine ID (known as a mach-type) is used to execute board specific setup code. Using this mechanism a single kernel can support a variety of different devices. When Marvell were creating the LSP (Linux Support Package) they decided to use a single mach-type for all of their boards and pass a board specific ATAG from U-Boot. This is the wrong thing to do for three reasons:
 * 1) They chose 0x20e as the mach-type which is already claimed by another device.
 * 2) Using ATAGs is just a different way of achieving the same thing as the mach-type identifier which has to be used initially anyway.
 * 3) The non-standard ATAG is not recognized by mainline kernels and this causes the memory detection to fail.

The first thing you will need to do is get a mach-type for your device, check http://www.arm.linux.org.uk/developer/machines/ and register it yourself if it is not already there. While it might seem strange registering a device you have no real association with this is perfectly acceptable. Add a line to the file arch/arm/tools/mach-types with the machine details. If you submit any patches do not include this file, it is updated regularly for you.

The board will always boot with 0x20e as the machine type since this is hard coded into U-Boot so you need some way to force it to use the new mach-type. The following patch will force the mach-type to 0x5e5 (Kurobox Pro). This works by prepending the 0xe3a01c05 and 0xe38110e5 instructions to the compressed image.

diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile index 25f1230..789190e 100644 --- a/arch/arm/boot/Makefile +++ b/arch/arm/boot/Makefile @@ -55,6 +55,10 @@ $(obj)/compressed/vmlinux: $(obj)/Image FORCE $(obj)/zImage:	$(obj)/compressed/vmlinux FORCE $(call if_changed,objcopy) +	devio > foo 'wl 0xe3a01c05,4' 'wl 0xe38110e5,4' +	cat foo $(obj)/zImage > zImage.new +	mv zImage.new $(obj)/zImage +	rm foo @echo ' Kernel: $@ is ready' endif

Board Setup
The easiest way to start is to copy an existing setup file from arch/arm/mach-orion5x/*-setup.c and add an entry to arch/arm/mach-orion5x/Makefile and arch/arm/mach-orion/Kconfig. Rename the functions/variables with a new device name and change the mach-type macros in the MACHINE_START macro. Remove device support for NOR/NAND flash, PCI/PCIE, GPIO keys, LED class drivers and any I2C devices. This should give you something that will boot.

Multiplexing Pins (the orion-git way)
The Orion SoC has twenty six multiplexing pins which are pins on the chip that can be assigned to different tasks. All of them can be GPIO pins and certain pins can be SATA presence/active, PCI interrupts/clocks, a second UART or NAND flash pins. There is no documentation that describes these functions that is not under NDA and even with this information you would need to know which MPP pin performs which function for your specific device.

The easiest way to get this information is to dump the values for the MPP pins from the stock kernel.

For such a thing, open the arch/arm/mach-mv88fxx81/Board/boardEnv/DB_88FXX81/mvBoardEnvSpec.h file from the stock kernel and find the board info related to your device. You'll find something like that in the definition (this example is taken from the Buffalo's Linkstation Pro kernel): {BUFFALO_BOARD_LS_GL_MPP0_7,			/* mpp0_7 */ BUFFALO_BOARD_LS_GL_MPP8_15,			/* mpp8_15 */ BUFFALO_BOARD_LS_GL_MPP16_23,			/* mpp16_23 */ BUFFALO_BOARD_LS_GL_MPP_DEV},			/* mppDev */ These are the values that are applied to the MPP configuration. Check the values corresponding :
 * 1) define BUFFALO_BOARD_LS_GL_MPP0_7    0x55220003
 * 2) define BUFFALO_BOARD_LS_GL_MPP8_15   0x55550000
 * 3) define BUFFALO_BOARD_LS_GL_MPP16_23  0x0
 * 4) define KUROBOX_BOARD_LS_GL_MPP_DEV   0x0

Sometimes, the MPP configuration that applies to your board is not clearly identified. To find which configuration is applied, check the kernel log and look for a line like : Marvell Development Board (LSP Version 1.7.801_NAS_MAXTOR)-- RD-88F5182-NAS-MXO then in the mvBoardEnvSpec.h, look for RD-88F5182-NAS-MXO (in this example). You'll find what you are looking for : "RD-88F5182-NAS-MXO",					/* boardName[MAX_BOARD_NAME_LEN] */ {RD_88F5182_2XSATA_MPP0_7,				/* mpp0_7 */ RD_88F5182_2XSATA_MPP8_15,				/* mpp8_15 */ RD_88F5182_2XSATA_MPP16_23,				/* mpp16_23 */ N_A},
 * 1) define RD_88F5182_2XSATA_INFO	{

Once identified, you'll have to write the corresponding code in your setup file. The setup file looks like that : static struct orion5x_mpp_mode board_mpp_modes[] __initdata = { { 0, MPP_CONFIGURATION0 }, { 1, MPP_CONFIGURATION1 }, ... 	{ 19, MPP_CONFIGURATION19 }, { -1 }, };

So, for example, this : BUFFALO_BOARD_LS_GL_MPP0_7    0x55220003 means that MPP0 has value 3, MPP1-3 have value 0, MPP4&MPP5 have value 2 ... Here is a table to figure out the configuration of a MPP (MPP_CONFIGURATIONx) depending of the assigned value : &sup1; MPPx=5 value not available on Marvell 88F5281 SoC ! &sup2; This MPP_UNUSED value is for Marvell 88f5281 SoC. Other SoC are using the value 5 for the MPP_UNUSED state.

Note that the "set as unused" value is often the same as the "set as GPIO" value, so it's up to you to know if a MPP is really used or not ... Also note that an "unused" MPP is equivalent to a MPP pin set as an output GPIO with the "0" value as output.

For example, this : BUFFALO_BOARD_LS_GL_MPP0_7    0x55220003 will be translated as orion5x_mpp_conf(0, MPP_GPIO); (or MPP_UNUSED) orion5x_mpp_conf(1, MPP_GPIO); (or MPP_UNUSED) orion5x_mpp_conf(2, MPP_GPIO); (or MPP_UNUSED) orion5x_mpp_conf(3, MPP_GPIO); (or MPP_UNUSED) orion5x_mpp_conf(4, MPP_PCI_ARB); orion5x_mpp_conf(5, MPP_PCI_ARB); orion5x_mpp_conf(6, MPP_SATA_LED); orion5x_mpp_conf(7, MPP_SATA_LED);

Interrupts MPP
If you check in the kernel configuration, you'll find a line marked as beeing intsGppMask. This line describes which MPP pins are configured as interrupts, you'll find PCI related interrupts, RTC chip related interrupt and any other interrupt used on your device. For example : ((1<<8)|(1<<9)|(1<<11)|(1<<12)|(1<<13)),   /* intsGppMask */ This means that MPP8, MPP9, MPP11, MPP12 and MPP13 are used as interrupt lines.

The RTC interrupt is easy to find as it's defined in the rtcIntPin field : 8,         /* rtcIntPin */ Check existing setup file to see how to configure RTC interrupt.

The PCI configuration is described in the next chapter.

Other interrupts are specific to your board, and you'll have to find by your own what they're used for.

PCI support
For PCI support, you need to know the slot offset and which MPP pins are used for the interrupts. Once you have this information look at a file such as ts209-setup.c for a device that supports both PCI and PCIE.

First, your should identify the IRQ lines used for PCI devices. For example : {{ {11, 12, 12, 13}},      /* pciSlot0 */ In this case MPP11, MPP12 and MPP13 are used as PCI Interrupts. Moreover the first PCI device (slot offset) number is 7 : {{0x7,        /* firstSlotDevNum */ You're now able to fill the "board_pci_preinit" function to initialize each interrupts. In this case, you should define the following parameters :
 * 1) define BOARD_PCI_SLOT0_OFFS			7	/* firstSlotDevNum */
 * 2) define BOARD_PCI_SLOT0_IRQ_PIN			11	/* PCI IntA */
 * 3) define BOARD_PCI_SLOT1_SLOT2_IRQ_PIN		12	/* PCI IntB&C */
 * 4) define BOARD_PCI_SLOT3_IRQ_PIN			13	/* PCI IntD */

Then fill the "board_pci_preinit" function to return the correct IRQ for each PCI slot. In this case it should be something like : /* * PCI IRQs are connected via GPIOs. */ switch (slot - BOARD_PCI_SLOT0_OFFS) { case 0: return gpio_to_irq(BOARD_PCI_SLOT0_IRQ_PIN); case 1: case 2: return gpio_to_irq(BOARD_PCI_SLOT1_SLOT2_IRQ_PIN); case 3: return gpio_to_irq(BOARD_PCI_SLOT3_IRQ_PIN); default: return -1; }

PCIE support
Only some Orion boards support PCIE but it does not rely on any of the MPP pins so enabling this is simple. For an example of a board that uses PCIE only look at kurobox_pro-setup.c.

NOR Flash
To setup the NOR flash you will need the partition layout for your device. This can usually be found by running dmesg or by watching the serial output as the stock kernel boots. From the information you can calculate the size and offset of each partition and put it into a struct mtd_partition. It is recommended that you keep the layout in the same order so you can use the stock firmware with the latest kernel.

NAND Flash
Similar to NOR flash you will need the layout information so you can put this into another struct mtd_partition

You can get the NAND flash memory mapping that apply to your device from the stock kernel of your device.

For example, in the Kurobox-Pro stock kernel, the mapping is defined in the arch\arm\mach-mv88fxx81\lsp\nand.c file : static struct mtd_partition parts_info[] = { { .name = "uImage", .offset = 0, .size = 4 * 1024 * 1024 }, { .name = "rootfs", .offset = MTDPART_OFS_NXTBLK, .size = 64 * 1024 * 1024 }, { .name = "extra", .offset = MTDPART_OFS_NXTBLK, .size = MTDPART_SIZ_FULL }, }; This is become in mach-orion setup file : static struct mtd_partition kurobox_pro_nand_parts[] = { { 	 	.name   = "uImage", .offset = 0, .size  = SZ_4M, }, 	{ 	 	.name  = "rootfs", .offset = SZ_4M, .size  = SZ_64M, }, 	{ 	 	.name  = "extra", .offset = SZ_4M + SZ_64M, .size  = SZ_256M - (SZ_4M + SZ_64M), }, };

SATA support
Devices with a 88f5182 SoC are using the internal 2xSATA controller (so you'll need to initialize it in the setup file). The internal SATA controller is using sata_mv driver. 88F5281 based devices, such as the QNAP TS-209, use an external SATA controller connected over PCI or PCIE (as the 88F5281 have no internal SATA controller). In this case, there is nothing special to do in the setup file (apart from correctly initializing PCI/PCIE bus) Most 88F5281 devices are using a Marvell 88SX6042 (PCI) or a Marvell 88SX7042 (PCIE) (using sata_mv driver too), but few devices are using a different controller (like the Synology DS107+ using a Silicon Image SATA controller).

Ethernet support
If you check in the kernel configuration, you'll find a line marked as beeing ethPhyAddr[MV_BOARD_MAX_PORTS]. This line describes what Phy address you'll have to correctly configure ethernet chip. For example : {0x8},        /* ethPhyAddr[MV_BOARD_MAX_PORTS] */ means that the Phy address of your chip is 0. In your setup file, you'll then have to set the ethernet initialization code to : static struct device_eth_platform_data board_eth_data = { .phy_addr	= 8, .force_phy_addr	= 1, }; note that "force_phy_addr = 1" is only needed if phy_addr is set to 0 (for every other values, just don't add the force_phy_addr field).

= Shutdown support =

Most of the boards are using various ways to shutdown, here are the known methods :
 * Using a GPIO output
 * Sending a command to a PIC/AVR over UART1
 * Just rebooting (U-Boot then put the board in a state close to a shutdown and will wait for a power on)
 * Using a CPLD

Check existing setup files to see how the setup code deals with various cases.

= PIC/AVR Micro-controller Support =

Most devices contain a micro-controller which some or all of the LEDs and buttons are connected to. This allows greater control over power management of the device and increases the number of GPIO pins for other purposes. The micro-controller also generally has a temperature sensor, a fan output and a buzzer output. The only device I know of that does not contain a micro-controller is the D-Link DNS-323.

The micro-controller normally communicates with the SoC over its second UART (MPP 16/17). The baud rate and commands vary between the different manufacturers and models. To get a device to power off when it is shutdown you will have to write a shutdown function in the board setup file that will write the appropriate command to the serial port on shutdown. For an example of this see arch/arm/mach-orion/ts209-setup.c.

Some devices (Kurobox Pro and Linkstation Pro) have an output connected to a GPIO line that is used as an interrupt when one of the buttons is pressed. This is not necessarily required for the buttons to function so the of the micro-controller functionality can be controlled from userspace.

How do we find the baud rate and command codes without documentation from the manufacturer?