diff --git a/arch/arm/boards/Makefile b/arch/arm/boards/Makefile index c60da81..122f5cd 100644 --- a/arch/arm/boards/Makefile +++ b/arch/arm/boards/Makefile @@ -79,6 +79,7 @@ obj-$(CONFIG_MACH_PCM051) += phytec-phycore-am335x/ obj-$(CONFIG_MACH_PHYTEC_PFLA02) += phytec-phyflex-imx6/ obj-$(CONFIG_MACH_PLATHOME_OPENBLOCKS_AX3) += plathome-openblocks-ax3/ +obj-$(CONFIG_MACH_PLATHOME_OPENBLOCKS_A6) += plathome-openblocks-a6/ obj-$(CONFIG_MACH_PM9261) += pm9261/ obj-$(CONFIG_MACH_PM9263) += pm9263/ obj-$(CONFIG_MACH_PM9G45) += pm9g45/ diff --git a/arch/arm/boards/plathome-openblocks-a6/Makefile b/arch/arm/boards/plathome-openblocks-a6/Makefile new file mode 100644 index 0000000..01c7a25 --- /dev/null +++ b/arch/arm/boards/plathome-openblocks-a6/Makefile @@ -0,0 +1,2 @@ +obj-y += board.o +lwl-y += lowlevel.o diff --git a/arch/arm/boards/plathome-openblocks-a6/board.c b/arch/arm/boards/plathome-openblocks-a6/board.c new file mode 100644 index 0000000..40a8c17 --- /dev/null +++ b/arch/arm/boards/plathome-openblocks-a6/board.c @@ -0,0 +1 @@ +/* empty */ diff --git a/arch/arm/boards/plathome-openblocks-a6/lowlevel.c b/arch/arm/boards/plathome-openblocks-a6/lowlevel.c new file mode 100644 index 0000000..b37a3d6 --- /dev/null +++ b/arch/arm/boards/plathome-openblocks-a6/lowlevel.c @@ -0,0 +1,32 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include + +extern char __dtb_kirkwood_openblocks_a6_bb_start[]; + +ENTRY_FUNCTION(start_plathome_openblocks_a6, r0, r1, r2) +{ + void *fdt; + + arm_cpu_lowlevel_init(); + + fdt = __dtb_kirkwood_openblocks_a6_bb_start - + get_runtime_offset(); + + mvebu_barebox_entry(fdt); +} diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index fac2b27..dcf014d 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -27,6 +27,7 @@ pbl-dtb-$(CONFIG_MACH_PCM051) += am335x-phytec-phycore.dtb.o pbl-dtb-$(CONFIG_MACH_PHYTEC_PFLA02) += imx6s-phytec-pbab01.dtb.o imx6dl-phytec-pbab01.dtb.o imx6q-phytec-pbab01.dtb.o pbl-dtb-$(CONFIG_MACH_PLATHOME_OPENBLOCKS_AX3) += armada-xp-openblocks-ax3-4-bb.dtb.o +pbl-dtb-$(CONFIG_MACH_PLATHOME_OPENBLOCKS_A6) += kirkwood-openblocks_a6-bb.dtb.o pbl-dtb-$(CONFIG_MACH_RADXA_ROCK) += rk3188-radxarock.dtb.o pbl-dtb-$(CONFIG_MACH_REALQ7) += imx6q-dmo-edmqmx6.dtb.o pbl-dtb-$(CONFIG_MACH_SABRELITE) += imx6q-sabrelite.dtb.o imx6dl-sabrelite.dtb.o diff --git a/arch/arm/dts/kirkwood-openblocks_a6-bb.dts b/arch/arm/dts/kirkwood-openblocks_a6-bb.dts new file mode 100644 index 0000000..42bfb07 --- /dev/null +++ b/arch/arm/dts/kirkwood-openblocks_a6-bb.dts @@ -0,0 +1,13 @@ +/* + * Barebox specific DT overlay for OpenBlocks A6 board + */ + +#include "arm/kirkwood-openblocks_a6.dts" + +/ { + gpio-leds { + led-green { + barebox,default-trigger = "heartbeat"; + }; + }; +}; diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 131f3a6..3270f92 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -81,6 +81,9 @@ config MACH_GLOBALSCALE_GURUPLUG bool "Guruplug" +config MACH_PLATHOME_OPENBLOCKS_A6 + bool "PlatHome OpenBlocks A6" + config MACH_USI_TOPKICK bool "Topkick" diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 04fe3c8..ccf1f9c 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -90,6 +90,13 @@ Support for NAND flash using GPMC. GPMC is a common memory interface found on Texas Instrument's OMAP platforms +config NAND_ORION + bool + prompt "Orion NAND driver" + depends on ARCH_MVEBU + help + Support for the Orion NAND controller, present in Kirkwood SoCs. + config NAND_ATMEL bool prompt "Atmel (AT91SAM9xxx) NAND driver" diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index a1414e1..02dacde 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_NAND_IMX) += nand_imx.o obj-$(CONFIG_NAND_IMX_BBM) += nand_imx_bbm.o obj-$(CONFIG_NAND_OMAP_GPMC) += nand_omap_gpmc.o nand_omap_bch_decoder.o +obj-$(CONFIG_NAND_ORION) += nand_orion.o obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o obj-$(CONFIG_NAND_S3C24XX) += nand_s3c24xx.o pbl-$(CONFIG_NAND_S3C24XX) += nand_s3c24xx.o diff --git a/drivers/mtd/nand/nand_orion.c b/drivers/mtd/nand/nand_orion.c new file mode 100644 index 0000000..a1c77b3 --- /dev/null +++ b/drivers/mtd/nand/nand_orion.c @@ -0,0 +1,160 @@ +/* + * (C) Copyright 2014, Ezequiel Garcia + * + * Based on Orion NAND driver from Linux (drivers/mtd/nand/orion_nand.c): + * Author: Tzachi Perelstein + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct orion_nand { + struct mtd_info mtd; + struct nand_chip chip; + + u8 ale; /* address line number connected to ALE */ + u8 cle; /* address line number connected to CLE */ +}; + +static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + struct nand_chip *chip = mtd->priv; + struct orion_nand *priv = chip->priv; + u32 offs; + + if (cmd == NAND_CMD_NONE) + return; + + if (ctrl & NAND_CLE) + offs = (1 << priv->cle); + else if (ctrl & NAND_ALE) + offs = (1 << priv->ale); + else + return; + + if (chip->options & NAND_BUSWIDTH_16) + offs <<= 1; + + writeb(cmd, chip->IO_ADDR_W + offs); +} + +static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + void __iomem *io_base = chip->IO_ADDR_R; + uint64_t *buf64; + int i = 0; + + while (len && (unsigned long)buf & 7) { + *buf++ = readb(io_base); + len--; + } + buf64 = (uint64_t *)buf; + while (i < len/8) { + /* + * Since GCC has no proper constraint (PR 43518) + * force x variable to r2/r3 registers as ldrd instruction + * requires first register to be even. + */ + register uint64_t x asm ("r2"); + + asm volatile ("ldrd\t%0, [%1]" : "=&r" (x) : "r" (io_base)); + buf64[i++] = x; + } + i *= 8; + while (i < len) + buf[i++] = readb(io_base); +} + +static int orion_nand_probe(struct device_d *dev) +{ + struct device_node *dev_node = dev->device_node; + struct orion_nand *priv; + struct mtd_info *mtd; + struct nand_chip *chip; + struct clk *clk; + void __iomem *io_base; + int width, ret; + u32 val = 0; + + priv = xzalloc(sizeof(struct orion_nand)); + mtd = &priv->mtd; + chip = &priv->chip; + + io_base = dev_request_mem_region(dev, 0); + if (!io_base) + return -EBUSY; + + if (!of_property_read_u32(dev_node, "cle", &val)) + priv->cle = (u8)val; + else + priv->cle = 0; + + if (!of_property_read_u32(dev_node, "ale", &val)) + priv->ale = (u8)val; + else + priv->ale = 1; + + if (!of_property_read_u32(dev_node, "bank-width", &val)) + width = (u8)val * 8; + else + width = 8; + + if (!of_property_read_u32(dev_node, "chip-delay", &val)) + chip->chip_delay = (u8)val; + + mtd->parent = dev; + mtd->priv = chip; + chip->priv = priv; + chip->IO_ADDR_R = chip->IO_ADDR_W = io_base; + chip->cmd_ctrl = orion_nand_cmd_ctrl; + chip->read_buf = orion_nand_read_buf; + chip->ecc.mode = NAND_ECC_SOFT; + + WARN(width > 16, "%d bit bus width out of range", width); + if (width == 16) + chip->options |= NAND_BUSWIDTH_16; + + /* Not all platforms can gate the clock, so this is optional */ + clk = clk_get(dev, 0); + if (!IS_ERR(clk)) + clk_enable(clk); + + if (nand_scan(mtd, 1)) { + ret = -ENXIO; + goto no_dev; + } + + add_mtd_nand_device(mtd, "orion_nand"); + return 0; +no_dev: + if (!IS_ERR(clk)) + clk_disable(clk); +no_res: + free(priv); + return ret; +} + +static __maybe_unused struct of_device_id orion_nand_compatible[] = { + { .compatible = "marvell,orion-nand", }, + {}, +}; + +static struct driver_d orion_nand_driver = { + .name = "orion_nand", + .probe = orion_nand_probe, + .of_compatible = DRV_OF_COMPAT(orion_nand_compatible), +}; +device_platform_driver(orion_nand_driver); diff --git a/images/Makefile.mvebu b/images/Makefile.mvebu index 009807d..5e90855 100644 --- a/images/Makefile.mvebu +++ b/images/Makefile.mvebu @@ -72,6 +72,17 @@ image-$(CONFIG_MACH_GLOBALSCALE_GURUPLUG) += barebox-globalscale-guruplug-uart.img image-$(CONFIG_MACH_GLOBALSCALE_GURUPLUG) += barebox-globalscale-guruplug-2nd.img +PLATHOME_OPENBLOCKS_A6_KWBOPTS = ${KWBOPTS} -i $(board)/plathome-openblocks-a6/kwbimage.cfg +OPTS_start_plathome_openblocks_a6.pblx.kwbimg = $(PLATHOME_OPENBLOCKS_A6_KWBOPTS) +OPTS_start_plathome_openblocks_a6.pblx.kwbuartimg = -m uart $(PLATHOME_OPENBLOCKS_A6_KWBOPTS) +FILE_barebox-plathome-openblocks-a6.img = start_plathome_openblocks_a6.pblx.kwbimg +FILE_barebox-plathome-openblocks-a6-uart.img = start_plathome_openblocks_a6.pblx.kwbuartimg +FILE_barebox-plathome-openblocks-a6-2nd.img = start_plathome_openblocks_a6.pblx +pblx-$(CONFIG_MACH_PLATHOME_OPENBLOCKS_A6) += start_plathome_openblocks_a6 +image-$(CONFIG_MACH_PLATHOME_OPENBLOCKS_A6) += barebox-plathome-openblocks-a6.img +image-$(CONFIG_MACH_PLATHOME_OPENBLOCKS_A6) += barebox-plathome-openblocks-a6-uart.img +image-$(CONFIG_MACH_PLATHOME_OPENBLOCKS_A6) += barebox-plathome-openblocks-a6-2nd.img + USI_TOPKICK_KWBOPTS = ${KWBOPTS} -i $(board)/usi-topkick/kwbimage.cfg OPTS_start_usi_topkick.pblx.kwbimg = $(USI_TOPKICK_KWBOPTS) OPTS_start_usi_topkick.pblx.kwbuartimg = -m uart $(USI_TOPKICK_KWBOPTS)