code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * arch/arm/mach-orion5x/common.c
 *
 * Core functions for Marvell Orion 5x SoCs
 *
 * Maintainer: Tzachi Perelstein <tzachi@marvell.com>
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/serial_8250.h>
#include <linux/mv643xx_i2c.h>
#include <linux/ata_platform.h>
#include <linux/delay.h>
#include <linux/clk-provider.h>
#include <linux/cpu.h>
#include <linux/platform_data/dsa.h>
#include <asm/page.h>
#include <asm/setup.h>
#include <asm/system_misc.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
#include <linux/platform_data/mtd-orion_nand.h>
#include <linux/platform_data/usb-ehci-orion.h>
#include <plat/time.h>
#include <plat/common.h>

#include "bridge-regs.h"
#include "common.h"
#include "orion5x.h"

/*****************************************************************************
 * I/O Address Mapping
 ****************************************************************************/
static struct map_desc orion5x_io_desc[] __initdata = {
	{
		.virtual	= (unsigned long) ORION5X_REGS_VIRT_BASE,
		.pfn		= __phys_to_pfn(ORION5X_REGS_PHYS_BASE),
		.length		= ORION5X_REGS_SIZE,
		.type		= MT_DEVICE,
	}, {
		.virtual	= (unsigned long) ORION5X_PCIE_WA_VIRT_BASE,
		.pfn		= __phys_to_pfn(ORION5X_PCIE_WA_PHYS_BASE),
		.length		= ORION5X_PCIE_WA_SIZE,
		.type		= MT_DEVICE,
	},
};

void __init orion5x_map_io(void)
{
	iotable_init(orion5x_io_desc, ARRAY_SIZE(orion5x_io_desc));
}

/*****************************************************************************
 * CLK tree
 ****************************************************************************/
static struct clk *tclk;

void __init clk_init(void)
{
	tclk = clk_register_fixed_rate(NULL, "tclk", NULL, 0, orion5x_tclk);

	orion_clkdev_init(tclk);
}

/*****************************************************************************
 * EHCI0
 ****************************************************************************/
void __init orion5x_ehci0_init(void)
{
	orion_ehci_init(ORION5X_USB0_PHYS_BASE, IRQ_ORION5X_USB0_CTRL,
			EHCI_PHY_ORION);
}

/*****************************************************************************
 * EHCI1
 ****************************************************************************/
void __init orion5x_ehci1_init(void)
{
	orion_ehci_1_init(ORION5X_USB1_PHYS_BASE, IRQ_ORION5X_USB1_CTRL);
}

/*****************************************************************************
 * GE00
 ****************************************************************************/
void __init orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data)
{
	orion_ge00_init(eth_data,
			ORION5X_ETH_PHYS_BASE, IRQ_ORION5X_ETH_SUM,
			IRQ_ORION5X_ETH_ERR,
			MV643XX_TX_CSUM_DEFAULT_LIMIT);
}

/*****************************************************************************
 * Ethernet switch
 ****************************************************************************/
void __init orion5x_eth_switch_init(struct dsa_chip_data *d)
{
	orion_ge00_switch_init(d);
}

/*****************************************************************************
 * I2C
 ****************************************************************************/
void __init orion5x_i2c_init(void)
{
	orion_i2c_init(I2C_PHYS_BASE, IRQ_ORION5X_I2C, 8);

}

/*****************************************************************************
 * SATA
 ****************************************************************************/
void __init orion5x_sata_init(struct mv_sata_platform_data *sata_data)
{
	orion_sata_init(sata_data, ORION5X_SATA_PHYS_BASE, IRQ_ORION5X_SATA);
}

/*****************************************************************************
 * SPI
 ****************************************************************************/
void __init orion5x_spi_init(void)
{
	orion_spi_init(SPI_PHYS_BASE);
}

/*****************************************************************************
 * UART0
 ****************************************************************************/
void __init orion5x_uart0_init(void)
{
	orion_uart0_init(UART0_VIRT_BASE, UART0_PHYS_BASE,
			 IRQ_ORION5X_UART0, tclk);
}

/*****************************************************************************
 * UART1
 ****************************************************************************/
void __init orion5x_uart1_init(void)
{
	orion_uart1_init(UART1_VIRT_BASE, UART1_PHYS_BASE,
			 IRQ_ORION5X_UART1, tclk);
}

/*****************************************************************************
 * XOR engine
 ****************************************************************************/
void __init orion5x_xor_init(void)
{
	orion_xor0_init(ORION5X_XOR_PHYS_BASE,
			ORION5X_XOR_PHYS_BASE + 0x200,
			IRQ_ORION5X_XOR0, IRQ_ORION5X_XOR1);
}

/*****************************************************************************
 * Cryptographic Engines and Security Accelerator (CESA)
 ****************************************************************************/
static void __init orion5x_crypto_init(void)
{
	mvebu_mbus_add_window_by_id(ORION_MBUS_SRAM_TARGET,
				    ORION_MBUS_SRAM_ATTR,
				    ORION5X_SRAM_PHYS_BASE,
				    ORION5X_SRAM_SIZE);
	orion_crypto_init(ORION5X_CRYPTO_PHYS_BASE, ORION5X_SRAM_PHYS_BASE,
			  SZ_8K, IRQ_ORION5X_CESA);
}

/*****************************************************************************
 * Watchdog
 ****************************************************************************/
static struct resource orion_wdt_resource[] = {
		DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x04),
		DEFINE_RES_MEM(RSTOUTn_MASK_PHYS, 0x04),
};

static struct platform_device orion_wdt_device = {
	.name		= "orion_wdt",
	.id		= -1,
	.num_resources	= ARRAY_SIZE(orion_wdt_resource),
	.resource	= orion_wdt_resource,
};

static void __init orion5x_wdt_init(void)
{
	platform_device_register(&orion_wdt_device);
}

/*****************************************************************************
 * Time handling
 ****************************************************************************/
void __init orion5x_init_early(void)
{
	u32 rev, dev;
	const char *mbus_soc_name;

	orion_time_set_base(TIMER_VIRT_BASE);

	/* Initialize the MBUS driver */
	orion5x_pcie_id(&dev, &rev);
	if (dev == MV88F5281_DEV_ID)
		mbus_soc_name = "marvell,orion5x-88f5281-mbus";
	else if (dev == MV88F5182_DEV_ID)
		mbus_soc_name = "marvell,orion5x-88f5182-mbus";
	else if (dev == MV88F5181_DEV_ID)
		mbus_soc_name = "marvell,orion5x-88f5181-mbus";
	else if (dev == MV88F6183_DEV_ID)
		mbus_soc_name = "marvell,orion5x-88f6183-mbus";
	else
		mbus_soc_name = NULL;
	mvebu_mbus_init(mbus_soc_name, ORION5X_BRIDGE_WINS_BASE,
			ORION5X_BRIDGE_WINS_SZ,
			ORION5X_DDR_WINS_BASE, ORION5X_DDR_WINS_SZ);
}

void orion5x_setup_wins(void)
{
	/*
	 * The PCIe windows will no longer be statically allocated
	 * here once Orion5x is migrated to the pci-mvebu driver.
	 */
	mvebu_mbus_add_window_remap_by_id(ORION_MBUS_PCIE_IO_TARGET,
					  ORION_MBUS_PCIE_IO_ATTR,
					  ORION5X_PCIE_IO_PHYS_BASE,
					  ORION5X_PCIE_IO_SIZE,
					  ORION5X_PCIE_IO_BUS_BASE);
	mvebu_mbus_add_window_by_id(ORION_MBUS_PCIE_MEM_TARGET,
				    ORION_MBUS_PCIE_MEM_ATTR,
				    ORION5X_PCIE_MEM_PHYS_BASE,
				    ORION5X_PCIE_MEM_SIZE);
	mvebu_mbus_add_window_remap_by_id(ORION_MBUS_PCI_IO_TARGET,
					  ORION_MBUS_PCI_IO_ATTR,
					  ORION5X_PCI_IO_PHYS_BASE,
					  ORION5X_PCI_IO_SIZE,
					  ORION5X_PCI_IO_BUS_BASE);
	mvebu_mbus_add_window_by_id(ORION_MBUS_PCI_MEM_TARGET,
				    ORION_MBUS_PCI_MEM_ATTR,
				    ORION5X_PCI_MEM_PHYS_BASE,
				    ORION5X_PCI_MEM_SIZE);
}

int orion5x_tclk;

static int __init orion5x_find_tclk(void)
{
	u32 dev, rev;

	orion5x_pcie_id(&dev, &rev);
	if (dev == MV88F6183_DEV_ID &&
	    (readl(MPP_RESET_SAMPLE) & 0x00000200) == 0)
		return 133333333;

	return 166666667;
}

void __init orion5x_timer_init(void)
{
	orion5x_tclk = orion5x_find_tclk();

	orion_time_init(ORION5X_BRIDGE_VIRT_BASE, BRIDGE_INT_TIMER1_CLR,
			IRQ_ORION5X_BRIDGE, orion5x_tclk);
}

/*****************************************************************************
 * General
 ****************************************************************************/
/*
 * Identify device ID and rev from PCIe configuration header space '0'.
 */
void __init orion5x_id(u32 *dev, u32 *rev, char **dev_name)
{
	orion5x_pcie_id(dev, rev);

	if (*dev == MV88F5281_DEV_ID) {
		if (*rev == MV88F5281_REV_D2) {
			*dev_name = "MV88F5281-D2";
		} else if (*rev == MV88F5281_REV_D1) {
			*dev_name = "MV88F5281-D1";
		} else if (*rev == MV88F5281_REV_D0) {
			*dev_name = "MV88F5281-D0";
		} else {
			*dev_name = "MV88F5281-Rev-Unsupported";
		}
	} else if (*dev == MV88F5182_DEV_ID) {
		if (*rev == MV88F5182_REV_A2) {
			*dev_name = "MV88F5182-A2";
		} else {
			*dev_name = "MV88F5182-Rev-Unsupported";
		}
	} else if (*dev == MV88F5181_DEV_ID) {
		if (*rev == MV88F5181_REV_B1) {
			*dev_name = "MV88F5181-Rev-B1";
		} else if (*rev == MV88F5181L_REV_A1) {
			*dev_name = "MV88F5181L-Rev-A1";
		} else {
			*dev_name = "MV88F5181(L)-Rev-Unsupported";
		}
	} else if (*dev == MV88F6183_DEV_ID) {
		if (*rev == MV88F6183_REV_B0) {
			*dev_name = "MV88F6183-Rev-B0";
		} else {
			*dev_name = "MV88F6183-Rev-Unsupported";
		}
	} else {
		*dev_name = "Device-Unknown";
	}
}

void __init orion5x_init(void)
{
	char *dev_name;
	u32 dev, rev;

	orion5x_id(&dev, &rev, &dev_name);
	printk(KERN_INFO "Orion ID: %s. TCLK=%d.\n", dev_name, orion5x_tclk);

	/*
	 * Setup Orion address map
	 */
	orion5x_setup_wins();

	/* Setup root of clk tree */
	clk_init();

	/*
	 * Don't issue "Wait for Interrupt" instruction if we are
	 * running on D0 5281 silicon.
	 */
	if (dev == MV88F5281_DEV_ID && rev == MV88F5281_REV_D0) {
		printk(KERN_INFO "Orion: Applying 5281 D0 WFI workaround.\n");
		cpu_idle_poll_ctrl(true);
	}

	/*
	 * The 5082/5181l/5182/6082/6082l/6183 have crypto
	 * while 5180n/5181/5281 don't have crypto.
	 */
	if ((dev == MV88F5181_DEV_ID && rev >= MV88F5181L_REV_A0) ||
	    dev == MV88F5182_DEV_ID || dev == MV88F6183_DEV_ID)
		orion5x_crypto_init();

	/*
	 * Register watchdog driver
	 */
	orion5x_wdt_init();
}

void orion5x_restart(enum reboot_mode mode, const char *cmd)
{
	/*
	 * Enable and issue soft reset
	 */
	orion5x_setbits(RSTOUTn_MASK, (1 << 2));
	orion5x_setbits(CPU_SOFT_RESET, 1);
	mdelay(200);
	orion5x_clrbits(CPU_SOFT_RESET, 1);
}

/*
 * Many orion-based systems have buggy bootloader implementations.
 * This is a common fixup for bogus memory tags.
 */
void __init tag_fixup_mem32(struct tag *t, char **from)
{
	for (; t->hdr.size; t = tag_next(t))
		if (t->hdr.tag == ATAG_MEM &&
		    (!t->u.mem.size || t->u.mem.size & ~PAGE_MASK ||
		     t->u.mem.start & ~PAGE_MASK)) {
			printk(KERN_WARNING
			       "Clearing invalid memory bank %dKB@0x%08x\n",
			       t->u.mem.size / 1024, t->u.mem.start);
			t->hdr.tag = 0;
		}
}


code:
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ARCH_ORION5X_COMMON_H
#define __ARCH_ORION5X_COMMON_H

#include <linux/reboot.h>

struct dsa_chip_data;
struct mv643xx_eth_platform_data;
struct mv_sata_platform_data;

#define ORION_MBUS_PCIE_MEM_TARGET    0x04
#define ORION_MBUS_PCIE_MEM_ATTR      0x59
#define ORION_MBUS_PCIE_IO_TARGET     0x04
#define ORION_MBUS_PCIE_IO_ATTR       0x51
#define ORION_MBUS_PCIE_WA_TARGET     0x04
#define ORION_MBUS_PCIE_WA_ATTR       0x79
#define ORION_MBUS_PCI_MEM_TARGET     0x03
#define ORION_MBUS_PCI_MEM_ATTR       0x59
#define ORION_MBUS_PCI_IO_TARGET      0x03
#define ORION_MBUS_PCI_IO_ATTR        0x51
#define ORION_MBUS_DEVBUS_BOOT_TARGET 0x01
#define ORION_MBUS_DEVBUS_BOOT_ATTR   0x0f
#define ORION_MBUS_DEVBUS_TARGET(cs)  0x01
#define ORION_MBUS_DEVBUS_ATTR(cs)    (~(1 << cs))
#define ORION_MBUS_SRAM_TARGET        0x09
#define ORION_MBUS_SRAM_ATTR          0x00

/*
 * Basic Orion init functions used early by machine-setup.
 */
void orion5x_map_io(void);
void orion5x_init_early(void);
void orion5x_init_irq(void);
void orion5x_init(void);
void orion5x_id(u32 *dev, u32 *rev, char **dev_name);
void clk_init(void);
extern int orion5x_tclk;
extern void orion5x_timer_init(void);

void orion5x_setup_wins(void);

void orion5x_ehci0_init(void);
void orion5x_ehci1_init(void);
void orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data);
void orion5x_eth_switch_init(struct dsa_chip_data *d);
void orion5x_i2c_init(void);
void orion5x_sata_init(struct mv_sata_platform_data *sata_data);
void orion5x_spi_init(void);
void orion5x_uart0_init(void);
void orion5x_uart1_init(void);
void orion5x_xor_init(void);
void orion5x_restart(enum reboot_mode, const char *);

/*
 * PCIe/PCI functions.
 */
struct pci_bus;
struct pci_host_bridge;
struct pci_sys_data;
struct pci_dev;

void orion5x_pcie_id(u32 *dev, u32 *rev);
void orion5x_pci_disable(void);
void orion5x_pci_set_cardbus_mode(void);
int orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys);
int orion5x_pci_sys_scan_bus(int nr, struct pci_host_bridge *bridge);
int orion5x_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);

struct tag;
extern void __init tag_fixup_mem32(struct tag *, char **);

#ifdef CONFIG_MACH_MSS2_DT
extern void mss2_init(void);
#else
static inline void mss2_init(void) {}
#endif

/*****************************************************************************
 * Helpers to access Orion registers
 ****************************************************************************/
/*
 * These are not preempt-safe.  Locks, if needed, must be taken
 * care of by the caller.
 */
#define orion5x_setbits(r, mask)	writel(readl(r) | (mask), (r))
#define orion5x_clrbits(r, mask)	writel(readl(r) & ~(mask), (r))

#endif

repo_name: angery/linux


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * arch/arm/mach-orion5x/db88f5281-setup.c
 *
 * Marvell Orion-2 Development Board Setup
 *
 * Maintainer: Tzachi Perelstein <tzachi@marvell.com>
 */
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/pci.h>
#include <linux/irq.h>
#include <linux/mtd/physmap.h>
#include <linux/mtd/rawnand.h>
#include <linux/timer.h>
#include <linux/mv643xx_eth.h>
#include <linux/i2c.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/pci.h>
#include <linux/platform_data/mtd-orion_nand.h>
#include "common.h"
#include "mpp.h"
#include "orion5x.h"

/*****************************************************************************
 * DB-88F5281 on board devices
 ****************************************************************************/

/*
 * 512K NOR flash Device bus boot chip select
 */

#define DB88F5281_NOR_BOOT_BASE		0xf4000000
#define DB88F5281_NOR_BOOT_SIZE		SZ_512K

/*
 * 7-Segment on Device bus chip select 0
 */

#define DB88F5281_7SEG_BASE		0xfa000000
#define DB88F5281_7SEG_SIZE		SZ_1K

/*
 * 32M NOR flash on Device bus chip select 1
 */

#define DB88F5281_NOR_BASE		0xfc000000
#define DB88F5281_NOR_SIZE		SZ_32M

/*
 * 32M NAND flash on Device bus chip select 2
 */

#define DB88F5281_NAND_BASE		0xfa800000
#define DB88F5281_NAND_SIZE		SZ_1K

/*
 * PCI
 */

#define DB88F5281_PCI_SLOT0_OFFS		7
#define DB88F5281_PCI_SLOT0_IRQ_PIN		12
#define DB88F5281_PCI_SLOT1_SLOT2_IRQ_PIN	13

/*****************************************************************************
 * 512M NOR Flash on Device bus Boot CS
 ****************************************************************************/

static struct physmap_flash_data db88f5281_boot_flash_data = {
	.width		= 1,	/* 8 bit bus width */
};

static struct resource db88f5281_boot_flash_resource = {
	.flags		= IORESOURCE_MEM,
	.start		= DB88F5281_NOR_BOOT_BASE,
	.end		= DB88F5281_NOR_BOOT_BASE + DB88F5281_NOR_BOOT_SIZE - 1,
};

static struct platform_device db88f5281_boot_flash = {
	.name		= "physmap-flash",
	.id		= 0,
	.dev		= {
		.platform_data	= &db88f5281_boot_flash_data,
	},
	.num_resources	= 1,
	.resource	= &db88f5281_boot_flash_resource,
};

/*****************************************************************************
 * 32M NOR Flash on Device bus CS1
 ****************************************************************************/

static struct physmap_flash_data db88f5281_nor_flash_data = {
	.width		= 4,	/* 32 bit bus width */
};

static struct resource db88f5281_nor_flash_resource = {
	.flags		= IORESOURCE_MEM,
	.start		= DB88F5281_NOR_BASE,
	.end		= DB88F5281_NOR_BASE + DB88F5281_NOR_SIZE - 1,
};

static struct platform_device db88f5281_nor_flash = {
	.name		= "physmap-flash",
	.id		= 1,
	.dev		= {
		.platform_data	= &db88f5281_nor_flash_data,
	},
	.num_resources	= 1,
	.resource	= &db88f5281_nor_flash_resource,
};

/*****************************************************************************
 * 32M NAND Flash on Device bus CS2
 ****************************************************************************/

static struct mtd_partition db88f5281_nand_parts[] = {
	{
		.name = "kernel",
		.offset = 0,
		.size = SZ_2M,
	}, {
		.name = "root",
		.offset = SZ_2M,
		.size = (SZ_16M - SZ_2M),
	}, {
		.name = "user",
		.offset = SZ_16M,
		.size = SZ_8M,
	}, {
		.name = "recovery",
		.offset = (SZ_16M + SZ_8M),
		.size = SZ_8M,
	},
};

static struct resource db88f5281_nand_resource = {
	.flags		= IORESOURCE_MEM,
	.start		= DB88F5281_NAND_BASE,
	.end		= DB88F5281_NAND_BASE + DB88F5281_NAND_SIZE - 1,
};

static struct orion_nand_data db88f5281_nand_data = {
	.parts		= db88f5281_nand_parts,
	.nr_parts	= ARRAY_SIZE(db88f5281_nand_parts),
	.cle		= 0,
	.ale		= 1,
	.width		= 8,
};

static struct platform_device db88f5281_nand_flash = {
	.name		= "orion_nand",
	.id		= -1,
	.dev		= {
		.platform_data	= &db88f5281_nand_data,
	},
	.resource	= &db88f5281_nand_resource,
	.num_resources	= 1,
};

/*****************************************************************************
 * 7-Segment on Device bus CS0
 * Dummy counter every 2 sec
 ****************************************************************************/

static void __iomem *db88f5281_7seg;
static struct timer_list db88f5281_timer;

static void db88f5281_7seg_event(struct timer_list *unused)
{
	static int count = 0;
	writel(0, db88f5281_7seg + (count << 4));
	count = (count + 1) & 7;
	mod_timer(&db88f5281_timer, jiffies + 2 * HZ);
}

static int __init db88f5281_7seg_init(void)
{
	if (machine_is_db88f5281()) {
		db88f5281_7seg = ioremap(DB88F5281_7SEG_BASE,
					DB88F5281_7SEG_SIZE);
		if (!db88f5281_7seg) {
			printk(KERN_ERR "Failed to ioremap db88f5281_7seg\n");
			return -EIO;
		}
		timer_setup(&db88f5281_timer, db88f5281_7seg_event, 0);
		mod_timer(&db88f5281_timer, jiffies + 2 * HZ);
	}

	return 0;
}

__initcall(db88f5281_7seg_init);

/*****************************************************************************
 * PCI
 ****************************************************************************/

static void __init db88f5281_pci_preinit(void)
{
	int pin;

	/*
	 * Configure PCI GPIO IRQ pins
	 */
	pin = DB88F5281_PCI_SLOT0_IRQ_PIN;
	if (gpio_request(pin, "PCI Int1") == 0) {
		if (gpio_direction_input(pin) == 0) {
			irq_set_irq_type(gpio_to_irq(pin), IRQ_TYPE_LEVEL_LOW);
		} else {
			printk(KERN_ERR "db88f5281_pci_preinit failed to "
					"set_irq_type pin %d\n", pin);
			gpio_free(pin);
		}
	} else {
		printk(KERN_ERR "db88f5281_pci_preinit failed to gpio_request %d\n", pin);
	}

	pin = DB88F5281_PCI_SLOT1_SLOT2_IRQ_PIN;
	if (gpio_request(pin, "PCI Int2") == 0) {
		if (gpio_direction_input(pin) == 0) {
			irq_set_irq_type(gpio_to_irq(pin), IRQ_TYPE_LEVEL_LOW);
		} else {
			printk(KERN_ERR "db88f5281_pci_preinit failed "
					"to set_irq_type pin %d\n", pin);
			gpio_free(pin);
		}
	} else {
		printk(KERN_ERR "db88f5281_pci_preinit failed to gpio_request %d\n", pin);
	}
}

static int __init db88f5281_pci_map_irq(const struct pci_dev *dev, u8 slot,
	u8 pin)
{
	int irq;

	/*
	 * Check for devices with hard-wired IRQs.
	 */
	irq = orion5x_pci_map_irq(dev, slot, pin);
	if (irq != -1)
		return irq;

	/*
	 * PCI IRQs are connected via GPIOs.
	 */
	switch (slot - DB88F5281_PCI_SLOT0_OFFS) {
	case 0:
		return gpio_to_irq(DB88F5281_PCI_SLOT0_IRQ_PIN);
	case 1:
	case 2:
		return gpio_to_irq(DB88F5281_PCI_SLOT1_SLOT2_IRQ_PIN);
	default:
		return -1;
	}
}

static struct hw_pci db88f5281_pci __initdata = {
	.nr_controllers	= 2,
	.preinit	= db88f5281_pci_preinit,
	.setup		= orion5x_pci_sys_setup,
	.scan		= orion5x_pci_sys_scan_bus,
	.map_irq	= db88f5281_pci_map_irq,
};

static int __init db88f5281_pci_init(void)
{
	if (machine_is_db88f5281())
		pci_common_init(&db88f5281_pci);

	return 0;
}

subsys_initcall(db88f5281_pci_init);

/*****************************************************************************
 * Ethernet
 ****************************************************************************/
static struct mv643xx_eth_platform_data db88f5281_eth_data = {
	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
};

/*****************************************************************************
 * RTC DS1339 on I2C bus
 ****************************************************************************/
static struct i2c_board_info __initdata db88f5281_i2c_rtc = {
	I2C_BOARD_INFO("ds1339", 0x68),
};

/*****************************************************************************
 * General Setup
 ****************************************************************************/
static unsigned int db88f5281_mpp_modes[] __initdata = {
	MPP0_GPIO,		/* USB Over Current */
	MPP1_GPIO,		/* USB Vbat input */
	MPP2_PCI_ARB,		/* PCI_REQn[2] */
	MPP3_PCI_ARB,		/* PCI_GNTn[2] */
	MPP4_PCI_ARB,		/* PCI_REQn[3] */
	MPP5_PCI_ARB,		/* PCI_GNTn[3] */
	MPP6_GPIO,		/* JP0, CON17.2 */
	MPP7_GPIO,		/* JP1, CON17.1 */
	MPP8_GPIO,		/* JP2, CON11.2 */
	MPP9_GPIO,		/* JP3, CON11.3 */
	MPP10_GPIO,		/* RTC int */
	MPP11_GPIO,		/* Baud Rate Generator */
	MPP12_GPIO,		/* PCI int 1 */
	MPP13_GPIO,		/* PCI int 2 */
	MPP14_NAND,		/* NAND_REn[2] */
	MPP15_NAND,		/* NAND_WEn[2] */
	MPP16_UART,		/* UART1_RX */
	MPP17_UART,		/* UART1_TX */
	MPP18_UART,		/* UART1_CTSn */
	MPP19_UART,		/* UART1_RTSn */
	0,
};

static void __init db88f5281_init(void)
{
	/*
	 * Basic Orion setup. Need to be called early.
	 */
	orion5x_init();

	orion5x_mpp_conf(db88f5281_mpp_modes);
	writel(0, MPP_DEV_CTRL);		/* DEV_D[31:16] */

	/*
	 * Configure peripherals.
	 */
	orion5x_ehci0_init();
	orion5x_eth_init(&db88f5281_eth_data);
	orion5x_i2c_init();
	orion5x_uart0_init();
	orion5x_uart1_init();

	mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_BOOT_TARGET,
				    ORION_MBUS_DEVBUS_BOOT_ATTR,
				    DB88F5281_NOR_BOOT_BASE,
				    DB88F5281_NOR_BOOT_SIZE);
	platform_device_register(&db88f5281_boot_flash);

	mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_TARGET(0),
				    ORION_MBUS_DEVBUS_ATTR(0),
				    DB88F5281_7SEG_BASE,
				    DB88F5281_7SEG_SIZE);

	mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_TARGET(1),
				    ORION_MBUS_DEVBUS_ATTR(1),
				    DB88F5281_NOR_BASE,
				    DB88F5281_NOR_SIZE);
	platform_device_register(&db88f5281_nor_flash);

	mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_TARGET(2),
				    ORION_MBUS_DEVBUS_ATTR(2),
				    DB88F5281_NAND_BASE,
				    DB88F5281_NAND_SIZE);
	platform_device_register(&db88f5281_nand_flash);

	i2c_register_board_info(0, &db88f5281_i2c_rtc, 1);
}

MACHINE_START(DB88F5281, "Marvell Orion-2 Development Board")
	/* Maintainer: Tzachi Perelstein <tzachi@marvell.com> */
	.atag_offset	= 0x100,
	.nr_irqs	= ORION5X_NR_IRQS,
	.init_machine	= db88f5281_init,
	.map_io		= orion5x_map_io,
	.init_early	= orion5x_init_early,
	.init_irq	= orion5x_init_irq,
	.init_time	= orion5x_timer_init,
	.restart	= orion5x_restart,
MACHINE_END


code:
/*
 * arch/arm/mach-orion5x/dns323-setup.c
 *
 * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
 *
 * Support for HW Rev C1:
 *
 * Copyright (C) 2010 Benjamin Herrenschmidt <benh@kernel.crashing.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 */
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/pci.h>
#include <linux/irq.h>
#include <linux/mtd/physmap.h>
#include <linux/mv643xx_eth.h>
#include <linux/leds.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/ata_platform.h>
#include <linux/phy.h>
#include <linux/marvell_phy.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/pci.h>
#include <asm/system_info.h>
#include <plat/orion-gpio.h>
#include "orion5x.h"
#include "common.h"
#include "mpp.h"

/* Rev A1 and B1 */
#define DNS323_GPIO_LED_RIGHT_AMBER	1
#define DNS323_GPIO_LED_LEFT_AMBER	2
#define DNS323_GPIO_SYSTEM_UP		3
#define DNS323_GPIO_LED_POWER1		4
#define DNS323_GPIO_LED_POWER2		5
#define DNS323_GPIO_OVERTEMP		6
#define DNS323_GPIO_RTC			7
#define DNS323_GPIO_POWER_OFF		8
#define DNS323_GPIO_KEY_POWER		9
#define DNS323_GPIO_KEY_RESET		10

/* Rev C1 */
#define DNS323C_GPIO_KEY_POWER		1
#define DNS323C_GPIO_POWER_OFF		2
#define DNS323C_GPIO_LED_RIGHT_AMBER	8
#define DNS323C_GPIO_LED_LEFT_AMBER	9
#define DNS323C_GPIO_LED_POWER		17
#define DNS323C_GPIO_FAN_BIT1		18
#define DNS323C_GPIO_FAN_BIT0		19

/* Exposed to userspace, do not change */
enum {
	DNS323_REV_A1,	/* 0 */
	DNS323_REV_B1,	/* 1 */
	DNS323_REV_C1,	/* 2 */
};

/****************************************************************************
 * PCI setup
 */

static int __init dns323_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
	int irq;

	/*
	 * Check for devices with hard-wired IRQs.
	 */
	irq = orion5x_pci_map_irq(dev, slot, pin);
	if (irq != -1)
		return irq;

	return -1;
}

static struct hw_pci dns323_pci __initdata = {
	.nr_controllers = 2,
	.setup		= orion5x_pci_sys_setup,
	.scan		= orion5x_pci_sys_scan_bus,
	.map_irq	= dns323_pci_map_irq,
};

static int __init dns323_pci_init(void)
{
	/* Rev B1 and C1 doesn't really use its PCI bus, and initialising PCI
	 * gets in the way of initialising the SATA controller.
	 */
	if (machine_is_dns323() && system_rev == DNS323_REV_A1)
		pci_common_init(&dns323_pci);

	return 0;
}

subsys_initcall(dns323_pci_init);

/****************************************************************************
 * 8MiB NOR flash (Spansion S29GL064M90TFIR4)
 *
 * Layout as used by D-Link:
 *  0x00000000-0x00010000 : "MTD1"
 *  0x00010000-0x00020000 : "MTD2"
 *  0x00020000-0x001a0000 : "Linux Kernel"
 *  0x001a0000-0x007d0000 : "File System"
 *  0x007d0000-0x00800000 : "u-boot"
 */

#define DNS323_NOR_BOOT_BASE 0xf4000000
#define DNS323_NOR_BOOT_SIZE SZ_8M

static struct mtd_partition dns323_partitions[] = {
	{
		.name	= "MTD1",
		.size	= 0x00010000,
		.offset	= 0,
	}, {
		.name	= "MTD2",
		.size	= 0x00010000,
		.offset = 0x00010000,
	}, {
		.name	= "Linux Kernel",
		.size	= 0x00180000,
		.offset	= 0x00020000,
	}, {
		.name	= "File System",
		.size	= 0x00630000,
		.offset	= 0x001A0000,
	}, {
		.name	= "u-boot",
		.size	= 0x00030000,
		.offset	= 0x007d0000,
	},
};

static struct physmap_flash_data dns323_nor_flash_data = {
	.width		= 1,
	.parts		= dns323_partitions,
	.nr_parts	= ARRAY_SIZE(dns323_partitions)
};

static struct resource dns323_nor_flash_resource = {
	.flags		= IORESOURCE_MEM,
	.start		= DNS323_NOR_BOOT_BASE,
	.end		= DNS323_NOR_BOOT_BASE + DNS323_NOR_BOOT_SIZE - 1,
};

static struct platform_device dns323_nor_flash = {
	.name		= "physmap-flash",
	.id		= 0,
	.dev		= {
		.platform_data	= &dns323_nor_flash_data,
	},
	.resource	= &dns323_nor_flash_resource,
	.num_resources	= 1,
};

/****************************************************************************
 * Ethernet
 */

static struct mv643xx_eth_platform_data dns323_eth_data = {
	.phy_addr = MV643XX_ETH_PHY_ADDR(8),
};

/* dns323_parse_hex_*() taken from tsx09-common.c; should a common copy of these
 * functions be kept somewhere?
 */
static int __init dns323_parse_hex_nibble(char n)
{
	if (n >= '0' && n <= '9')
		return n - '0';

	if (n >= 'A' && n <= 'F')
		return n - 'A' + 10;

	if (n >= 'a' && n <= 'f')
		return n - 'a' + 10;

	return -1;
}

static int __init dns323_parse_hex_byte(const char *b)
{
	int hi;
	int lo;

	hi = dns323_parse_hex_nibble(b[0]);
	lo = dns323_parse_hex_nibble(b[1]);

	if (hi < 0 || lo < 0)
		return -1;

	return (hi << 4) | lo;
}

static int __init dns323_read_mac_addr(void)
{
	u_int8_t addr[6];
	int i;
	char *mac_page;

	/* MAC address is stored as a regular ol' string in /dev/mtdblock4
	 * (0x007d0000-0x00800000) starting at offset 196480 (0x2ff80).
	 */
	mac_page = ioremap(DNS323_NOR_BOOT_BASE + 0x7d0000 + 196480, 1024);
	if (!mac_page)
		return -ENOMEM;

	/* Sanity check the string we're looking at */
	for (i = 0; i < 5; i++) {
		if (*(mac_page + (i * 3) + 2) != ':') {
			goto error_fail;
		}
	}

	for (i = 0; i < 6; i++)	{
		int byte;

		byte = dns323_parse_hex_byte(mac_page + (i * 3));
		if (byte < 0) {
			goto error_fail;
		}

		addr[i] = byte;
	}

	iounmap(mac_page);
	printk("DNS-323: Found ethernet MAC address: %pM\n", addr);

	memcpy(dns323_eth_data.mac_addr, addr, 6);

	return 0;

error_fail:
	iounmap(mac_page);
	return -EINVAL;
}

/****************************************************************************
 * GPIO LEDs (simple - doesn't use hardware blinking support)
 */

static struct gpio_led dns323ab_leds[] = {
	{
		.name = "power:blue",
		.gpio = DNS323_GPIO_LED_POWER2,
		.default_trigger = "default-on",
	}, {
		.name = "right:amber",
		.gpio = DNS323_GPIO_LED_RIGHT_AMBER,
		.active_low = 1,
	}, {
		.name = "left:amber",
		.gpio = DNS323_GPIO_LED_LEFT_AMBER,
		.active_low = 1,
	},
};

static struct gpio_led dns323c_leds[] = {
	{
		.name = "power:blue",
		.gpio = DNS323C_GPIO_LED_POWER,
		.default_trigger = "timer",
		.active_low = 1,
	}, {
		.name = "right:amber",
		.gpio = DNS323C_GPIO_LED_RIGHT_AMBER,
		.active_low = 1,
	}, {
		.name = "left:amber",
		.gpio = DNS323C_GPIO_LED_LEFT_AMBER,
		.active_low = 1,
	},
};

static struct gpio_led_platform_data dns323ab_led_data = {
	.num_leds	= ARRAY_SIZE(dns323ab_leds),
	.leds		= dns323ab_leds,
	.gpio_blink_set = orion_gpio_led_blink_set,
};

static struct gpio_led_platform_data dns323c_led_data = {
	.num_leds	= ARRAY_SIZE(dns323c_leds),
	.leds		= dns323c_leds,
	.gpio_blink_set = orion_gpio_led_blink_set,
};

static struct platform_device dns323_gpio_leds = {
	.name		= "leds-gpio",
	.id		= -1,
	.dev		= {
		.platform_data	= &dns323ab_led_data,
	},
};

/****************************************************************************
 * GPIO Attached Keys
 */

static struct gpio_keys_button dns323ab_buttons[] = {
	{
		.code		= KEY_RESTART,
		.gpio		= DNS323_GPIO_KEY_RESET,
		.desc		= "Reset Button",
		.active_low	= 1,
	}, {
		.code		= KEY_POWER,
		.gpio		= DNS323_GPIO_KEY_POWER,
		.desc		= "Power Button",
		.active_low	= 1,
	},
};

static struct gpio_keys_platform_data dns323ab_button_data = {
	.buttons	= dns323ab_buttons,
	.nbuttons	= ARRAY_SIZE(dns323ab_buttons),
};

static struct gpio_keys_button dns323c_buttons[] = {
	{
		.code		= KEY_POWER,
		.gpio		= DNS323C_GPIO_KEY_POWER,
		.desc		= "Power Button",
		.active_low	= 1,
	},
};

static struct gpio_keys_platform_data dns323c_button_data = {
	.buttons	= dns323c_buttons,
	.nbuttons	= ARRAY_SIZE(dns323c_buttons),
};

static struct platform_device dns323_button_device = {
	.name		= "gpio-keys",
	.id		= -1,
	.num_resources	= 0,
	.dev		= {
		.platform_data	= &dns323ab_button_data,
	},
};

/*****************************************************************************
 * SATA
 */
static struct mv_sata_platform_data dns323_sata_data = {
       .n_ports        = 2,
};

/****************************************************************************
 * General Setup
 */
static unsigned int dns323a_mpp_modes[] __initdata = {
	MPP0_PCIE_RST_OUTn,
	MPP1_GPIO,		/* right amber LED (sata ch0) */
	MPP2_GPIO,		/* left amber LED (sata ch1) */
	MPP3_UNUSED,
	MPP4_GPIO,		/* power button LED */
	MPP5_GPIO,		/* power button LED */
	MPP6_GPIO,		/* GMT G751-2f overtemp */
	MPP7_GPIO,		/* M41T80 nIRQ/OUT/SQW */
	MPP8_GPIO,		/* triggers power off */
	MPP9_GPIO,		/* power button switch */
	MPP10_GPIO,		/* reset button switch */
	MPP11_UNUSED,
	MPP12_UNUSED,
	MPP13_UNUSED,
	MPP14_UNUSED,
	MPP15_UNUSED,
	MPP16_UNUSED,
	MPP17_UNUSED,
	MPP18_UNUSED,
	MPP19_UNUSED,
	0,
};

static unsigned int dns323b_mpp_modes[] __initdata = {
	MPP0_UNUSED,
	MPP1_GPIO,		/* right amber LED (sata ch0) */
	MPP2_GPIO,		/* left amber LED (sata ch1) */
	MPP3_GPIO,		/* system up flag */
	MPP4_GPIO,		/* power button LED */
	MPP5_GPIO,		/* power button LED */
	MPP6_GPIO,		/* GMT G751-2f overtemp */
	MPP7_GPIO,		/* M41T80 nIRQ/OUT/SQW */
	MPP8_GPIO,		/* triggers power off */
	MPP9_GPIO,		/* power button switch */
	MPP10_GPIO,		/* reset button switch */
	MPP11_UNUSED,
	MPP12_SATA_LED,
	MPP13_SATA_LED,
	MPP14_SATA_LED,
	MPP15_SATA_LED,
	MPP16_UNUSED,
	MPP17_UNUSED,
	MPP18_UNUSED,
	MPP19_UNUSED,
	0,
};

static unsigned int dns323c_mpp_modes[] __initdata = {
	MPP0_GPIO,		/* ? input */
	MPP1_GPIO,		/* input power switch (0 = pressed) */
	MPP2_GPIO,		/* output power off */
	MPP3_UNUSED,		/* ? output */
	MPP4_UNUSED,		/* ? output */
	MPP5_UNUSED,		/* ? output */
	MPP6_UNUSED,		/* ? output */
	MPP7_UNUSED,		/* ? output */
	MPP8_GPIO,		/* i/o right amber LED */
	MPP9_GPIO,		/* i/o left amber LED */
	MPP10_GPIO,		/* input */
	MPP11_UNUSED,
	MPP12_SATA_LED,
	MPP13_SATA_LED,
	MPP14_SATA_LED,
	MPP15_SATA_LED,
	MPP16_UNUSED,
	MPP17_GPIO,		/* power button LED */
	MPP18_GPIO,		/* fan speed bit 0 */
	MPP19_GPIO,		/* fan speed bit 1 */
	0,
};

/* Rev C1 Fan speed notes:
 *
 * The fan is controlled by 2 GPIOs on this board. The settings
 * of the bits is as follow:
 *
 *  GPIO 18    GPIO 19    Fan
 *
 *    0          0        stopped
 *    0          1        low speed
 *    1          0        high speed
 *    1          1        don't do that (*)
 *
 * (*) I think the two bits control two feed-in resistors into a fixed
 *     PWN circuit, setting both bits will basically go a 'bit' faster
 *     than high speed, but d-link doesn't do it and you may get out of
 *     HW spec so don't do it.
 */

/*
 * On the DNS-323 A1 and B1 the following devices are attached via I2C:
 *
 *  i2c addr | chip        | description
 *  0x3e     | GMT G760Af  | fan speed PWM controller
 *  0x48     | GMT G751-2f | temp. sensor and therm. watchdog (LM75 compatible)
 *  0x68     | ST M41T80   | RTC w/ alarm
 */
static struct i2c_board_info __initdata dns323ab_i2c_devices[] = {
	{
		I2C_BOARD_INFO("g760a", 0x3e),
	}, {
		I2C_BOARD_INFO("lm75", 0x48),
	}, {
		I2C_BOARD_INFO("m41t80", 0x68),
	},
};

/*
 * On the DNS-323 C1 the following devices are attached via I2C:
 *
 *  i2c addr | chip        | description
 *  0x48     | GMT G751-2f | temp. sensor and therm. watchdog (LM75 compatible)
 *  0x68     | ST M41T80   | RTC w/ alarm
 */
static struct i2c_board_info __initdata dns323c_i2c_devices[] = {
	{
		I2C_BOARD_INFO("lm75", 0x48),
	}, {
		I2C_BOARD_INFO("m41t80", 0x68),
	},
};

/* DNS-323 rev. A specific power off method */
static void dns323a_power_off(void)
{
	pr_info("DNS-323: Triggering power-off...\n");
	gpio_set_value(DNS323_GPIO_POWER_OFF, 1);
}

/* DNS-323 rev B specific power off method */
static void dns323b_power_off(void)
{
	pr_info("DNS-323: Triggering power-off...\n");
	/* Pin has to be changed to 1 and back to 0 to do actual power off. */
	gpio_set_value(DNS323_GPIO_POWER_OFF, 1);
	mdelay(100);
	gpio_set_value(DNS323_GPIO_POWER_OFF, 0);
}

/* DNS-323 rev. C specific power off method */
static void dns323c_power_off(void)
{
	pr_info("DNS-323: Triggering power-off...\n");
	gpio_set_value(DNS323C_GPIO_POWER_OFF, 1);
}

static int dns323c_phy_fixup(struct phy_device *phy)
{
	phy->dev_flags |= MARVELL_PHY_M1118_DNS323_LEDS;

	return 0;
}

static int __init dns323_identify_rev(void)
{
	u32 dev, rev, i, reg;

	pr_debug("DNS-323: Identifying board ... \n");

	/* Rev A1 has a 5181 */
	orion5x_pcie_id(&dev, &rev);
	if (dev == MV88F5181_DEV_ID) {
		pr_debug("DNS-323: 5181 found, board is A1\n");
		return DNS323_REV_A1;
	}
	pr_debug("DNS-323: 5182 found, board is B1 or C1, checking PHY...\n");

	/* Rev B1 and C1 both have 5182, let's poke at the eth PHY. This is
	 * a bit gross but we want to do that without links into the eth
	 * driver so let's poke at it directly. We default to rev B1 in
	 * case the accesses fail
	 */

#define ETH_SMI_REG		(ORION5X_ETH_VIRT_BASE + 0x2000 + 0x004)
#define  SMI_BUSY		0x10000000
#define  SMI_READ_VALID		0x08000000
#define  SMI_OPCODE_READ	0x04000000
#define  SMI_OPCODE_WRITE	0x00000000

	for (i = 0; i < 1000; i++) {
		reg = readl(ETH_SMI_REG);
		if (!(reg & SMI_BUSY))
			break;
	}
	if (i >= 1000) {
		pr_warn("DNS-323: Timeout accessing PHY, assuming rev B1\n");
		return DNS323_REV_B1;
	}
	writel((3 << 21)	/* phy ID reg */ |
	       (8 << 16)	/* phy addr */ |
	       SMI_OPCODE_READ, ETH_SMI_REG);
	for (i = 0; i < 1000; i++) {
		reg = readl(ETH_SMI_REG);
		if (reg & SMI_READ_VALID)
			break;
	}
	if (i >= 1000) {
		pr_warn("DNS-323: Timeout reading PHY, assuming rev B1\n");
		return DNS323_REV_B1;
	}
	pr_debug("DNS-323: Ethernet PHY ID 0x%x\n", reg & 0xffff);

	/* Note: the Marvell tools mask the ID with 0x3f0 before comparison
	 * but I don't see that making a difference here, at least with
	 * any known Marvell PHY ID
	 */
	switch(reg & 0xfff0) {
	case 0x0cc0: /* MV88E1111 */
		return DNS323_REV_B1;
	case 0x0e10: /* MV88E1118 */
		return DNS323_REV_C1;
	default:
		pr_warn("DNS-323: Unknown PHY ID 0x%04x, assuming rev B1\n",
			reg & 0xffff);
	}
	return DNS323_REV_B1;
}

static void __init dns323_init(void)
{
	/* Setup basic Orion functions. Need to be called early. */
	orion5x_init();

	/* Identify revision */
	system_rev = dns323_identify_rev();
	pr_info("DNS-323: Identified HW revision %c1\n", 'A' + system_rev);

	/* Just to be tricky, the 5182 has a completely different
	 * set of MPP modes to the 5181.
	 */
	switch(system_rev) {
	case DNS323_REV_A1:
		orion5x_mpp_conf(dns323a_mpp_modes);
		writel(0, MPP_DEV_CTRL);		/* DEV_D[31:16] */
		break;
	case DNS323_REV_B1:
		orion5x_mpp_conf(dns323b_mpp_modes);
		break;
	case DNS323_REV_C1:
		orion5x_mpp_conf(dns323c_mpp_modes);
		break;
	}

	/* setup flash mapping
	 * CS3 holds a 8 MB Spansion S29GL064M90TFIR4
	 */
	mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_BOOT_TARGET,
				    ORION_MBUS_DEVBUS_BOOT_ATTR,
				    DNS323_NOR_BOOT_BASE,
				    DNS323_NOR_BOOT_SIZE);
	platform_device_register(&dns323_nor_flash);

	/* Sort out LEDs, Buttons and i2c devices */
	switch(system_rev) {
	case DNS323_REV_A1:
		/* The 5181 power LED is active low and requires
		 * DNS323_GPIO_LED_POWER1 to also be low.
		 */
		 dns323ab_leds[0].active_low = 1;
		 gpio_request(DNS323_GPIO_LED_POWER1, "Power Led Enable");
		 gpio_direction_output(DNS323_GPIO_LED_POWER1, 0);
		fallthrough;
	case DNS323_REV_B1:
		i2c_register_board_info(0, dns323ab_i2c_devices,
				ARRAY_SIZE(dns323ab_i2c_devices));
		break;
	case DNS323_REV_C1:
		/* Hookup LEDs & Buttons */
		dns323_gpio_leds.dev.platform_data = &dns323c_led_data;
		dns323_button_device.dev.platform_data = &dns323c_button_data;

		/* Hookup i2c devices and fan driver */
		i2c_register_board_info(0, dns323c_i2c_devices,
				ARRAY_SIZE(dns323c_i2c_devices));
		platform_device_register_simple("dns323c-fan", 0, NULL, 0);

		/* Register fixup for the PHY LEDs */
		if (!IS_BUILTIN(CONFIG_PHYLIB))
			break;
		phy_register_fixup_for_uid(MARVELL_PHY_ID_88E1118,
					   MARVELL_PHY_ID_MASK,
					   dns323c_phy_fixup);
	}

	platform_device_register(&dns323_gpio_leds);
	platform_device_register(&dns323_button_device);

	/*
	 * Configure peripherals.
	 */
	if (dns323_read_mac_addr() < 0)
		printk("DNS-323: Failed to read MAC address\n");
	orion5x_ehci0_init();
	orion5x_eth_init(&dns323_eth_data);
	orion5x_i2c_init();
	orion5x_uart0_init();

	/* Remaining GPIOs */
	switch(system_rev) {
	case DNS323_REV_A1:
		/* Poweroff GPIO */
		if (gpio_request(DNS323_GPIO_POWER_OFF, "POWEROFF") != 0 ||
		    gpio_direction_output(DNS323_GPIO_POWER_OFF, 0) != 0)
			pr_err("DNS-323: failed to setup power-off GPIO\n");
		pm_power_off = dns323a_power_off;
		break;
	case DNS323_REV_B1:
		/* 5182 built-in SATA init */
		orion5x_sata_init(&dns323_sata_data);

		/* The DNS323 rev B1 has flag to indicate the system is up.
		 * Without this flag set, power LED will flash and cannot be
		 * controlled via leds-gpio.
		 */
		if (gpio_request(DNS323_GPIO_SYSTEM_UP, "SYS_READY") == 0)
			gpio_direction_output(DNS323_GPIO_SYSTEM_UP, 1);

		/* Poweroff GPIO */
		if (gpio_request(DNS323_GPIO_POWER_OFF, "POWEROFF") != 0 ||
		    gpio_direction_output(DNS323_GPIO_POWER_OFF, 0) != 0)
			pr_err("DNS-323: failed to setup power-off GPIO\n");
		pm_power_off = dns323b_power_off;
		break;
	case DNS323_REV_C1:
		/* 5182 built-in SATA init */
		orion5x_sata_init(&dns323_sata_data);

		/* Poweroff GPIO */
		if (gpio_request(DNS323C_GPIO_POWER_OFF, "POWEROFF") != 0 ||
		    gpio_direction_output(DNS323C_GPIO_POWER_OFF, 0) != 0)
			pr_err("DNS-323: failed to setup power-off GPIO\n");
		pm_power_off = dns323c_power_off;

		/* Now, -this- should theoretically be done by the sata_mv driver
		 * once I figure out what's going on there. Maybe the behaviour
		 * of the LEDs should be somewhat passed via the platform_data.
		 * for now, just whack the register and make the LEDs happy
		 *
		 * Note: AFAIK, rev B1 needs the same treatment but I'll let
		 * somebody else test it.
		 */
		writel(0x5, ORION5X_SATA_VIRT_BASE + 0x2c);
		break;
	}
}

/* Warning: D-Link uses a wrong mach-type (=526) in their bootloader */
MACHINE_START(DNS323, "D-Link DNS-323")
	/* Maintainer: Herbert Valerio Riedel <hvr@gnu.org> */
	.atag_offset	= 0x100,
	.nr_irqs	= ORION5X_NR_IRQS,
	.init_machine	= dns323_init,
	.map_io		= orion5x_map_io,
	.init_early	= orion5x_init_early,
	.init_irq	= orion5x_init_irq,
	.init_time	= orion5x_timer_init,
	.fixup		= tag_fixup_mem32,
	.restart	= orion5x_restart,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * arch/arm/mach-orion5x/irq.c
 *
 * Core IRQ functions for Marvell Orion System On Chip
 *
 * Maintainer: Tzachi Perelstein <tzachi@marvell.com>
 */
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <plat/orion-gpio.h>
#include <plat/irq.h>
#include <asm/exception.h>
#include "bridge-regs.h"
#include "common.h"

static int __initdata gpio0_irqs[4] = {
	IRQ_ORION5X_GPIO_0_7,
	IRQ_ORION5X_GPIO_8_15,
	IRQ_ORION5X_GPIO_16_23,
	IRQ_ORION5X_GPIO_24_31,
};

static asmlinkage void
__exception_irq_entry orion5x_legacy_handle_irq(struct pt_regs *regs)
{
	u32 stat;

	stat = readl_relaxed(MAIN_IRQ_CAUSE);
	stat &= readl_relaxed(MAIN_IRQ_MASK);
	if (stat) {
		unsigned int hwirq = 1 + __fls(stat);
		handle_IRQ(hwirq, regs);
		return;
	}
}

void __init orion5x_init_irq(void)
{
	orion_irq_init(1, MAIN_IRQ_MASK);

	set_handle_irq(orion5x_legacy_handle_irq);

	/*
	 * Initialize gpiolib for GPIOs 0-31.
	 */
	orion_gpio_init(0, 32, GPIO_VIRT_BASE, 0,
			IRQ_ORION5X_GPIO_START, gpio0_irqs);
}


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * IRQ definitions for Orion SoC
 *
 *  Maintainer: Tzachi Perelstein <tzachi@marvell.com>
 */

#ifndef __ASM_ARCH_IRQS_H
#define __ASM_ARCH_IRQS_H

/*
 * Orion Main Interrupt Controller
 */
#define IRQ_ORION5X_BRIDGE		(1 + 0)
#define IRQ_ORION5X_DOORBELL_H2C	(1 + 1)
#define IRQ_ORION5X_DOORBELL_C2H	(1 + 2)
#define IRQ_ORION5X_UART0		(1 + 3)
#define IRQ_ORION5X_UART1		(1 + 4)
#define IRQ_ORION5X_I2C			(1 + 5)
#define IRQ_ORION5X_GPIO_0_7		(1 + 6)
#define IRQ_ORION5X_GPIO_8_15		(1 + 7)
#define IRQ_ORION5X_GPIO_16_23		(1 + 8)
#define IRQ_ORION5X_GPIO_24_31		(1 + 9)
#define IRQ_ORION5X_PCIE0_ERR		(1 + 10)
#define IRQ_ORION5X_PCIE0_INT		(1 + 11)
#define IRQ_ORION5X_USB1_CTRL		(1 + 12)
#define IRQ_ORION5X_DEV_BUS_ERR		(1 + 14)
#define IRQ_ORION5X_PCI_ERR		(1 + 15)
#define IRQ_ORION5X_USB_BR_ERR		(1 + 16)
#define IRQ_ORION5X_USB0_CTRL		(1 + 17)
#define IRQ_ORION5X_ETH_RX		(1 + 18)
#define IRQ_ORION5X_ETH_TX		(1 + 19)
#define IRQ_ORION5X_ETH_MISC		(1 + 20)
#define IRQ_ORION5X_ETH_SUM		(1 + 21)
#define IRQ_ORION5X_ETH_ERR		(1 + 22)
#define IRQ_ORION5X_IDMA_ERR		(1 + 23)
#define IRQ_ORION5X_IDMA_0		(1 + 24)
#define IRQ_ORION5X_IDMA_1		(1 + 25)
#define IRQ_ORION5X_IDMA_2		(1 + 26)
#define IRQ_ORION5X_IDMA_3		(1 + 27)
#define IRQ_ORION5X_CESA		(1 + 28)
#define IRQ_ORION5X_SATA		(1 + 29)
#define IRQ_ORION5X_XOR0		(1 + 30)
#define IRQ_ORION5X_XOR1		(1 + 31)

/*
 * Orion General Purpose Pins
 */
#define IRQ_ORION5X_GPIO_START	33
#define NR_GPIO_IRQS		32

#define ORION5X_NR_IRQS		(IRQ_ORION5X_GPIO_START + NR_GPIO_IRQS)

#endif


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * arch/arm/mach-orion5x/kurobox_pro-setup.c
 *
 * Maintainer: Ronen Shitrit <rshitrit@marvell.com>
 */
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/pci.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/mtd/physmap.h>
#include <linux/mtd/rawnand.h>
#include <linux/mv643xx_eth.h>
#include <linux/i2c.h>
#include <linux/serial_reg.h>
#include <linux/ata_platform.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/pci.h>
#include <linux/platform_data/mtd-orion_nand.h>
#include "common.h"
#include "mpp.h"
#include "orion5x.h"

/*****************************************************************************
 * KUROBOX-PRO Info
 ****************************************************************************/

/*
 * 256K NOR flash Device bus boot chip select
 */

#define KUROBOX_PRO_NOR_BOOT_BASE	0xf4000000
#define KUROBOX_PRO_NOR_BOOT_SIZE	SZ_256K

/*
 * 256M NAND flash on Device bus chip select 1
 */

#define KUROBOX_PRO_NAND_BASE		0xfc000000
#define KUROBOX_PRO_NAND_SIZE		SZ_2M

/*****************************************************************************
 * 256MB NAND Flash on Device bus CS0
 ****************************************************************************/

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),
	},
};

static struct resource kurobox_pro_nand_resource = {
	.flags		= IORESOURCE_MEM,
	.start		= KUROBOX_PRO_NAND_BASE,
	.end		= KUROBOX_PRO_NAND_BASE + KUROBOX_PRO_NAND_SIZE - 1,
};

static struct orion_nand_data kurobox_pro_nand_data = {
	.parts		= kurobox_pro_nand_parts,
	.nr_parts	= ARRAY_SIZE(kurobox_pro_nand_parts),
	.cle		= 0,
	.ale		= 1,
	.width		= 8,
};

static struct platform_device kurobox_pro_nand_flash = {
	.name		= "orion_nand",
	.id		= -1,
	.dev		= {
		.platform_data	= &kurobox_pro_nand_data,
	},
	.resource	= &kurobox_pro_nand_resource,
	.num_resources	= 1,
};

/*****************************************************************************
 * 256KB NOR Flash on BOOT Device
 ****************************************************************************/

static struct physmap_flash_data kurobox_pro_nor_flash_data = {
	.width		= 1,
};

static struct resource kurobox_pro_nor_flash_resource = {
	.flags			= IORESOURCE_MEM,
	.start			= KUROBOX_PRO_NOR_BOOT_BASE,
	.end			= KUROBOX_PRO_NOR_BOOT_BASE + KUROBOX_PRO_NOR_BOOT_SIZE - 1,
};

static struct platform_device kurobox_pro_nor_flash = {
	.name			= "physmap-flash",
	.id			= 0,
	.dev		= {
		.platform_data	= &kurobox_pro_nor_flash_data,
	},
	.num_resources		= 1,
	.resource		= &kurobox_pro_nor_flash_resource,
};

/*****************************************************************************
 * PCI
 ****************************************************************************/

static int __init kurobox_pro_pci_map_irq(const struct pci_dev *dev, u8 slot,
	u8 pin)
{
	int irq;

	/*
	 * Check for devices with hard-wired IRQs.
	 */
	irq = orion5x_pci_map_irq(dev, slot, pin);
	if (irq != -1)
		return irq;

	/*
	 * PCI isn't used on the Kuro
	 */
	return -1;
}

static struct hw_pci kurobox_pro_pci __initdata = {
	.nr_controllers	= 2,
	.setup		= orion5x_pci_sys_setup,
	.scan		= orion5x_pci_sys_scan_bus,
	.map_irq	= kurobox_pro_pci_map_irq,
};

static int __init kurobox_pro_pci_init(void)
{
	if (machine_is_kurobox_pro()) {
		orion5x_pci_disable();
		pci_common_init(&kurobox_pro_pci);
	}

	return 0;
}

subsys_initcall(kurobox_pro_pci_init);

/*****************************************************************************
 * Ethernet
 ****************************************************************************/

static struct mv643xx_eth_platform_data kurobox_pro_eth_data = {
	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
};

/*****************************************************************************
 * RTC 5C372a on I2C bus
 ****************************************************************************/
static struct i2c_board_info __initdata kurobox_pro_i2c_rtc = {
	I2C_BOARD_INFO("rs5c372a", 0x32),
};

/*****************************************************************************
 * SATA
 ****************************************************************************/
static struct mv_sata_platform_data kurobox_pro_sata_data = {
	.n_ports	= 2,
};

/*****************************************************************************
 * Kurobox Pro specific power off method via UART1-attached microcontroller
 ****************************************************************************/

#define UART1_REG(x)	(UART1_VIRT_BASE + ((UART_##x) << 2))

static int kurobox_pro_miconread(unsigned char *buf, int count)
{
	int i;
	int timeout;

	for (i = 0; i < count; i++) {
		timeout = 10;

		while (!(readl(UART1_REG(LSR)) & UART_LSR_DR)) {
			if (--timeout == 0)
				break;
			udelay(1000);
		}

		if (timeout == 0)
			break;
		buf[i] = readl(UART1_REG(RX));
	}

	/* return read bytes */
	return i;
}

static int kurobox_pro_miconwrite(const unsigned char *buf, int count)
{
	int i = 0;

	while (count--) {
		while (!(readl(UART1_REG(LSR)) & UART_LSR_THRE))
			barrier();
		writel(buf[i++], UART1_REG(TX));
	}

	return 0;
}

static int kurobox_pro_miconsend(const unsigned char *data, int count)
{
	int i;
	unsigned char checksum = 0;
	unsigned char recv_buf[40];
	unsigned char send_buf[40];
	unsigned char correct_ack[3];
	int retry = 2;

	/* Generate checksum */
	for (i = 0; i < count; i++)
		checksum -=  data[i];

	do {
		/* Send data */
		kurobox_pro_miconwrite(data, count);

		/* send checksum */
		kurobox_pro_miconwrite(&checksum, 1);

		if (kurobox_pro_miconread(recv_buf, sizeof(recv_buf)) <= 3) {
			printk(KERN_ERR ">%s: receive failed.\n", __func__);

			/* send preamble to clear the receive buffer */
			memset(&send_buf, 0xff, sizeof(send_buf));
			kurobox_pro_miconwrite(send_buf, sizeof(send_buf));

			/* make dummy reads */
			mdelay(100);
			kurobox_pro_miconread(recv_buf, sizeof(recv_buf));
		} else {
			/* Generate expected ack */
			correct_ack[0] = 0x01;
			correct_ack[1] = data[1];
			correct_ack[2] = 0x00;

			/* checksum Check */
			if ((recv_buf[0] + recv_buf[1] + recv_buf[2] +
			     recv_buf[3]) & 0xFF) {
				printk(KERN_ERR ">%s: Checksum Error : "
					"Received data[%02x, %02x, %02x, %02x]"
					"\n", __func__, recv_buf[0],
					recv_buf[1], recv_buf[2], recv_buf[3]);
			} else {
				/* Check Received Data */
				if (correct_ack[0] == recv_buf[0] &&
				    correct_ack[1] == recv_buf[1] &&
				    correct_ack[2] == recv_buf[2]) {
					/* Interval for next command */
					mdelay(10);

					/* Receive ACK */
					return 0;
				}
			}
			/* Received NAK or illegal Data */
			printk(KERN_ERR ">%s: Error : NAK or Illegal Data "
					"Received\n", __func__);
		}
	} while (retry--);

	/* Interval for next command */
	mdelay(10);

	return -1;
}

static void kurobox_pro_power_off(void)
{
	const unsigned char watchdogkill[]	= {0x01, 0x35, 0x00};
	const unsigned char shutdownwait[]	= {0x00, 0x0c};
	const unsigned char poweroff[]		= {0x00, 0x06};
	/* 38400 baud divisor */
	const unsigned divisor = ((orion5x_tclk + (8 * 38400)) / (16 * 38400));

	pr_info("%s: triggering power-off...\n", __func__);

	/* hijack uart1 and reset into sane state (38400,8n1,even parity) */
	writel(0x83, UART1_REG(LCR));
	writel(divisor & 0xff, UART1_REG(DLL));
	writel((divisor >> 8) & 0xff, UART1_REG(DLM));
	writel(0x1b, UART1_REG(LCR));
	writel(0x00, UART1_REG(IER));
	writel(0x07, UART1_REG(FCR));
	writel(0x00, UART1_REG(MCR));

	/* Send the commands to shutdown the Kurobox Pro */
	kurobox_pro_miconsend(watchdogkill, sizeof(watchdogkill)) ;
	kurobox_pro_miconsend(shutdownwait, sizeof(shutdownwait)) ;
	kurobox_pro_miconsend(poweroff, sizeof(poweroff));
}

/*****************************************************************************
 * General Setup
 ****************************************************************************/
static unsigned int kurobox_pro_mpp_modes[] __initdata = {
	MPP0_UNUSED,
	MPP1_UNUSED,
	MPP2_GPIO,		/* GPIO Micon */
	MPP3_GPIO,		/* GPIO Rtc */
	MPP4_UNUSED,
	MPP5_UNUSED,
	MPP6_NAND,		/* NAND Flash REn */
	MPP7_NAND,		/* NAND Flash WEn */
	MPP8_UNUSED,
	MPP9_UNUSED,
	MPP10_UNUSED,
	MPP11_UNUSED,
	MPP12_SATA_LED,		/* SATA 0 presence */
	MPP13_SATA_LED,		/* SATA 1 presence */
	MPP14_SATA_LED,		/* SATA 0 active */
	MPP15_SATA_LED,		/* SATA 1 active */
	MPP16_UART,		/* UART1 RXD */
	MPP17_UART,		/* UART1 TXD */
	MPP18_UART,		/* UART1 CTSn */
	MPP19_UART,		/* UART1 RTSn */
	0,
};

static void __init kurobox_pro_init(void)
{
	/*
	 * Setup basic Orion functions. Need to be called early.
	 */
	orion5x_init();

	orion5x_mpp_conf(kurobox_pro_mpp_modes);

	/*
	 * Configure peripherals.
	 */
	orion5x_ehci0_init();
	orion5x_ehci1_init();
	orion5x_eth_init(&kurobox_pro_eth_data);
	orion5x_i2c_init();
	orion5x_sata_init(&kurobox_pro_sata_data);
	orion5x_uart0_init();
	orion5x_uart1_init();
	orion5x_xor_init();

	mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_BOOT_TARGET,
				    ORION_MBUS_DEVBUS_BOOT_ATTR,
				    KUROBOX_PRO_NOR_BOOT_BASE,
				    KUROBOX_PRO_NOR_BOOT_SIZE);
	platform_device_register(&kurobox_pro_nor_flash);

	if (machine_is_kurobox_pro()) {
		mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_TARGET(0),
					    ORION_MBUS_DEVBUS_ATTR(0),
					    KUROBOX_PRO_NAND_BASE,
					    KUROBOX_PRO_NAND_SIZE);
		platform_device_register(&kurobox_pro_nand_flash);
	}

	i2c_register_board_info(0, &kurobox_pro_i2c_rtc, 1);

	/* register Kurobox Pro specific power-off method */
	pm_power_off = kurobox_pro_power_off;
}

#ifdef CONFIG_MACH_KUROBOX_PRO
MACHINE_START(KUROBOX_PRO, "Buffalo/Revogear Kurobox Pro")
	/* Maintainer: Ronen Shitrit <rshitrit@marvell.com> */
	.atag_offset	= 0x100,
	.nr_irqs	= ORION5X_NR_IRQS,
	.init_machine	= kurobox_pro_init,
	.map_io		= orion5x_map_io,
	.init_early	= orion5x_init_early,
	.init_irq	= orion5x_init_irq,
	.init_time	= orion5x_timer_init,
	.fixup		= tag_fixup_mem32,
	.restart	= orion5x_restart,
MACHINE_END
#endif

#ifdef CONFIG_MACH_LINKSTATION_PRO
MACHINE_START(LINKSTATION_PRO, "Buffalo Linkstation Pro/Live")
	/* Maintainer: Byron Bradley <byron.bbradley@gmail.com> */
	.atag_offset	= 0x100,
	.nr_irqs	= ORION5X_NR_IRQS,
	.init_machine	= kurobox_pro_init,
	.map_io		= orion5x_map_io,
	.init_early	= orion5x_init_early,
	.init_irq	= orion5x_init_irq,
	.init_time	= orion5x_timer_init,
	.fixup		= tag_fixup_mem32,
	.restart	= orion5x_restart,
MACHINE_END
#endif


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * arch/arm/mach-orion5x/ls_hgl-setup.c
 *
 * Maintainer: Zhu Qingsen <zhuqs@cn.fujitsu.com>
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/mtd/physmap.h>
#include <linux/mv643xx_eth.h>
#include <linux/leds.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/ata_platform.h>
#include <linux/gpio.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include "common.h"
#include "mpp.h"
#include "orion5x.h"

/*****************************************************************************
 * Linkstation LS-HGL Info
 ****************************************************************************/

/*
 * 256K NOR flash Device bus boot chip select
 */

#define LS_HGL_NOR_BOOT_BASE	0xf4000000
#define LS_HGL_NOR_BOOT_SIZE	SZ_256K

/*****************************************************************************
 * 256KB NOR Flash on BOOT Device
 ****************************************************************************/

static struct physmap_flash_data ls_hgl_nor_flash_data = {
	.width		= 1,
};

static struct resource ls_hgl_nor_flash_resource = {
	.flags	= IORESOURCE_MEM,
	.start	= LS_HGL_NOR_BOOT_BASE,
	.end	= LS_HGL_NOR_BOOT_BASE + LS_HGL_NOR_BOOT_SIZE - 1,
};

static struct platform_device ls_hgl_nor_flash = {
	.name			= "physmap-flash",
	.id			= 0,
	.dev		= {
		.platform_data	= &ls_hgl_nor_flash_data,
	},
	.num_resources		= 1,
	.resource		= &ls_hgl_nor_flash_resource,
};

/*****************************************************************************
 * Ethernet
 ****************************************************************************/

static struct mv643xx_eth_platform_data ls_hgl_eth_data = {
	.phy_addr	= 8,
};

/*****************************************************************************
 * RTC 5C372a on I2C bus
 ****************************************************************************/

static struct i2c_board_info __initdata ls_hgl_i2c_rtc = {
	I2C_BOARD_INFO("rs5c372a", 0x32),
};

/*****************************************************************************
 * LEDs attached to GPIO
 ****************************************************************************/

#define LS_HGL_GPIO_LED_ALARM   2
#define LS_HGL_GPIO_LED_INFO    3
#define LS_HGL_GPIO_LED_FUNC    17
#define LS_HGL_GPIO_LED_PWR     0

static struct gpio_led ls_hgl_led_pins[] = {
	{
		.name	   = "alarm:red",
		.gpio	   = LS_HGL_GPIO_LED_ALARM,
		.active_low     = 1,
	}, {
		.name	   = "info:amber",
		.gpio	   = LS_HGL_GPIO_LED_INFO,
		.active_low     = 1,
	}, {
		.name	   = "func:blue:top",
		.gpio	   = LS_HGL_GPIO_LED_FUNC,
		.active_low     = 1,
	}, {
		.name	   = "power:blue:bottom",
		.gpio	   = LS_HGL_GPIO_LED_PWR,
	},
};

static struct gpio_led_platform_data ls_hgl_led_data = {
	.leds	   = ls_hgl_led_pins,
	.num_leds       = ARRAY_SIZE(ls_hgl_led_pins),
};

static struct platform_device ls_hgl_leds = {
	.name   = "leds-gpio",
	.id     = -1,
	.dev    = {
		.platform_data  = &ls_hgl_led_data,
	},
};

/****************************************************************************
 * GPIO Attached Keys
 ****************************************************************************/
#define LS_HGL_GPIO_KEY_FUNC       15
#define LS_HGL_GPIO_KEY_POWER      8
#define LS_HGL_GPIO_KEY_AUTOPOWER  10

#define LS_HGL_SW_POWER     0x00
#define LS_HGL_SW_AUTOPOWER 0x01

static struct gpio_keys_button ls_hgl_buttons[] = {
	{
		.code	   = KEY_OPTION,
		.gpio	   = LS_HGL_GPIO_KEY_FUNC,
		.desc	   = "Function Button",
		.active_low     = 1,
	}, {
		.type		= EV_SW,
		.code	   = LS_HGL_SW_POWER,
		.gpio	   = LS_HGL_GPIO_KEY_POWER,
		.desc	   = "Power-on Switch",
		.active_low     = 1,
	}, {
		.type		= EV_SW,
		.code	   = LS_HGL_SW_AUTOPOWER,
		.gpio	   = LS_HGL_GPIO_KEY_AUTOPOWER,
		.desc	   = "Power-auto Switch",
		.active_low     = 1,
	},
};

static struct gpio_keys_platform_data ls_hgl_button_data = {
	.buttons	= ls_hgl_buttons,
	.nbuttons       = ARRAY_SIZE(ls_hgl_buttons),
};

static struct platform_device ls_hgl_button_device = {
	.name	   = "gpio-keys",
	.id	     = -1,
	.num_resources  = 0,
	.dev	    = {
		.platform_data  = &ls_hgl_button_data,
	},
};

/*****************************************************************************
 * SATA
 ****************************************************************************/
static struct mv_sata_platform_data ls_hgl_sata_data = {
	.n_ports	= 2,
};

/*****************************************************************************
 * Linkstation LS-HGL specific power off method: reboot
 ****************************************************************************/
/*
 * On the Linkstation LS-HGL, the shutdown process is following:
 * - Userland monitors key events until the power switch goes to off position
 * - The board reboots
 * - U-boot starts and goes into an idle mode waiting for the user
 *   to move the switch to ON position
 */

static void ls_hgl_power_off(void)
{
	orion5x_restart(REBOOT_HARD, NULL);
}

/*****************************************************************************
 * General Setup
 ****************************************************************************/

#define LS_HGL_GPIO_USB_POWER	9
#define LS_HGL_GPIO_AUTO_POWER	10
#define LS_HGL_GPIO_POWER	    8

#define LS_HGL_GPIO_HDD_POWER	1

static unsigned int ls_hgl_mpp_modes[] __initdata = {
	MPP0_GPIO, /* LED_PWR */
	MPP1_GPIO, /* HDD_PWR */
	MPP2_GPIO, /* LED_ALARM */
	MPP3_GPIO, /* LED_INFO */
	MPP4_UNUSED,
	MPP5_UNUSED,
	MPP6_GPIO, /* FAN_LCK */
	MPP7_GPIO, /* INIT */
	MPP8_GPIO, /* POWER */
	MPP9_GPIO, /* USB_PWR */
	MPP10_GPIO, /* AUTO_POWER */
	MPP11_UNUSED, /* LED_ETH (dummy) */
	MPP12_UNUSED,
	MPP13_UNUSED,
	MPP14_UNUSED,
	MPP15_GPIO, /* FUNC */
	MPP16_UNUSED,
	MPP17_GPIO, /* LED_FUNC */
	MPP18_UNUSED,
	MPP19_UNUSED,
	0,
};

static void __init ls_hgl_init(void)
{
	/*
	 * Setup basic Orion functions. Need to be called early.
	 */
	orion5x_init();

	orion5x_mpp_conf(ls_hgl_mpp_modes);

	/*
	 * Configure peripherals.
	 */
	orion5x_ehci0_init();
	orion5x_ehci1_init();
	orion5x_eth_init(&ls_hgl_eth_data);
	orion5x_i2c_init();
	orion5x_sata_init(&ls_hgl_sata_data);
	orion5x_uart0_init();
	orion5x_xor_init();

	mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_BOOT_TARGET,
				    ORION_MBUS_DEVBUS_BOOT_ATTR,
				    LS_HGL_NOR_BOOT_BASE,
				    LS_HGL_NOR_BOOT_SIZE);
	platform_device_register(&ls_hgl_nor_flash);

	platform_device_register(&ls_hgl_button_device);

	platform_device_register(&ls_hgl_leds);

	i2c_register_board_info(0, &ls_hgl_i2c_rtc, 1);

	/* enable USB power */
	gpio_set_value(LS_HGL_GPIO_USB_POWER, 1);

	/* register power-off method */
	pm_power_off = ls_hgl_power_off;

	pr_info("%s: finished\n", __func__);
}

MACHINE_START(LINKSTATION_LS_HGL, "Buffalo Linkstation LS-HGL")
	/* Maintainer: Zhu Qingsen <zhuqs@cn.fujistu.com> */
	.atag_offset	= 0x100,
	.nr_irqs	= ORION5X_NR_IRQS,
	.init_machine	= ls_hgl_init,
	.map_io		= orion5x_map_io,
	.init_early	= orion5x_init_early,
	.init_irq	= orion5x_init_irq,
	.init_time	= orion5x_timer_init,
	.fixup		= tag_fixup_mem32,
	.restart	= orion5x_restart,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * arch/arm/mach-orion5x/mpp.c
 *
 * MPP functions for Marvell Orion 5x SoCs
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <plat/mpp.h>
#include "orion5x.h"
#include "mpp.h"
#include "common.h"

static unsigned int __init orion5x_variant(void)
{
	u32 dev;
	u32 rev;

	orion5x_pcie_id(&dev, &rev);

	if (dev == MV88F5181_DEV_ID)
		return MPP_F5181_MASK;

	if (dev == MV88F5182_DEV_ID)
		return MPP_F5182_MASK;

	if (dev == MV88F5281_DEV_ID)
		return MPP_F5281_MASK;

	printk(KERN_ERR "MPP setup: unknown orion5x variant "
	       "(dev %#x rev %#x)\n", dev, rev);
	return 0;
}

void __init orion5x_mpp_conf(unsigned int *mpp_list)
{
	orion_mpp_conf(mpp_list, orion5x_variant(),
		       MPP_MAX, ORION5X_DEV_BUS_VIRT_BASE);
}


code:
/*
 * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
 * Copyright (C) 2008 Martin Michlmayr <tbm@cyrius.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 */
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/mtd/physmap.h>
#include <linux/mv643xx_eth.h>
#include <linux/leds.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/ata_platform.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include "common.h"
#include "mpp.h"
#include "orion5x.h"

#define MV2120_NOR_BOOT_BASE	0xf4000000
#define MV2120_NOR_BOOT_SIZE	SZ_512K

#define MV2120_GPIO_RTC_IRQ	3
#define MV2120_GPIO_KEY_RESET	17
#define MV2120_GPIO_KEY_POWER	18
#define MV2120_GPIO_POWER_OFF	19

/*****************************************************************************
 * Ethernet
 ****************************************************************************/
static struct mv643xx_eth_platform_data mv2120_eth_data = {
	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
};

static struct mv_sata_platform_data mv2120_sata_data = {
	.n_ports	= 2,
};

static struct mtd_partition mv2120_partitions[] = {
	{
		.name	= "firmware",
		.size	= 0x00080000,
		.offset	= 0,
	},
};

static struct physmap_flash_data mv2120_nor_flash_data = {
	.width		= 1,
	.parts		= mv2120_partitions,
	.nr_parts	= ARRAY_SIZE(mv2120_partitions)
};

static struct resource mv2120_nor_flash_resource = {
	.flags		= IORESOURCE_MEM,
	.start		= MV2120_NOR_BOOT_BASE,
	.end		= MV2120_NOR_BOOT_BASE + MV2120_NOR_BOOT_SIZE - 1,
};

static struct platform_device mv2120_nor_flash = {
	.name		= "physmap-flash",
	.id		= 0,
	.dev		= {
		.platform_data	= &mv2120_nor_flash_data,
	},
	.resource	= &mv2120_nor_flash_resource,
	.num_resources	= 1,
};

static struct gpio_keys_button mv2120_buttons[] = {
	{
		.code		= KEY_RESTART,
		.gpio		= MV2120_GPIO_KEY_RESET,
		.desc		= "reset",
		.active_low	= 1,
	}, {
		.code		= KEY_POWER,
		.gpio		= MV2120_GPIO_KEY_POWER,
		.desc		= "power",
		.active_low	= 1,
	},
};

static struct gpio_keys_platform_data mv2120_button_data = {
	.buttons	= mv2120_buttons,
	.nbuttons	= ARRAY_SIZE(mv2120_buttons),
};

static struct platform_device mv2120_button_device = {
	.name		= "gpio-keys",
	.id		= -1,
	.num_resources	= 0,
	.dev		= {
		.platform_data	= &mv2120_button_data,
	},
};

/****************************************************************************
 * General Setup
 ****************************************************************************/
static unsigned int mv2120_mpp_modes[] __initdata = {
	MPP0_GPIO,		/* Sys status LED */
	MPP1_GPIO,		/* Sys error LED */
	MPP2_GPIO,		/* OverTemp interrupt */
	MPP3_GPIO,		/* RTC interrupt */
	MPP4_GPIO,		/* V_LED 5V */
	MPP5_GPIO,		/* V_LED 3.3V */
	MPP6_UNUSED,
	MPP7_UNUSED,
	MPP8_GPIO,		/* SATA 0 fail LED */
	MPP9_GPIO,		/* SATA 1 fail LED */
	MPP10_UNUSED,
	MPP11_UNUSED,
	MPP12_SATA_LED,		/* SATA 0 presence */
	MPP13_SATA_LED,		/* SATA 1 presence */
	MPP14_SATA_LED,		/* SATA 0 active */
	MPP15_SATA_LED,		/* SATA 1 active */
	MPP16_UNUSED,
	MPP17_GPIO,		/* Reset button */
	MPP18_GPIO,		/* Power button */
	MPP19_GPIO,		/* Power off */
	0,
};

static struct i2c_board_info __initdata mv2120_i2c_rtc = {
	I2C_BOARD_INFO("pcf8563", 0x51),
	.irq	= 0,
};

static struct gpio_led mv2120_led_pins[] = {
	{
		.name			= "mv2120:blue:health",
		.gpio			= 0,
	},
	{
		.name			= "mv2120:red:health",
		.gpio			= 1,
	},
	{
		.name			= "mv2120:led:bright",
		.gpio			= 4,
		.default_trigger	= "default-on",
	},
	{
		.name			= "mv2120:led:dimmed",
		.gpio			= 5,
	},
	{
		.name			= "mv2120:red:sata0",
		.gpio			= 8,
		.active_low		= 1,
	},
	{
		.name			= "mv2120:red:sata1",
		.gpio			= 9,
		.active_low		= 1,
	},

};

static struct gpio_led_platform_data mv2120_led_data = {
	.leds		= mv2120_led_pins,
	.num_leds	= ARRAY_SIZE(mv2120_led_pins),
};

static struct platform_device mv2120_leds = {
	.name	= "leds-gpio",
	.id	= -1,
	.dev	= {
		.platform_data	= &mv2120_led_data,
	}
};

static void mv2120_power_off(void)
{
	pr_info("%s: triggering power-off...\n", __func__);
	gpio_set_value(MV2120_GPIO_POWER_OFF, 0);
}

static void __init mv2120_init(void)
{
	/* Setup basic Orion functions. Need to be called early. */
	orion5x_init();

	orion5x_mpp_conf(mv2120_mpp_modes);

	/*
	 * Configure peripherals.
	 */
	orion5x_ehci0_init();
	orion5x_ehci1_init();
	orion5x_eth_init(&mv2120_eth_data);
	orion5x_i2c_init();
	orion5x_sata_init(&mv2120_sata_data);
	orion5x_uart0_init();
	orion5x_xor_init();

	mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_BOOT_TARGET,
				    ORION_MBUS_DEVBUS_BOOT_ATTR,
				    MV2120_NOR_BOOT_BASE,
				    MV2120_NOR_BOOT_SIZE);
	platform_device_register(&mv2120_nor_flash);

	platform_device_register(&mv2120_button_device);

	if (gpio_request(MV2120_GPIO_RTC_IRQ, "rtc") == 0) {
		if (gpio_direction_input(MV2120_GPIO_RTC_IRQ) == 0)
			mv2120_i2c_rtc.irq = gpio_to_irq(MV2120_GPIO_RTC_IRQ);
		else
			gpio_free(MV2120_GPIO_RTC_IRQ);
	}
	i2c_register_board_info(0, &mv2120_i2c_rtc, 1);
	platform_device_register(&mv2120_leds);

	/* register mv2120 specific power-off method */
	if (gpio_request(MV2120_GPIO_POWER_OFF, "POWEROFF") != 0 ||
	    gpio_direction_output(MV2120_GPIO_POWER_OFF, 1) != 0)
		pr_err("mv2120: failed to setup power-off GPIO\n");
	pm_power_off = mv2120_power_off;
}

/* Warning: HP uses a wrong mach-type (=526) in their bootloader */
MACHINE_START(MV2120, "HP Media Vault mv2120")
	/* Maintainer: Martin Michlmayr <tbm@cyrius.com> */
	.atag_offset	= 0x100,
	.nr_irqs	= ORION5X_NR_IRQS,
	.init_machine	= mv2120_init,
	.map_io		= orion5x_map_io,
	.init_early	= orion5x_init_early,
	.init_irq	= orion5x_init_irq,
	.init_time	= orion5x_timer_init,
	.fixup		= tag_fixup_mem32,
	.restart	= orion5x_restart,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * arch/arm/mach-orion5x/net2big-setup.c
 *
 * LaCie 2Big Network NAS setup
 *
 * Copyright (C) 2009 Simon Guinot <sguinot@lacie.com>
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/mtd/physmap.h>
#include <linux/mv643xx_eth.h>
#include <linux/leds.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/ata_platform.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <plat/orion-gpio.h>
#include "common.h"
#include "mpp.h"
#include "orion5x.h"

/*****************************************************************************
 * LaCie 2Big Network Info
 ****************************************************************************/

/*
 * 512KB NOR flash Device bus boot chip select
 */

#define NET2BIG_NOR_BOOT_BASE		0xfff80000
#define NET2BIG_NOR_BOOT_SIZE		SZ_512K

/*****************************************************************************
 * 512KB NOR Flash on Boot Device
 ****************************************************************************/

/*
 * TODO: Check write support on flash MX29LV400CBTC-70G
 */

static struct mtd_partition net2big_partitions[] = {
	{
		.name		= "Full512kb",
		.size		= MTDPART_SIZ_FULL,
		.offset		= 0x00000000,
		.mask_flags	= MTD_WRITEABLE,
	},
};

static struct physmap_flash_data net2big_nor_flash_data = {
	.width		= 1,
	.parts		= net2big_partitions,
	.nr_parts	= ARRAY_SIZE(net2big_partitions),
};

static struct resource net2big_nor_flash_resource = {
	.flags			= IORESOURCE_MEM,
	.start			= NET2BIG_NOR_BOOT_BASE,
	.end			= NET2BIG_NOR_BOOT_BASE
					+ NET2BIG_NOR_BOOT_SIZE - 1,
};

static struct platform_device net2big_nor_flash = {
	.name			= "physmap-flash",
	.id			= 0,
	.dev		= {
		.platform_data	= &net2big_nor_flash_data,
	},
	.num_resources		= 1,
	.resource		= &net2big_nor_flash_resource,
};

/*****************************************************************************
 * Ethernet
 ****************************************************************************/

static struct mv643xx_eth_platform_data net2big_eth_data = {
	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
};

/*****************************************************************************
 * I2C devices
 ****************************************************************************/

/*
 * i2c addr | chip         | description
 * 0x32     | Ricoh 5C372b | RTC
 * 0x50     | HT24LC08     | eeprom (1kB)
 */
static struct i2c_board_info __initdata net2big_i2c_devices[] = {
	{
		I2C_BOARD_INFO("rs5c372b", 0x32),
	}, {
		I2C_BOARD_INFO("24c08", 0x50),
	},
};

/*****************************************************************************
 * SATA
 ****************************************************************************/

static struct mv_sata_platform_data net2big_sata_data = {
	.n_ports	= 2,
};

#define NET2BIG_GPIO_SATA_POWER_REQ	19
#define NET2BIG_GPIO_SATA0_POWER	23
#define NET2BIG_GPIO_SATA1_POWER	25

static void __init net2big_sata_power_init(void)
{
	int err;

	/* Configure GPIOs over MPP max number. */
	orion_gpio_set_valid(NET2BIG_GPIO_SATA0_POWER, 1);
	orion_gpio_set_valid(NET2BIG_GPIO_SATA1_POWER, 1);

	err = gpio_request(NET2BIG_GPIO_SATA0_POWER, "SATA0 power status");
	if (err == 0) {
		err = gpio_direction_input(NET2BIG_GPIO_SATA0_POWER);
		if (err)
			gpio_free(NET2BIG_GPIO_SATA0_POWER);
	}
	if (err) {
		pr_err("net2big: failed to setup SATA0 power GPIO\n");
		return;
	}

	err = gpio_request(NET2BIG_GPIO_SATA1_POWER, "SATA1 power status");
	if (err == 0) {
		err = gpio_direction_input(NET2BIG_GPIO_SATA1_POWER);
		if (err)
			gpio_free(NET2BIG_GPIO_SATA1_POWER);
	}
	if (err) {
		pr_err("net2big: failed to setup SATA1 power GPIO\n");
		goto err_free_1;
	}

	err = gpio_request(NET2BIG_GPIO_SATA_POWER_REQ, "SATA power request");
	if (err == 0) {
		err = gpio_direction_output(NET2BIG_GPIO_SATA_POWER_REQ, 0);
		if (err)
			gpio_free(NET2BIG_GPIO_SATA_POWER_REQ);
	}
	if (err) {
		pr_err("net2big: failed to setup SATA power request GPIO\n");
		goto err_free_2;
	}

	if (gpio_get_value(NET2BIG_GPIO_SATA0_POWER) &&
		gpio_get_value(NET2BIG_GPIO_SATA1_POWER)) {
		return;
	}

	/*
	 * SATA power up on both disk is done by pulling high the CPLD power
	 * request line. The 300ms delay is related to the CPLD clock and is
	 * needed to be sure that the CPLD has take into account the low line
	 * status.
	 */
	msleep(300);
	gpio_set_value(NET2BIG_GPIO_SATA_POWER_REQ, 1);
	pr_info("net2big: power up SATA hard disks\n");

	return;

err_free_2:
	gpio_free(NET2BIG_GPIO_SATA1_POWER);
err_free_1:
	gpio_free(NET2BIG_GPIO_SATA0_POWER);

	return;
}

/*****************************************************************************
 * GPIO LEDs
 ****************************************************************************/

/*
 * The power front LEDs (blue and red) and SATA red LEDs are controlled via a
 * single GPIO line and are compatible with the leds-gpio driver.
 *
 * The SATA blue LEDs have some hardware blink capabilities which are detailed
 * in the following array:
 *
 * SATAx blue LED | SATAx activity | LED state
 *                |                |
 *       0        |       0        |  blink (rate 300ms)
 *       1        |       0        |  off
 *       ?        |       1        |  on
 *
 * Notes: The blue and the red front LED's can't be on at the same time.
 *        Blue LED have priority.
 */

#define NET2BIG_GPIO_PWR_RED_LED	6
#define NET2BIG_GPIO_PWR_BLUE_LED	16
#define NET2BIG_GPIO_PWR_LED_BLINK_STOP	7

#define NET2BIG_GPIO_SATA0_RED_LED	11
#define NET2BIG_GPIO_SATA1_RED_LED	10

#define NET2BIG_GPIO_SATA0_BLUE_LED	17
#define NET2BIG_GPIO_SATA1_BLUE_LED	13

static struct gpio_led net2big_leds[] = {
	{
		.name = "net2big:red:power",
		.gpio = NET2BIG_GPIO_PWR_RED_LED,
	},
	{
		.name = "net2big:blue:power",
		.gpio = NET2BIG_GPIO_PWR_BLUE_LED,
	},
	{
		.name = "net2big:red:sata0",
		.gpio = NET2BIG_GPIO_SATA0_RED_LED,
	},
	{
		.name = "net2big:red:sata1",
		.gpio = NET2BIG_GPIO_SATA1_RED_LED,
	},
};

static struct gpio_led_platform_data net2big_led_data = {
	.num_leds = ARRAY_SIZE(net2big_leds),
	.leds = net2big_leds,
};

static struct platform_device net2big_gpio_leds = {
	.name           = "leds-gpio",
	.id             = -1,
	.dev            = {
		.platform_data  = &net2big_led_data,
	},
};

static void __init net2big_gpio_leds_init(void)
{
	int err;

	/* Stop initial CPLD slow red/blue blinking on power LED. */
	err = gpio_request(NET2BIG_GPIO_PWR_LED_BLINK_STOP,
			   "Power LED blink stop");
	if (err == 0) {
		err = gpio_direction_output(NET2BIG_GPIO_PWR_LED_BLINK_STOP, 1);
		if (err)
			gpio_free(NET2BIG_GPIO_PWR_LED_BLINK_STOP);
	}
	if (err)
		pr_err("net2big: failed to setup power LED blink GPIO\n");

	/*
	 * Configure SATA0 and SATA1 blue LEDs to blink in relation with the
	 * hard disk activity.
	 */
	err = gpio_request(NET2BIG_GPIO_SATA0_BLUE_LED,
			   "SATA0 blue LED control");
	if (err == 0) {
		err = gpio_direction_output(NET2BIG_GPIO_SATA0_BLUE_LED, 1);
		if (err)
			gpio_free(NET2BIG_GPIO_SATA0_BLUE_LED);
	}
	if (err)
		pr_err("net2big: failed to setup SATA0 blue LED GPIO\n");

	err = gpio_request(NET2BIG_GPIO_SATA1_BLUE_LED,
			   "SATA1 blue LED control");
	if (err == 0) {
		err = gpio_direction_output(NET2BIG_GPIO_SATA1_BLUE_LED, 1);
		if (err)
			gpio_free(NET2BIG_GPIO_SATA1_BLUE_LED);
	}
	if (err)
		pr_err("net2big: failed to setup SATA1 blue LED GPIO\n");

	platform_device_register(&net2big_gpio_leds);
}

/****************************************************************************
 * GPIO keys
 ****************************************************************************/

#define NET2BIG_GPIO_PUSH_BUTTON	18
#define NET2BIG_GPIO_POWER_SWITCH_ON	8
#define NET2BIG_GPIO_POWER_SWITCH_OFF	9

#define NET2BIG_SWITCH_POWER_ON		0x1
#define NET2BIG_SWITCH_POWER_OFF	0x2

static struct gpio_keys_button net2big_buttons[] = {
	{
		.type		= EV_SW,
		.code		= NET2BIG_SWITCH_POWER_OFF,
		.gpio		= NET2BIG_GPIO_POWER_SWITCH_OFF,
		.desc		= "Power rocker switch (auto|off)",
		.active_low	= 0,
	},
	{
		.type		= EV_SW,
		.code		= NET2BIG_SWITCH_POWER_ON,
		.gpio		= NET2BIG_GPIO_POWER_SWITCH_ON,
		.desc		= "Power rocker switch (on|auto)",
		.active_low	= 0,
	},
	{
		.type		= EV_KEY,
		.code		= KEY_POWER,
		.gpio		= NET2BIG_GPIO_PUSH_BUTTON,
		.desc		= "Front Push Button",
		.active_low	= 0,
	},
};

static struct gpio_keys_platform_data net2big_button_data = {
	.buttons	= net2big_buttons,
	.nbuttons	= ARRAY_SIZE(net2big_buttons),
};

static struct platform_device net2big_gpio_buttons = {
	.name		= "gpio-keys",
	.id		= -1,
	.dev		= {
		.platform_data	= &net2big_button_data,
	},
};

/*****************************************************************************
 * General Setup
 ****************************************************************************/

static unsigned int net2big_mpp_modes[] __initdata = {
	MPP0_GPIO,	/* Raid mode (bit 0) */
	MPP1_GPIO,	/* USB port 2 fuse (0 = Fail, 1 = Ok) */
	MPP2_GPIO,	/* Raid mode (bit 1) */
	MPP3_GPIO,	/* Board ID (bit 0) */
	MPP4_GPIO,	/* Fan activity (0 = Off, 1 = On) */
	MPP5_GPIO,	/* Fan fail detection */
	MPP6_GPIO,	/* Red front LED (0 = Off, 1 = On) */
	MPP7_GPIO,	/* Disable initial blinking on front LED */
	MPP8_GPIO,	/* Rear power switch (on|auto) */
	MPP9_GPIO,	/* Rear power switch (auto|off) */
	MPP10_GPIO,	/* SATA 1 red LED (0 = Off, 1 = On) */
	MPP11_GPIO,	/* SATA 0 red LED (0 = Off, 1 = On) */
	MPP12_GPIO,	/* Board ID (bit 1) */
	MPP13_GPIO,	/* SATA 1 blue LED blink control */
	MPP14_SATA_LED,
	MPP15_SATA_LED,
	MPP16_GPIO,	/* Blue front LED control */
	MPP17_GPIO,	/* SATA 0 blue LED blink control */
	MPP18_GPIO,	/* Front button (0 = Released, 1 = Pushed ) */
	MPP19_GPIO,	/* SATA{0,1} power On/Off request */
	0,
	/* 22: USB port 1 fuse (0 = Fail, 1 = Ok) */
	/* 23: SATA 0 power status */
	/* 24: Board power off */
	/* 25: SATA 1 power status */
};

#define NET2BIG_GPIO_POWER_OFF		24

static void net2big_power_off(void)
{
	gpio_set_value(NET2BIG_GPIO_POWER_OFF, 1);
}

static void __init net2big_init(void)
{
	/*
	 * Setup basic Orion functions. Need to be called early.
	 */
	orion5x_init();

	orion5x_mpp_conf(net2big_mpp_modes);

	/*
	 * Configure peripherals.
	 */
	orion5x_ehci0_init();
	orion5x_ehci1_init();
	orion5x_eth_init(&net2big_eth_data);
	orion5x_i2c_init();
	orion5x_uart0_init();
	orion5x_xor_init();

	net2big_sata_power_init();
	orion5x_sata_init(&net2big_sata_data);

	mvebu_mbus_add_window_by_id(ORION_MBUS_DEVBUS_BOOT_TARGET,
				    ORION_MBUS_DEVBUS_BOOT_ATTR,
				    NET2BIG_NOR_BOOT_BASE,
				    NET2BIG_NOR_BOOT_SIZE);
	platform_device_register(&net2big_nor_flash);

	platform_device_register(&net2big_gpio_buttons);
	net2big_gpio_leds_init();

	i2c_register_board_info(0, net2big_i2c_devices,
				ARRAY_SIZE(net2big_i2c_devices));

	orion_gpio_set_valid(NET2BIG_GPIO_POWER_OFF, 1);

	if (gpio_request(NET2BIG_GPIO_POWER_OFF, "power-off") == 0 &&
	    gpio_direction_output(NET2BIG_GPIO_POWER_OFF, 0) == 0)
		pm_power_off = net2big_power_off;
	else
		pr_err("net2big: failed to configure power-off GPIO\n");

	pr_notice("net2big: Flash writing is not yet supported.\n");
}

/* Warning: LaCie use a wrong mach-type (0x20e=526) in their bootloader. */
MACHINE_START(NET2BIG, "LaCie 2Big Network")
	.atag_offset	= 0x100,
	.nr_irqs	= ORION5X_NR_IRQS,
	.init_machine	= net2big_init,
	.map_io		= orion5x_map_io,
	.init_early	= orion5x_init_early,
	.init_irq	= orion5x_init_irq,
	.init_time	= orion5x_timer_init,
	.fixup		= tag_fixup_mem32,
	.restart	= orion5x_restart,
MACHINE_END


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Generic definitions of Orion SoC flavors:
 *  Orion-1, Orion-VoIP, Orion-NAS, Orion-2, and Orion-1-90.
 *
 * Maintainer: Tzachi Perelstein <tzachi@marvell.com>
 */

#ifndef __ASM_ARCH_ORION5X_H
#define __ASM_ARCH_ORION5X_H

#include "irqs.h"

/*****************************************************************************
 * Orion Address Maps
 *
 * phys
 * e0000000	PCIe MEM space
 * e8000000	PCI MEM space
 * f0000000	PCIe WA space (Orion-1/Orion-NAS only)
 * f1000000	on-chip peripheral registers
 * f2000000	PCIe I/O space
 * f2100000	PCI I/O space
 * f2200000	SRAM dedicated for the crypto unit
 * f4000000	device bus mappings (boot)
 * fa000000	device bus mappings (cs0)
 * fa800000	device bus mappings (cs2)
 * fc000000	device bus mappings (cs0/cs1)
 *
 * virt		phys		size
 * fec00000	f1000000	1M	on-chip peripheral registers
 * fee00000	f2000000	64K	PCIe I/O space
 * fee10000	f2100000	64K	PCI I/O space
 * fd000000	f0000000	16M	PCIe WA space (Orion-1/Orion-NAS only)
 ****************************************************************************/
#define ORION5X_REGS_PHYS_BASE		0xf1000000
#define ORION5X_REGS_VIRT_BASE		IOMEM(0xfec00000)
#define ORION5X_REGS_SIZE		SZ_1M

#define ORION5X_PCIE_IO_PHYS_BASE	0xf2000000
#define ORION5X_PCIE_IO_BUS_BASE	0x00000000
#define ORION5X_PCIE_IO_SIZE		SZ_64K

#define ORION5X_PCI_IO_PHYS_BASE	0xf2100000
#define ORION5X_PCI_IO_BUS_BASE		0x00010000
#define ORION5X_PCI_IO_SIZE		SZ_64K

#define ORION5X_SRAM_PHYS_BASE		(0xf2200000)
#define ORION5X_SRAM_SIZE		SZ_8K

/* Relevant only for Orion-1/Orion-NAS */
#define ORION5X_PCIE_WA_PHYS_BASE	0xf0000000
#define ORION5X_PCIE_WA_VIRT_BASE	IOMEM(0xfd000000)
#define ORION5X_PCIE_WA_SIZE		SZ_16M

#define ORION5X_PCIE_MEM_PHYS_BASE	0xe0000000
#define ORION5X_PCIE_MEM_SIZE		SZ_128M

#define ORION5X_PCI_MEM_PHYS_BASE	0xe8000000
#define ORION5X_PCI_MEM_SIZE		SZ_128M

/*******************************************************************************
 * Orion Registers Map
 ******************************************************************************/

#define ORION5X_DDR_PHYS_BASE           (ORION5X_REGS_PHYS_BASE + 0x00000)
#define  ORION5X_DDR_WINS_BASE          (ORION5X_DDR_PHYS_BASE + 0x1500)
#define  ORION5X_DDR_WINS_SZ            (0x10)
#define ORION5X_DDR_VIRT_BASE		(ORION5X_REGS_VIRT_BASE + 0x00000)
#define ORION5X_DEV_BUS_PHYS_BASE	(ORION5X_REGS_PHYS_BASE + 0x10000)
#define ORION5X_DEV_BUS_VIRT_BASE	(ORION5X_REGS_VIRT_BASE + 0x10000)
#define ORION5X_DEV_BUS_REG(x)		(ORION5X_DEV_BUS_VIRT_BASE + (x))
#define  GPIO_VIRT_BASE			ORION5X_DEV_BUS_REG(0x0100)
#define  SPI_PHYS_BASE			(ORION5X_DEV_BUS_PHYS_BASE + 0x0600)
#define  I2C_PHYS_BASE			(ORION5X_DEV_BUS_PHYS_BASE + 0x1000)
#define  UART0_PHYS_BASE		(ORION5X_DEV_BUS_PHYS_BASE + 0x2000)
#define  UART0_VIRT_BASE		(ORION5X_DEV_BUS_VIRT_BASE + 0x2000)
#define  UART1_PHYS_BASE		(ORION5X_DEV_BUS_PHYS_BASE + 0x2100)
#define  UART1_VIRT_BASE		(ORION5X_DEV_BUS_VIRT_BASE + 0x2100)

#define ORION5X_BRIDGE_VIRT_BASE	(ORION5X_REGS_VIRT_BASE + 0x20000)
#define ORION5X_BRIDGE_PHYS_BASE	(ORION5X_REGS_PHYS_BASE + 0x20000)
#define  ORION5X_BRIDGE_WINS_BASE       (ORION5X_BRIDGE_PHYS_BASE)
#define  ORION5X_BRIDGE_WINS_SZ         (0x80)

#define ORION5X_PCI_VIRT_BASE		(ORION5X_REGS_VIRT_BASE + 0x30000)

#define ORION5X_PCIE_VIRT_BASE		(ORION5X_REGS_VIRT_BASE + 0x40000)

#define ORION5X_USB0_PHYS_BASE		(ORION5X_REGS_PHYS_BASE + 0x50000)
#define ORION5X_USB0_VIRT_BASE		(ORION5X_REGS_VIRT_BASE + 0x50000)

#define ORION5X_XOR_PHYS_BASE		(ORION5X_REGS_PHYS_BASE + 0x60900)
#define ORION5X_XOR_VIRT_BASE		(ORION5X_REGS_VIRT_BASE + 0x60900)

#define ORION5X_ETH_PHYS_BASE		(ORION5X_REGS_PHYS_BASE + 0x70000)
#define ORION5X_ETH_VIRT_BASE		(ORION5X_REGS_VIRT_BASE + 0x70000)

#define ORION5X_SATA_PHYS_BASE		(ORION5X_REGS_PHYS_BASE + 0x80000)
#define ORION5X_SATA_VIRT_BASE		(ORION5X_REGS_VIRT_BASE + 0x80000)

#define ORION5X_CRYPTO_PHYS_BASE	(ORION5X_REGS_PHYS_BASE + 0x90000)

#define ORION5X_USB1_PHYS_BASE		(ORION5X_REGS_PHYS_BASE + 0xa0000)
#define ORION5X_USB1_VIRT_BASE		(ORION5X_REGS_VIRT_BASE + 0xa0000)

/*******************************************************************************
 * Device Bus Registers
 ******************************************************************************/
#define MPP_0_7_CTRL		ORION5X_DEV_BUS_REG(0x000)
#define MPP_8_15_CTRL		ORION5X_DEV_BUS_REG(0x004)
#define MPP_16_19_CTRL		ORION5X_DEV_BUS_REG(0x050)
#define MPP_DEV_CTRL		ORION5X_DEV_BUS_REG(0x008)
#define MPP_RESET_SAMPLE	ORION5X_DEV_BUS_REG(0x010)
#define DEV_BANK_0_PARAM	ORION5X_DEV_BUS_REG(0x45c)
#define DEV_BANK_1_PARAM	ORION5X_DEV_BUS_REG(0x460)
#define DEV_BANK_2_PARAM	ORION5X_DEV_BUS_REG(0x464)
#define DEV_BANK_BOOT_PARAM	ORION5X_DEV_BUS_REG(0x46c)
#define DEV_BUS_CTRL		ORION5X_DEV_BUS_REG(0x4c0)
#define DEV_BUS_INT_CAUSE	ORION5X_DEV_BUS_REG(0x4d0)
#define DEV_BUS_INT_MASK	ORION5X_DEV_BUS_REG(0x4d4)

/*******************************************************************************
 * Supported Devices & Revisions
 ******************************************************************************/
/* Orion-1 (88F5181) and Orion-VoIP (88F5181L) */
#define MV88F5181_DEV_ID	0x5181
#define MV88F5181_REV_B1	3
#define MV88F5181L_REV_A0	8
#define MV88F5181L_REV_A1	9
/* Orion-NAS (88F5182) */
#define MV88F5182_DEV_ID	0x5182
#define MV88F5182_REV_A2	2
/* Orion-2 (88F5281) */
#define MV88F5281_DEV_ID	0x5281
#define MV88F5281_REV_D0	4
#define MV88F5281_REV_D1	5
#define MV88F5281_REV_D2	6
/* Orion-1-90 (88F6183) */
#define MV88F6183_DEV_ID	0x6183
#define MV88F6183_REV_B0	3

#endif